Skip to content

Commit 852f348

Browse files
authored
Merge pull request #452 from mcci-catena/issue447
Fix errors in US and AS923 tests (and AU915 implementation)
2 parents 3364725 + 8810228 commit 852f348

File tree

10 files changed

+107
-55
lines changed

10 files changed

+107
-55
lines changed

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,12 @@ The LMIC library provides a fairly complete LoRaWAN Class A and Class B
120120
implementation, supporting the EU-868, US-915, AU-921, AS-923, and IN-866 bands. Only a limited
121121
number of features was tested using this port on Arduino hardware, so be careful when using any of the untested features.
122122

123-
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.
123+
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.
124124

125125
What certainly works:
126126

127127
- Sending packets uplink, taking into account duty cycling.
128128
- Encryption and message integrity checking.
129-
- Receiving downlink packets in the RX2 window.
130129
- Custom frequencies and data rate settings.
131130
- Over-the-air activation (OTAA / joining).
132131
- Receiving downlink packets in the RX1 and RX2 windows.
@@ -207,9 +206,11 @@ The library supports the following regions:
207206
`-D CFG_kr920` | `LMIC_REGION_kr920` | 8 | 2.9 | Korea 920-923 MHz ISM
208207
`-D CFG_in866` | `LMIC_REGION_in866` | 9 | 2.10 | India 865-867 MHz ISM
209208

