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. 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> 24u) & 0xFFu) diff --git a/src/lmic/lmic_as923.c b/src/lmic/lmic_as923.c index ddff00b2..f46f50b0 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; } @@ -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; } @@ -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 24fdf106..e12ad8aa 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; } @@ -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 = AU921_UPLINK_DWELL_TIME_osticks; + } + if (dwellDelay > globalDutyDelay) { + globalDutyDelay = dwellDelay; + } + if (globalDutyDelay != 0) { + LMIC.globalDutyAvail = txbeg + globalDutyDelay; } } 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; 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; diff --git a/src/lmic/lorabase_as923.h b/src/lmic/lorabase_as923.h index 9cba8c45..d65bb75d 100644 --- a/src/lmic/lorabase_as923.h +++ b/src/lmic/lorabase_as923.h @@ -93,4 +93,13 @@ 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, + // initial value of DownlinkDwellTime before TxParamSetupReq received. + AS923_INITIAL_TxParam_DownlinkDwellTime = 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) };