From b7d443394377523bf8210be0cb146af79ed75ea6 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 10 Sep 2019 18:44:42 -0400 Subject: [PATCH 01/10] Fix #447: Default AS/AU UplinkDwellTime must be 1 --- src/lmic/lmic_as923.c | 2 +- src/lmic/lmic_au921.c | 2 +- src/lmic/lorabase_as923.h | 7 +++++++ src/lmic/lorabase_au921.h | 5 +++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lmic/lmic_as923.c b/src/lmic/lmic_as923.c index ddff00b2..419aec76 100644 --- a/src/lmic/lmic_as923.c +++ b/src/lmic/lmic_as923.c @@ -77,7 +77,7 @@ static CONST_TABLE(u1_t, maxFrameLens_dwell1)[] = { static uint8_t LMICas923_getUplinkDwellBit(uint8_t mcmd_txparam) { if (mcmd_txparam == 0xFF) - return 0; + return AS923_INITIAL_TxParam_UplinkDwellTime; return (mcmd_txparam & MCMD_TxParam_TxDWELL_MASK) != 0; } diff --git a/src/lmic/lmic_au921.c b/src/lmic/lmic_au921.c index 24fdf106..0bb387bf 100644 --- a/src/lmic/lmic_au921.c +++ b/src/lmic/lmic_au921.c @@ -67,7 +67,7 @@ static bit_t LMICau921_getUplinkDwellBit() { // if uninitialized, return default. if (LMIC.txParam == 0xFF) { - return 0; + return AU921_INITIAL_TxParam_UplinkDwellTime; } return (LMIC.txParam & MCMD_TxParam_TxDWELL_MASK) != 0; } diff --git a/src/lmic/lorabase_as923.h b/src/lmic/lorabase_as923.h index 9cba8c45..74909650 100644 --- a/src/lmic/lorabase_as923.h +++ b/src/lmic/lorabase_as923.h @@ -93,4 +93,11 @@ enum { AS923_V102_TX_CAP = 100 }; // v1.0.2 allows 100% # define AS923_TX_CAP AS923_V102_TX_CAP #endif +// TxParam defaults +enum { + // initial value of UplinkDwellTime before TxParamSetupReq received. + AS923_INITIAL_TxParam_UplinkDwellTime = 1, + AS923_UPLINK_DWELL_TIME_osticks = sec2osticks(20), +}; + #endif /* _lorabase_as923_h_ */ diff --git a/src/lmic/lorabase_au921.h b/src/lmic/lorabase_au921.h index d4c33b9f..7d8a1984 100644 --- a/src/lmic/lorabase_au921.h +++ b/src/lmic/lorabase_au921.h @@ -76,6 +76,11 @@ enum { enum { AU921_TX_EIRP_MAX_DBM = 30 // 30 dBm }; +enum { + // initial value of UplinkDwellTime before TxParamSetupReq received. + AU921_INITIAL_TxParam_UplinkDwellTime = 1, + AU921_UPLINK_DWELL_TIME_osticks = sec2osticks(20), +}; enum { DR_PAGE_AU921 = 0x10 * (LMIC_REGION_au921 - 1) }; From 3209e3337805f9c473de5456593aaadf57383929 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 10 Sep 2019 18:47:23 -0400 Subject: [PATCH 02/10] Fix #448: AS923, AU915 enforce dwell time based on TxParam --- src/lmic/lmic_as923.c | 17 +++++++++++++++-- src/lmic/lmic_au921.c | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/lmic/lmic_as923.c b/src/lmic/lmic_as923.c index 419aec76..d66c10a7 100644 --- a/src/lmic/lmic_as923.c +++ b/src/lmic/lmic_as923.c @@ -370,6 +370,9 @@ LMICas923_initJoinLoop(void) { void LMICas923_updateTx(ostime_t txbeg) { u4_t freq = LMIC.channelFreq[LMIC.txChnl]; + u4_t dwellDelay; + u4_t globalDutyDelay; + // Update global/band specific duty cycle stats ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); // Update channel/global duty cycle stats @@ -377,8 +380,18 @@ LMICas923_updateTx(ostime_t txbeg) { LMIC.freq = freq & ~(u4_t)3; LMIC.txpow = LMICas923_getMaxEIRP(LMIC.txParam); band->avail = txbeg + airtime * band->txcap; - if (LMIC.globalDutyRate != 0) - LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate); + dwellDelay = globalDutyDelay = 0; + if (LMIC.globalDutyRate != 0) { + globalDutyDelay = (airtime << LMIC.globalDutyRate); + } + if (LMICas923_getUplinkDwellBit(LMIC.txParam)) { + dwellDelay = AS923_UPLINK_DWELL_TIME_osticks; + } + if (dwellDelay > globalDutyDelay) { + globalDutyDelay = dwellDelay; + } + if (globalDutyDelay != 0) + LMIC.globalDutyAvail = txbeg + globalDutyDelay; } diff --git a/src/lmic/lmic_au921.c b/src/lmic/lmic_au921.c index 0bb387bf..399d50fc 100644 --- a/src/lmic/lmic_au921.c +++ b/src/lmic/lmic_au921.c @@ -239,10 +239,23 @@ void LMICau921_updateTx(ostime_t txbeg) { LMIC.freq = AU921_500kHz_UPFBASE + (chnl - 64)*AU921_500kHz_UPFSTEP; } - // Update global duty cycle stats + // Update global duty cycle stat and deal with dwell time. + u4_t dwellDelay; + u4_t globalDutyDelay; + dwellDelay = globalDutyDelay = 0; + if (LMIC.globalDutyRate != 0) { ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); - LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate); + globalDutyDelay = txbeg + (airtime << LMIC.globalDutyRate); + } + if (LMICau921_getUplinkDwellBit(LMIC.txParam)) { + dwellDelay = AS923_UPLINK_DWELL_TIME_osticks; + } + if (dwellDelay > globalDutyDelay) { + globalDutyDelay = dwellDelay; + } + if (globalDutyDelay != 0) { + LMIC.globalDutyAvail = txbeg + globalDutyDelay; } } From ccfcc758657ece8940ea92717dad304658e29fa3 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 10 Sep 2019 18:50:02 -0400 Subject: [PATCH 03/10] Version is v3.0.99.4 --- src/lmic/lmic.h | 2 +- src/lmic/lmic_as923.c | 2 +- src/lmic/lorabase_as923.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lmic/lmic.h b/src/lmic/lmic.h index caa7b379..c9f31ba5 100644 --- a/src/lmic/lmic.h +++ b/src/lmic/lmic.h @@ -105,7 +105,7 @@ extern "C"{ #define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \ (((major) << 24ul) | ((minor) << 16ul) | ((patch) << 8ul) | ((local) << 0ul)) -#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 3) /* v3.0.99.3 */ +#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 4) /* v3.0.99.4 */ #define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \ (((v) >> 24u) & 0xFFu) diff --git a/src/lmic/lmic_as923.c b/src/lmic/lmic_as923.c index d66c10a7..f46f50b0 100644 --- a/src/lmic/lmic_as923.c +++ b/src/lmic/lmic_as923.c @@ -85,7 +85,7 @@ LMICas923_getUplinkDwellBit(uint8_t mcmd_txparam) { static uint8_t LMICas923_getDownlinkDwellBit(uint8_t mcmd_txparam) { if (mcmd_txparam == 0xFF) - return 0; + return AS923_INITIAL_TxParam_DownlinkDwellTime; return (mcmd_txparam & MCMD_TxParam_RxDWELL_MASK) != 0; } diff --git a/src/lmic/lorabase_as923.h b/src/lmic/lorabase_as923.h index 74909650..d65bb75d 100644 --- a/src/lmic/lorabase_as923.h +++ b/src/lmic/lorabase_as923.h @@ -97,6 +97,8 @@ enum { AS923_V102_TX_CAP = 100 }; // v1.0.2 allows 100% enum { // initial value of UplinkDwellTime before TxParamSetupReq received. AS923_INITIAL_TxParam_UplinkDwellTime = 1, + // initial value of DownlinkDwellTime before TxParamSetupReq received. + AS923_INITIAL_TxParam_DownlinkDwellTime = 1, AS923_UPLINK_DWELL_TIME_osticks = sec2osticks(20), }; From b1d79b5883e606dfaaaa99a1f007d8dfa67f7e42 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 10 Sep 2019 19:16:53 -0400 Subject: [PATCH 04/10] Fix #446: AS923 don't report join failure till all ch scanned --- src/lmic/lmic.c | 10 +--------- src/lmic/lmic_eu_like.c | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/src/lmic/lmic.c b/src/lmic/lmic.c index e181c4e2..ec94ae04 100644 --- a/src/lmic/lmic.c +++ b/src/lmic/lmic.c @@ -1597,7 +1597,7 @@ static bit_t processJoinAccept (void) { ASSERT((LMIC.opmode & (OP_JOINING|OP_REJOIN))!=0); // // XXX(tmm@mcci.com) OP_REJOIN confuses me, and I'm not sure why we're - // adjusting DRs here. We've just recevied a join accept, and the + // adjusting DRs here. We've just received a join accept, and the // datarate therefore shouldn't be in play. In effect, we set the // initial data rate based on the number of times we tried to rejoin. // @@ -1672,18 +1672,10 @@ static bit_t processJoinAccept_nojoinframe(void) { // claimed to return a delay but really returns 0 or 1. // Once we update as923 to return failed after dr2, we // can take out this #if. -#if CFG_region != LMIC_REGION_as923 os_setTimedCallback(&LMIC.osjob, os_getTime()+failed, failed ? FUNC_ADDR(onJoinFailed) // one JOIN iteration done and failed : FUNC_ADDR(runEngineUpdate)); // next step to be delayed -#else - // in the join of AS923 v1.1 older, only DR2 is used. Therefore, - // not much improvement when it handles two different behavior; - // onJoinFailed or runEngineUpdate. - os_setTimedCallback(&LMIC.osjob, os_getTime()+failed, - FUNC_ADDR(onJoinFailed)); -#endif // stop this join process. return 1; } diff --git a/src/lmic/lmic_eu_like.c b/src/lmic/lmic_eu_like.c index fbaae360..982ae496 100644 --- a/src/lmic/lmic_eu_like.c +++ b/src/lmic/lmic_eu_like.c @@ -174,24 +174,25 @@ ostime_t LMICeulike_nextJoinState(uint8_t nDefaultChannels) { if ((++LMIC.txCnt % nDefaultChannels) == 0) { // Lower DR every nth try (having all default channels with same DR) // - // TODO(tmm@mcci.com) add new DR_REGIN_JOIN_MIN instead of LORAWAN_DR0; + // TODO(tmm@mcci.com) add new DR_REGION_JOIN_MIN instead of LORAWAN_DR0; // then we can eliminate the LMIC_REGION_as923 below because we'll set // the failed flag here. This will cause the outer caller to take the // appropriate join path. Or add new LMICeulike_GetLowestJoinDR() // + +// TODO(tmm@mcci.com) - see above; please remove regional dependency from this file. +#if CFG_region == LMIC_REGION_as923 + // in the join of AS923 v1.1 or older, only DR2 is used. + // no need to change the DR. + LMIC.datarate = AS923_DR_SF10; + failed = 1; +#else if (LMIC.datarate == LORAWAN_DR0) failed = 1; // we have tried all DR - signal EV_JOIN_FAILED - else - { -// TODO(tmm@mcci.com) - see above; please remove regional dependency from this file. -#if CFG_region != LMIC_REGION_as923 + else { LMICcore_setDrJoin(DRCHG_NOJACC, decDR((dr_t)LMIC.datarate)); -#else - // in the join of AS923 v1.1 or older, only DR2 is used. - // no need to change the DR. - LMIC.datarate = AS923_DR_SF10; -#endif } +#endif } // Clear NEXTCHNL because join state engine controls channel hopping LMIC.opmode &= ~OP_NEXTCHNL; From 0c0614495ff690202284c459679003dc30342add Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 10 Sep 2019 20:14:52 -0400 Subject: [PATCH 05/10] Fix #448: typo in AU915 code --- src/lmic/lmic_au921.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lmic/lmic_au921.c b/src/lmic/lmic_au921.c index 399d50fc..e12ad8aa 100644 --- a/src/lmic/lmic_au921.c +++ b/src/lmic/lmic_au921.c @@ -249,7 +249,7 @@ void LMICau921_updateTx(ostime_t txbeg) { globalDutyDelay = txbeg + (airtime << LMIC.globalDutyRate); } if (LMICau921_getUplinkDwellBit(LMIC.txParam)) { - dwellDelay = AS923_UPLINK_DWELL_TIME_osticks; + dwellDelay = AU921_UPLINK_DWELL_TIME_osticks; } if (dwellDelay > globalDutyDelay) { globalDutyDelay = dwellDelay; From f8f9bbc17059373658746e70d8662ffa6d6b453a Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 10 Sep 2019 20:18:25 -0400 Subject: [PATCH 06/10] Fix #450 Fix #445: LMIC_clrTxData more carefully --- src/lmic/lmic.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/lmic/lmic.c b/src/lmic/lmic.c index ec94ae04..e431e8c9 100644 --- a/src/lmic/lmic.c +++ b/src/lmic/lmic.c @@ -2744,9 +2744,20 @@ void LMIC_init (void) { void LMIC_clrTxData (void) { - bit_t const txActive = LMIC.opmode & OP_TXDATA; - LMIC.opmode &= ~(OP_TXDATA|OP_TXRXPEND|OP_POLL); + u2_t opmode = LMIC.opmode; + bit_t const txActive = opmode & OP_TXDATA; + if (! txActive) { + return; + } LMIC.pendTxLen = 0; + opmode &= ~(OP_TXDATA | OP_POLL); + if (! (opmode & OP_JOINING)) { + // in this case, we are joining, and the TX data + // is just pending. + opmode &= ~(OP_TXRXPEND); + } + + LMIC.opmode = opmode; if (txActive) reportEventNoUpdate(EV_TXCANCELED); @@ -2787,15 +2798,23 @@ dr_t LMIC_feasibleDataRateForFrame(dr_t dr, u1_t payloadSize) { return dr; } -static void adjustDrForFrame(u1_t len) { +static bit_t isTxPathBusy(void) { + return (LMIC.opmode & (OP_TXDATA|OP_JOINING)) != 0; +} + +static bit_t adjustDrForFrameIfNotBusy(u1_t len) { + if (isTxPathBusy()) { + return 0; + } dr_t newDr = LMIC_feasibleDataRateForFrame(LMIC.datarate, len); if (newDr != LMIC.datarate) { setDrTxpow(DRCHG_FRAMESIZE, newDr, KEEP_TXPOW); } + return 1; } void LMIC_setTxData (void) { - adjustDrForFrame(LMIC.pendTxLen); + adjustDrForFrameIfNotBusy(LMIC.pendTxLen); LMIC_setTxData_strict(); } @@ -2812,7 +2831,7 @@ void LMIC_setTxData_strict (void) { // send a message, attempting to adjust TX data rate lmic_tx_error_t LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed) { - adjustDrForFrame(dlen); + adjustDrForFrameIfNotBusy(dlen); return LMIC_setTxData2_strict(port, data, dlen, confirmed); } @@ -2846,7 +2865,7 @@ lmic_tx_error_t LMIC_sendWithCallback ( u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed, lmic_txmessage_cb_t *pCb, void *pUserData ) { - adjustDrForFrame(dlen); + adjustDrForFrameIfNotBusy(dlen); return LMIC_sendWithCallback_strict(port, data, dlen, confirmed, pCb, pUserData); } From ea09b2de2dc29c1195d287931f44b7b6d7eb8e6e Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Tue, 10 Sep 2019 20:19:28 -0400 Subject: [PATCH 07/10] Version is v3.0.99.5 --- src/lmic/lmic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lmic/lmic.h b/src/lmic/lmic.h index c9f31ba5..d05d2c04 100644 --- a/src/lmic/lmic.h +++ b/src/lmic/lmic.h @@ -105,7 +105,7 @@ extern "C"{ #define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \ (((major) << 24ul) | ((minor) << 16ul) | ((patch) << 8ul) | ((local) << 0ul)) -#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 4) /* v3.0.99.4 */ +#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 5) /* v3.0.99.5 */ #define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \ (((v) >> 24u) & 0xFFu) From 467d137a2073c93aa6deaaaf961a6a7c6cb1f074 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Wed, 11 Sep 2019 05:27:50 -0400 Subject: [PATCH 08/10] Clean up warnings in compliance sketch, more AVR-isms --- .../compliance-otaa-halconfig.ino | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/compliance-otaa-halconfig/compliance-otaa-halconfig.ino b/examples/compliance-otaa-halconfig/compliance-otaa-halconfig.ino index 530f49ae..beae4cbd 100644 --- a/examples/compliance-otaa-halconfig/compliance-otaa-halconfig.ino +++ b/examples/compliance-otaa-halconfig/compliance-otaa-halconfig.ino @@ -314,7 +314,7 @@ void printFcnts(cEventQueue::eventnode_t &e) { } #if LMIC_ENABLE_event_logging -// dump all the registers. Must have printf setup. +// dump all the registers. void printAllRegisters(void) { uint8_t regbuf[0x80]; regbuf[0] = 0; @@ -400,21 +400,21 @@ void eventPrint(cEventQueue::eventnode_t &e) { u1_t nwkKey[16]; u1_t artKey[16]; LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey); - Serial.print("netid: "); + Serial.print(F("netid: ")); Serial.println(netid, DEC); - Serial.print("devaddr: "); + Serial.print(F("devaddr: ")); Serial.println(devaddr, HEX); - Serial.print("artKey: "); - for (int i=0; i Date: Wed, 11 Sep 2019 07:18:20 -0400 Subject: [PATCH 09/10] Clean up warnings in compliance sketch, more AVR-isms --- src/lmic/lmic_compliance.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lmic/lmic_compliance.c b/src/lmic/lmic_compliance.c index 072e7aef..cf80618e 100644 --- a/src/lmic/lmic_compliance.c +++ b/src/lmic/lmic_compliance.c @@ -54,8 +54,9 @@ static lmic_event_cb_t lmicEventCb; static lmic_txmessage_cb_t sendUplinkCompleteCb; static osjobcbfn_t timerExpiredCb; -/* this is declared global so the optimizer can chuck it without warnings */ +/* these are declared global so the optimizer can chuck them without warnings */ const char *LMICcompliance_txSuccessToString(int fSuccess); +const char * LMICcompliance_fsmstate_getName(lmic_compliance_fsmstate_t state); /****************************************************************************\ | @@ -386,8 +387,6 @@ Name: evEchoCommand() */ -static lmic_txmessage_cb_t evEchoCommandCb; - static void evEchoCommand( const uint8_t *pMessage, size_t nMessage @@ -439,7 +438,7 @@ Name: fsmEval() */ -static const char * lmic_compliance_fsmstate_Getname(lmic_compliance_fsmstate_t state) { +const char * LMICcompliance_fsmstate_getName(lmic_compliance_fsmstate_t state) { const char * const names[] = { LMIC_COMPLIANCE_FSMSTATE__NAMES }; if ((unsigned) state >= sizeof(names)/sizeof(names[0])) @@ -497,8 +496,8 @@ static void fsmEval(void) { // state change! LMIC_COMPLIANCE_PRINTF("%s: change state %s(%u) => %s(%u)\n", __func__, - lmic_compliance_fsmstate_Getname(oldState), (unsigned) oldState, - lmic_compliance_fsmstate_Getname(newState), (unsigned) newState + LMICcompliance_fsmstate_getName(oldState), (unsigned) oldState, + LMICcompliance_fsmstate_getName(newState), (unsigned) newState ); fNewState = true; LMIC_Compliance.fsmState = newState; From 881022825ceca2503cbafc10bcaa8c5e84b03cb3 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Wed, 11 Sep 2019 07:45:16 -0400 Subject: [PATCH 10/10] Fix #451: improve documentation on region selection --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 56275380..b79ed62f 100644 --- a/README.md +++ b/README.md @@ -120,13 +120,12 @@ The LMIC library provides a fairly complete LoRaWAN Class A and Class B implementation, supporting the EU-868, US-915, AU-921, AS-923, and IN-866 bands. Only a limited number of features was tested using this port on Arduino hardware, so be careful when using any of the untested features. -The library has only been tested with LoRaWAN 1.0.2 networks and does not have the separated key structure defined by LoRaWAN 1.1. +The library has only been tested with LoRaWAN 1.0.2/1.03 networks and does not have the separated key structure defined by LoRaWAN 1.1. What certainly works: - Sending packets uplink, taking into account duty cycling. - Encryption and message integrity checking. -- Receiving downlink packets in the RX2 window. - Custom frequencies and data rate settings. - Over-the-air activation (OTAA / joining). - Receiving downlink packets in the RX1 and RX2 windows. @@ -207,9 +206,11 @@ The library supports the following regions: `-D CFG_kr920` | `LMIC_REGION_kr920` | 8 | 2.9 | Korea 920-923 MHz ISM `-D CFG_in866` | `LMIC_REGION_in866` | 9 | 2.10 | India 865-867 MHz ISM -You should define exactly one of `CFG_...` variables. If you don't, -the library assumes `CFG_eu868`. The library changes configuration pretty substantially -according to the region. Some of the differences are listed below. +The library requires that the compile environment or the project config file define exactly one of `CFG_...` variables. As released, `project_config/lmic_project_config.h` defines `CFG_us915`. If you build with PlatformIO or other environments, and you do not provide a pointer to the platform config file, `src/lmic/config.h` will define `CFG_eu868`. + +MCCI BSPs add menu entries to the Arduino IDE so you can select the target region interactively. + +The library changes configuration pretty substantially according to the region selected, and this affects the symbols in-scope in your sketches and cpp files. Some of the differences are listed below. This list is not comprehensive, and is subject to change in future major releases. #### eu868, as923, in866, kr920 @@ -1126,6 +1127,7 @@ function uflt12f(rawUflt12) - v3.0.99 (still in pre-release) adds the following changes. (This is not an exhaustive list.) Note that the behavior of the LMIC changes in important ways, as it now enforces the LoRaWAN mandated maximum frame size for a given data rate. For Class A devices, this may cause your device to go silent after join, if you're not able to handle the frame size dictated by the parameters downloaded to the device by the network during join. The library will attempt to find a data rate that will work, but there is no guarantee that the network has provided such a data rate. + - [#452](https://github.com/mcci-catena/arduino-lmic/pull/452) fixes a bug [#450](https://github.com/mcci-catena/arduino-lmic/issues/450) in `LMIC_clrTxData()` that would cause join hiccups if called while (1) a join was in progress and (2) a regular data packet was waiting to be uplinked after the join completes. Also fixes AS923- and AU915-specific bugs [#446](https://github.com/mcci-catena/arduino-lmic/issues/446), [#447](https://github.com/mcci-catena/arduino-lmic/issues/447), [#448](https://github.com/mcci-catena/arduino-lmic/issues/448). Version is `v3.0.99.5`. - [#443](https://github.com/mcci-catena/arduino-lmic/pull/443) addresses a number of problems found in cooperation with [RedwoodComm](https://redwoodcomm.com). They suggested a timing improvement to speed testing; this lead to the discovery of a number of problems. Some were in the compliance framework, but one corrects timing for very high spreading factors, several ([#442](https://github.com/mcci-catena/arduino-lmic/issues/442), [#436](https://github.com/mcci-catena/arduino-lmic/issues/438), [#435](https://github.com/mcci-catena/arduino-lmic/issues/435), [#434](https://github.com/mcci-catena/arduino-lmic/issues/434) fix glaring problems in FSK support; [#249](https://github.com/mcci-catena/arduino-lmic/issues/249) greatly enhances stability by making API calls much less likely to crash the LMIC if it's active. Version is v3.0.99.3. - [#388](https://github.com/mcci-catena/arduino-lmic/issues/388), [#389](https://github.com/mcci-catena/arduino-lmic/issues/390), [#390](https://github.com/mcci-catena/arduino-lmic/issues/390) change the LMIC to honor the maximum frame size for a given DR in the current region. This proves to be a breaking change for many applications, especially in the US, because DR0 in the US supports only an 11-byte payload, and many apps were ignoring this. Additional error codes were defined so that apps can detect and recover from this situation, but they must detect; otherwise they run the risk of being blocked from the network by the LMIC. Because of this change, the next version of the LMIC will be V3.1 or higher, and the LMIC version for development is bumped to 3.0.99.0. - [#401](https://github.com/mcci-catena/arduino-lmic/issues/401) adds 865 MHz through 868 MHz to the "1%" band for EU.