210-
You should define exactly one of `CFG_...` variables. If you don't,
211-
the library assumes `CFG_eu868`. The library changes configuration pretty substantially
212-
according to the region. Some of the differences are listed below.
209+
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`.
210+
211+
MCCI BSPs add menu entries to the Arduino IDE so you can select the target region interactively.
212+
213+
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.
213214

214215
#### eu868, as923, in866, kr920
215216

@@ -1126,6 +1127,7 @@ function uflt12f(rawUflt12)
11261127

11271128
- 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.
11281129

1130+
- [#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`.
11291131
- [#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.
11301132
- [#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.
11311133
- [#401](https://github.com/mcci-catena/arduino-lmic/issues/401) adds 865 MHz through 868 MHz to the "1%" band for EU.

examples/compliance-otaa-halconfig/compliance-otaa-halconfig.ino

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ void printFcnts(cEventQueue::eventnode_t &e) {
314314
}
315315

316316
#if LMIC_ENABLE_event_logging
317-
// dump all the registers. Must have printf setup.
317+
// dump all the registers.
318318
void printAllRegisters(void) {
319319
uint8_t regbuf[0x80];
320320
regbuf[0] = 0;
@@ -400,21 +400,21 @@ void eventPrint(cEventQueue::eventnode_t &e) {
400400
u1_t nwkKey[16];
401401
u1_t artKey[16];
402402
LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey);
403-
Serial.print("netid: ");
403+
Serial.print(F("netid: "));
404404
Serial.println(netid, DEC);
405-
Serial.print("devaddr: ");
405+
Serial.print(F("devaddr: "));
406406
Serial.println(devaddr, HEX);
407-
Serial.print("artKey: ");
408-
for (int i=0; i<sizeof(artKey); ++i) {
407+
Serial.print(F("artKey: "));
408+
for (size_t i=0; i<sizeof(artKey); ++i) {
409409
if (i != 0)
410-
Serial.print("-");
410+
Serial.print('-');
411411
printHex2(artKey[i]);
412412
}
413-
Serial.println("");
414-
Serial.print("nwkKey: ");
415-
for (int i=0; i<sizeof(nwkKey); ++i) {
413+
printNl();
414+
Serial.print(F("nwkKey: "));
415+
for (size_t i=0; i<sizeof(nwkKey); ++i) {
416416
if (i != 0)
417-
Serial.print("-");
417+
Serial.print('-');
418418
printHex2(nwkKey[i]);
419419
}
420420
} while (0);
@@ -432,7 +432,6 @@ void eventPrint(cEventQueue::eventnode_t &e) {
432432
printFreq(e.freq);
433433
printRps(e.rps);
434434
printOpmode(e.opmode);
435-
printf(" irqLevel %u", hal_getIrqLevel());
436435
#if LMIC_ENABLE_event_logging
437436
printAllRegisters();
438437
#endif

src/lmic/lmic.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,7 +1597,7 @@ static bit_t processJoinAccept (void) {
15971597
ASSERT((LMIC.opmode & (OP_JOINING|OP_REJOIN))!=0);
15981598
//
15991599
// XXX(tmm@mcci.com) OP_REJOIN confuses me, and I'm not sure why we're
1600-
// adjusting DRs here. We've just recevied a join accept, and the
1600+
// adjusting DRs here. We've just received a join accept, and the
16011601
// datarate therefore shouldn't be in play. In effect, we set the
16021602
// initial data rate based on the number of times we tried to rejoin.
16031603
//
@@ -1672,18 +1672,10 @@ static bit_t processJoinAccept_nojoinframe(void) {
16721672
// claimed to return a delay but really returns 0 or 1.
16731673
// Once we update as923 to return failed after dr2, we
16741674
// can take out this #if.
1675-
#if CFG_region != LMIC_REGION_as923
16761675
os_setTimedCallback(&LMIC.osjob, os_getTime()+failed,
16771676
failed
16781677
? FUNC_ADDR(onJoinFailed) // one JOIN iteration done and failed
16791678
: FUNC_ADDR(runEngineUpdate)); // next step to be delayed
1680-
#else
1681-
// in the join of AS923 v1.1 older, only DR2 is used. Therefore,
1682-
// not much improvement when it handles two different behavior;
1683-
// onJoinFailed or runEngineUpdate.
1684-
os_setTimedCallback(&LMIC.osjob, os_getTime()+failed,
1685-
FUNC_ADDR(onJoinFailed));
1686-
#endif
16871679
// stop this join process.
16881680
return 1;
16891681
}
@@ -2752,9 +2744,20 @@ void LMIC_init (void) {
27522744

27532745

27542746
void LMIC_clrTxData (void) {
2755-
bit_t const txActive = LMIC.opmode & OP_TXDATA;
2756-
LMIC.opmode &= ~(OP_TXDATA|OP_TXRXPEND|OP_POLL);
2747+
u2_t opmode = LMIC.opmode;
2748+
bit_t const txActive = opmode & OP_TXDATA;
2749+
if (! txActive) {
2750+
return;
2751+
}
27572752
LMIC.pendTxLen = 0;
2753+
opmode &= ~(OP_TXDATA | OP_POLL);
2754+
if (! (opmode & OP_JOINING)) {
2755+
// in this case, we are joining, and the TX data
2756+
// is just pending.
2757+
opmode &= ~(OP_TXRXPEND);
2758+
}
2759+
2760+
LMIC.opmode = opmode;
27582761

27592762
if (txActive)
27602763
reportEventNoUpdate(EV_TXCANCELED);
@@ -2795,15 +2798,23 @@ dr_t LMIC_feasibleDataRateForFrame(dr_t dr, u1_t payloadSize) {
27952798
return dr;
27962799
}
27972800

2798-
static void adjustDrForFrame(u1_t len) {
2801+
static bit_t isTxPathBusy(void) {
2802+
return (LMIC.opmode & (OP_TXDATA|OP_JOINING)) != 0;
2803+
}
2804+
2805+
static bit_t adjustDrForFrameIfNotBusy(u1_t len) {
2806+
if (isTxPathBusy()) {
2807+
return 0;
2808+
}
27992809
dr_t newDr = LMIC_feasibleDataRateForFrame(LMIC.datarate, len);
28002810
if (newDr != LMIC.datarate) {
28012811
setDrTxpow(DRCHG_FRAMESIZE, newDr, KEEP_TXPOW);
28022812
}
2813+
return 1;
28032814
}
28042815

28052816
void LMIC_setTxData (void) {
2806-
adjustDrForFrame(LMIC.pendTxLen);
2817+
adjustDrForFrameIfNotBusy(LMIC.pendTxLen);
28072818
LMIC_setTxData_strict();
28082819
}
28092820

@@ -2820,7 +2831,7 @@ void LMIC_setTxData_strict (void) {
28202831

28212832
// send a message, attempting to adjust TX data rate
28222833
lmic_tx_error_t LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed) {
2823-
adjustDrForFrame(dlen);
2834+
adjustDrForFrameIfNotBusy(dlen);
28242835
return LMIC_setTxData2_strict(port, data, dlen, confirmed);
28252836
}
28262837

@@ -2854,7 +2865,7 @@ lmic_tx_error_t LMIC_sendWithCallback (
28542865
u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed,
28552866
lmic_txmessage_cb_t *pCb, void *pUserData
28562867
) {
2857-
adjustDrForFrame(dlen);
2868+
adjustDrForFrameIfNotBusy(dlen);
28582869
return LMIC_sendWithCallback_strict(port, data, dlen, confirmed, pCb, pUserData);
28592870
}
28602871

src/lmic/lmic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ extern "C"{
105105
#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \
106106
(((major) << 24ul) | ((minor) << 16ul) | ((patch) << 8ul) | ((local) << 0ul))
107107

108-
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 3) /* v3.0.99.3 */
108+
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 5) /* v3.0.99.5 */
109109

110110
#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \
111111
(((v) >> 24u) & 0xFFu)

src/lmic/lmic_as923.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,15 @@ static CONST_TABLE(u1_t, maxFrameLens_dwell1)[] = {
7777
static uint8_t
7878
LMICas923_getUplinkDwellBit(uint8_t mcmd_txparam) {
7979
if (mcmd_txparam == 0xFF)
80-
return 0;
80+
return AS923_INITIAL_TxParam_UplinkDwellTime;
8181

8282
return (mcmd_txparam & MCMD_TxParam_TxDWELL_MASK) != 0;
8383
}
8484

8585
static uint8_t
8686
LMICas923_getDownlinkDwellBit(uint8_t mcmd_txparam) {
8787
if (mcmd_txparam == 0xFF)
88-
return 0;
88+
return AS923_INITIAL_TxParam_DownlinkDwellTime;
8989

9090
return (mcmd_txparam & MCMD_TxParam_RxDWELL_MASK) != 0;
9191
}
@@ -370,15 +370,28 @@ LMICas923_initJoinLoop(void) {
370370
void
371371
LMICas923_updateTx(ostime_t txbeg) {
372372
u4_t freq = LMIC.channelFreq[LMIC.txChnl];
373+
u4_t dwellDelay;
374+
u4_t globalDutyDelay;
375+
373376
// Update global/band specific duty cycle stats
374377
ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
375378
// Update channel/global duty cycle stats
376379
xref2band_t band = &LMIC.bands[freq & 0x3];
377380
LMIC.freq = freq & ~(u4_t)3;
378381
LMIC.txpow = LMICas923_getMaxEIRP(LMIC.txParam);
379382
band->avail = txbeg + airtime * band->txcap;
380-
if (LMIC.globalDutyRate != 0)
381-
LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate);
383+
dwellDelay = globalDutyDelay = 0;
384+
if (LMIC.globalDutyRate != 0) {
385+
globalDutyDelay = (airtime << LMIC.globalDutyRate);
386+
}
387+
if (LMICas923_getUplinkDwellBit(LMIC.txParam)) {
388+
dwellDelay = AS923_UPLINK_DWELL_TIME_osticks;
389+
}
390+
if (dwellDelay > globalDutyDelay) {
391+
globalDutyDelay = dwellDelay;
392+
}
393+
if (globalDutyDelay != 0)
394+
LMIC.globalDutyAvail = txbeg + globalDutyDelay;
382395
}
383396

384397

src/lmic/lmic_au921.c

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ static bit_t
6767
LMICau921_getUplinkDwellBit() {
6868
// if uninitialized, return default.
6969
if (LMIC.txParam == 0xFF) {
70-
return 0;
70+
return AU921_INITIAL_TxParam_UplinkDwellTime;
7171
}
7272
return (LMIC.txParam & MCMD_TxParam_TxDWELL_MASK) != 0;
7373
}
@@ -239,10 +239,23 @@ void LMICau921_updateTx(ostime_t txbeg) {
239239
LMIC.freq = AU921_500kHz_UPFBASE + (chnl - 64)*AU921_500kHz_UPFSTEP;
240240
}
241241

242-
// Update global duty cycle stats
242+
// Update global duty cycle stat and deal with dwell time.
243+
u4_t dwellDelay;
244+
u4_t globalDutyDelay;
245+
dwellDelay = globalDutyDelay = 0;
246+
243247
if (LMIC.globalDutyRate != 0) {
244248
ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen);
245-
LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate);
249+
globalDutyDelay = txbeg + (airtime << LMIC.globalDutyRate);
250+
}
251+
if (LMICau921_getUplinkDwellBit(LMIC.txParam)) {
252+
dwellDelay = AU921_UPLINK_DWELL_TIME_osticks;
253+
}
254+
if (dwellDelay > globalDutyDelay) {
255+
globalDutyDelay = dwellDelay;
256+
}
257+
if (globalDutyDelay != 0) {
258+
LMIC.globalDutyAvail = txbeg + globalDutyDelay;
246259
}
247260
}
248261

src/lmic/lmic_compliance.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ static lmic_event_cb_t lmicEventCb;
5454
static lmic_txmessage_cb_t sendUplinkCompleteCb;
5555
static osjobcbfn_t timerExpiredCb;
5656

57-
/* this is declared global so the optimizer can chuck it without warnings */
57+
/* these are declared global so the optimizer can chuck them without warnings */
5858
const char *LMICcompliance_txSuccessToString(int fSuccess);
59+
const char * LMICcompliance_fsmstate_getName(lmic_compliance_fsmstate_t state);
5960

6061
/****************************************************************************\
6162
|
@@ -386,8 +387,6 @@ Name: evEchoCommand()
386387
387388
*/
388389

389-
static lmic_txmessage_cb_t evEchoCommandCb;
390-
391390
static void evEchoCommand(
392391
const uint8_t *pMessage,
393392
size_t nMessage
@@ -439,7 +438,7 @@ Name: fsmEval()
439438
440439
*/
441440

442-
static const char * lmic_compliance_fsmstate_Getname(lmic_compliance_fsmstate_t state) {
441+
const char * LMICcompliance_fsmstate_getName(lmic_compliance_fsmstate_t state) {
443442
const char * const names[] = { LMIC_COMPLIANCE_FSMSTATE__NAMES };
444443

445444
if ((unsigned) state >= sizeof(names)/sizeof(names[0]))
@@ -497,8 +496,8 @@ static void fsmEval(void) {
497496
// state change!
498497
LMIC_COMPLIANCE_PRINTF("%s: change state %s(%u) => %s(%u)\n",
499498
__func__,
500-
lmic_compliance_fsmstate_Getname(oldState), (unsigned) oldState,
501-
lmic_compliance_fsmstate_Getname(newState), (unsigned) newState
499+
LMICcompliance_fsmstate_getName(oldState), (unsigned) oldState,
500+
LMICcompliance_fsmstate_getName(newState), (unsigned) newState
502501
);
503502
fNewState = true;
504503
LMIC_Compliance.fsmState = newState;

src/lmic/lmic_eu_like.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,24 +174,25 @@ ostime_t LMICeulike_nextJoinState(uint8_t nDefaultChannels) {
174174
if ((++LMIC.txCnt % nDefaultChannels) == 0) {
175175
// Lower DR every nth try (having all default channels with same DR)
176176
//
177-
// TODO(tmm@mcci.com) add new DR_REGIN_JOIN_MIN instead of LORAWAN_DR0;
177+
// TODO(tmm@mcci.com) add new DR_REGION_JOIN_MIN instead of LORAWAN_DR0;
178178
// then we can eliminate the LMIC_REGION_as923 below because we'll set
179179
// the failed flag here. This will cause the outer caller to take the
180180
// appropriate join path. Or add new LMICeulike_GetLowestJoinDR()
181181
//
182+
183+
// TODO(tmm@mcci.com) - see above; please remove regional dependency from this file.
184+
#if CFG_region == LMIC_REGION_as923
185+
// in the join of AS923 v1.1 or older, only DR2 is used.
186+
// no need to change the DR.
187+
LMIC.datarate = AS923_DR_SF10;
188+
failed = 1;
189+
#else
182190
if (LMIC.datarate == LORAWAN_DR0)
183191
failed = 1; // we have tried all DR - signal EV_JOIN_FAILED
184-
else
185-
{
186-
// TODO(tmm@mcci.com) - see above; please remove regional dependency from this file.
187-
#if CFG_region != LMIC_REGION_as923
192+
else {
188193
LMICcore_setDrJoin(DRCHG_NOJACC, decDR((dr_t)LMIC.datarate));
189-
#else
190-
// in the join of AS923 v1.1 or older, only DR2 is used.
191-
// no need to change the DR.
192-
LMIC.datarate = AS923_DR_SF10;
193-
#endif
194194
}
195+
#endif
195196
}
196197
// Clear NEXTCHNL because join state engine controls channel hopping
197198
LMIC.opmode &= ~OP_NEXTCHNL;

src/lmic/lorabase_as923.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,13 @@ enum { AS923_V102_TX_CAP = 100 }; // v1.0.2 allows 100%
9393
# define AS923_TX_CAP AS923_V102_TX_CAP
9494
#endif
9595

96+
// TxParam defaults
97+
enum {
98+
// initial value of UplinkDwellTime before TxParamSetupReq received.
99+
AS923_INITIAL_TxParam_UplinkDwellTime = 1,
100+
// initial value of DownlinkDwellTime before TxParamSetupReq received.
101+
AS923_INITIAL_TxParam_DownlinkDwellTime = 1,
102+
AS923_UPLINK_DWELL_TIME_osticks = sec2osticks(20),
103+
};
104+
96105
#endif /* _lorabase_as923_h_ */

src/lmic/lorabase_au921.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ enum {
7676
enum {
7777
AU921_TX_EIRP_MAX_DBM = 30 // 30 dBm
7878
};
79+
enum {
80+
// initial value of UplinkDwellTime before TxParamSetupReq received.
81+
AU921_INITIAL_TxParam_UplinkDwellTime = 1,
82+
AU921_UPLINK_DWELL_TIME_osticks = sec2osticks(20),
83+
};
7984

8085
enum { DR_PAGE_AU921 = 0x10 * (LMIC_REGION_au921 - 1) };
8186

0 commit comments

Comments
 (0)