Skip to content

Commit 9a3792d

Browse files
authored
Merge pull request #727 from mcci-catena/issue515
Fix channel sequencing
2 parents 1a6074b + 13c8759 commit 9a3792d

20 files changed

+801
-209
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ If the library is configured for US915 operation, we make the following changes:
288288

289289
- Add the APIs `LMIC_enableChannel()`,
290290
`LMIC_enableSubBand()`, `LMIC_disableSubBand()`, and `LMIC_selectSubBand()`.
291-
- Add the constants `MAX_XCHANNELS`.
292291
- Add a number of additional `DR_...` symbols.
293292

294293
### Selecting the target radio transceiver

src/lmic/lmic.h

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Copyright (c) 2014-2016 IBM Corporation.
33
* Copyright (c) 2016 Matthijs Kooijman.
4-
* Copyright (c) 2016-2020 MCCI Corporation.
4+
* Copyright (c) 2016-2021 MCCI Corporation.
55
* All rights reserved.
66
*
77
* Redistribution and use in source and binary forms, with or without
@@ -96,7 +96,7 @@
9696
extern "C"{
9797
#endif
9898

99-
// LMIC version -- this is ths IBM LMIC version
99+
// LMIC version -- this is the IBM LMIC version
100100
#define LMIC_VERSION_MAJOR 1
101101
#define LMIC_VERSION_MINOR 6
102102
#define LMIC_VERSION_BUILD 1468577746
@@ -105,7 +105,8 @@ extern "C"{
105105
#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \
106106
((((major)*UINT32_C(1)) << 24) | (((minor)*UINT32_C(1)) << 16) | (((patch)*UINT32_C(1)) << 8) | (((local)*UINT32_C(1)) << 0))
107107

108-
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 3, 0, 0) /* v3.3.0 */
108+
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 99, 0, 2)
109+
/* 3.99.0-1 */
109110

110111
#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \
111112
((((v)*UINT32_C(1)) >> 24u) & 0xFFu)
@@ -119,10 +120,35 @@ extern "C"{
119120
#define ARDUINO_LMIC_VERSION_GET_LOCAL(v) \
120121
((v) & 0xFFu)
121122

123+
/// \brief convert a semantic version to an ordinal integer.
124+
#define ARDUINO_LMIC_VERSION_TO_ORDINAL(v) \
125+
(((v) & 0xFFFFFF00u) | (((v) - 1) & 0xFFu))
126+
127+
/// \brief compare two semantic versions
128+
/// \return \c true if \p a is less than \p b (as a semantic version).
129+
#define ARDUINO_LMIC_VERSION_COMPARE_LT(a, b) \
130+
(ARDUINO_LMIC_VERSION_TO_ORDINAL(a) < ARDUINO_LMIC_VERSION_TO_ORDINAL(b))
131+
132+
/// \brief compare two semantic versions
133+
/// \return \c true if \p a is less than or equal to \p b (as a semantic version).
134+
#define ARDUINO_LMIC_VERSION_COMPARE_LE(a, b) \
135+
(ARDUINO_LMIC_VERSION_TO_ORDINAL(a) <= ARDUINO_LMIC_VERSION_TO_ORDINAL(b))
136+
137+
/// \brief compare two semantic versions
138+
/// \return \c true if \p a is greater than \p b (as a semantic version).
139+
#define ARDUINO_LMIC_VERSION_COMPARE_GT(a, b) \
140+
(ARDUINO_LMIC_VERSION_TO_ORDINAL(a) > ARDUINO_LMIC_VERSION_TO_ORDINAL(b))
141+
142+
/// \brief compare two semantic versions
143+
/// \return \c true if \p a is greater than or equal to \p b (as a semantic version).
144+
#define ARDUINO_LMIC_VERSION_COMPARE_GE(a, b) \
145+
(ARDUINO_LMIC_VERSION_TO_ORDINAL(a) >= ARDUINO_LMIC_VERSION_TO_ORDINAL(b))
146+
147+
122148
//! Only For Antenna Tuning Tests !
123149
//#define CFG_TxContinuousMode 1
124150

125-
// since this was annouunced as the API variable, we keep it. But it's not used,
151+
// since this was announced as the API variable, we keep it. But it's not used,
126152
// MAX_LEN_FRAME is what the code uses.
127153
enum { MAX_FRAME_LEN = MAX_LEN_FRAME }; //!< Library cap on max frame length
128154

@@ -131,10 +157,10 @@ enum { MAX_MISSED_BCNS = (2 * 60 * 60 + 127) / 128 }; //!< threshold for d
131157
// note that we need 100 ppm timing accuracy for
132158
// this, to keep the timing error to +/- 700ms.
133159
enum { MAX_RXSYMS = 350 }; // Stop tracking beacon if sync error grows beyond this. A 0.4% clock error
134-
// at SF9.125k means 512 ms; one sybol is 4.096 ms,
160+
// at SF9.125k means 512 ms; one symbol is 4.096 ms,
135161
// so this needs to be at least 125 for an STM32L0.
136162
// And for 100ppm clocks and 2 hours of beacon misses,
137-
// this needs to accomodate 1.4 seconds of error at
163+
// this needs to accommodate 1.4 seconds of error at
138164
// 4.096 ms/sym or at least 342 symbols.
139165

140166
enum { LINK_CHECK_CONT = 0 , // continue with this after reported dead link
@@ -161,7 +187,7 @@ struct band_t {
161187
u2_t txcap; // duty cycle limitation: 1/txcap
162188
s1_t txpow; // maximum TX power
163189
u1_t lastchnl; // last used channel
164-
ostime_t avail; // channel is blocked until this time
190+
ostime_t avail; // band is blocked until this time
165191
};
166192
TYPEDEF_xref2band_t; //!< \internal
167193

@@ -172,10 +198,8 @@ struct lmic_saved_adr_state_s {
172198

173199
#elif CFG_LMIC_US_like // US915 spectrum =================================================
174200

175-
enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable
176-
177201
struct lmic_saved_adr_state_s {
178-
u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits
202+
u2_t channelMap[(72+15)/16]; // enabled bits
179203
u2_t activeChannels125khz;
180204
u2_t activeChannels500khz;
181205
};
@@ -531,10 +555,10 @@ struct lmic_t {
531555
// bit map of enabled datarates for each channel
532556
u2_t channelDrMap[MAX_CHANNELS];
533557
u2_t channelMap;
558+
u2_t channelShuffleMap;
534559
#elif CFG_LMIC_US_like
535-
u4_t xchFreq[MAX_XCHANNELS]; // extra channel frequencies (if device is behind a repeater)
536-
u2_t xchDrMap[MAX_XCHANNELS]; // extra channel datarate ranges ---XXX: ditto
537-
u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits
560+
u2_t channelMap[(72+15)/16]; // enabled bits
561+
u2_t channelShuffleMap[(72+15)/16]; // enabled bits
538562
u2_t activeChannels125khz;
539563
u2_t activeChannels500khz;
540564
#endif
@@ -569,7 +593,10 @@ struct lmic_t {
569593

570594
u1_t txChnl; // channel for next TX
571595
u1_t globalDutyRate; // max rate: 1/2^k
572-
596+
#if CFG_LMIC_US_like
597+
u1_t txChnl_125kHz; ///< during joins on 500 kHz, the 125 kHz channel
598+
/// that was last used.
599+
#endif
573600
u1_t upRepeat; // configured up repeat
574601
s1_t adrTxPow; // ADR adjusted TX power
575602
u1_t datarate; // current data rate
@@ -659,6 +686,9 @@ bit_t LMIC_enableChannel(u1_t channel);
659686
bit_t LMIC_disableSubBand(u1_t band);
660687
bit_t LMIC_selectSubBand(u1_t band);
661688

689+
//! \brief get the number of (fixed) default channels before the progammable channels.
690+
u1_t LMIC_queryNumDefaultChannels(void);
691+
662692
void LMIC_setDrTxpow (dr_t dr, s1_t txpow); // set default/start DR/txpow
663693
void LMIC_setAdrMode (bit_t enabled); // set ADR mode (if mobile turn off)
664694

@@ -705,6 +735,8 @@ int LMIC_getNetworkTimeReference(lmic_time_reference_t *pReference);
705735
int LMIC_registerRxMessageCb(lmic_rxmessage_cb_t *pRxMessageCb, void *pUserData);
706736
int LMIC_registerEventCb(lmic_event_cb_t *pEventCb, void *pUserData);
707737

738+
int LMIC_findNextChannel(uint16_t *, const uint16_t *, uint16_t, int);
739+
708740
// APIs for client half of compliance.
709741
typedef u1_t lmic_compliance_rx_action_t;
710742

src/lmic/lmic_as923.c

Lines changed: 127 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (c) 2014-2016 IBM Corporation.
3-
* Copyright (c) 2017, 2019 MCCI Corporation.
3+
* Copyright (c) 2017, 2019-2021 MCCI Corporation.
44
* All rights reserved.
55
*
66
* Redistribution and use in source and binary forms, with or without
@@ -50,6 +50,14 @@ CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
5050
ILLEGAL_RPS
5151
};
5252

53+
bit_t
54+
LMICas923_validDR(dr_t dr) {
55+
// use subtract here to avoid overflow
56+
if (dr >= LENOF_TABLE(_DR2RPS_CRC) - 2)
57+
return 0;
58+
return TABLE_GET_U1(_DR2RPS_CRC, dr+1)!=ILLEGAL_RPS;
59+
}
60+
5361
// see table in 2.7.6 -- this assumes UplinkDwellTime = 0.
5462
static CONST_TABLE(u1_t, maxFrameLens_dwell0)[] = {
5563
59+5, // [0]
@@ -226,17 +234,29 @@ bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
226234
return 1;
227235
}
228236

237+
238+
///
239+
/// \brief query number of default channels.
240+
///
241+
u1_t LMIC_queryNumDefaultChannels() {
242+
return NUM_DEFAULT_CHANNELS;
243+
}
244+
245+
///
246+
/// \brief LMIC_setupChannel for EU 868
247+
///
248+
/// \note according to LoRaWAN 1.3 section 5.6, "the acceptable range
249+
/// for **ChIndex** is N to 16", where N is our \c NUM_DEFAULT_CHANNELS.
250+
/// This routine is used internally for MAC commands, so we enforce
251+
/// this for the extenal API as well.
252+
///
229253
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
230254
// zero the band bits in freq, just in case.
231255
freq &= ~3;
232256

233257
if (chidx < NUM_DEFAULT_CHANNELS) {
234-
// can't disable a default channel.
235-
if (freq == 0)
236-
return 0;
237-
// can't change a default channel.
238-
else if (freq != (LMIC.channelFreq[chidx] & ~3))
239-
return 0;
258+
// can't do anything to a default channel.
259+
return 0;
240260
}
241261
bit_t fEnable = (freq != 0);
242262
if (chidx >= MAX_CHANNELS)
@@ -315,36 +335,107 @@ void LMICas923_setRx1Params(void) {
315335
LMIC.rps = dndr2rps(LMIC.dndr);
316336
}
317337

318-
319-
// return the next time, but also do channel hopping here
320-
// identical to the EU868 version; but note that we only have BAND_CENTI
321-
// at work.
338+
///
339+
/// \brief change the TX channel given the desired tx time.
340+
///
341+
/// \param [in] now is the time at which we want to transmit. In fact, it's always
342+
/// the current time.
343+
///
344+
/// \returns the actual time at which we can transmit. \c LMIC.txChnl is set to the
345+
/// selected channel.
346+
///
347+
/// \details
348+
/// We scan all the bands, creating a mask of all enabled channels that are
349+
/// feasible at the earliest possible time. We then randomly choose one from
350+
/// that, updating the shuffle mask.
351+
///
352+
/// \note
353+
/// identical to the EU868 version; but note that we only have BAND_CENTI
354+
/// in AS923.
355+
///
322356
ostime_t LMICas923_nextTx(ostime_t now) {
323-
u1_t bmap = 0xF;
324-
do {
325-
ostime_t mintime = now + /*8h*/sec2osticks(28800);
326-
u1_t band = 0;
327-
for (u1_t bi = 0; bi<4; bi++) {
328-
if ((bmap & (1 << bi)) && mintime - LMIC.bands[bi].avail > 0)
329-
mintime = LMIC.bands[band = bi].avail;
330-
}
331-
// Find next channel in given band
332-
u1_t chnl = LMIC.bands[band].lastchnl;
333-
for (u1_t ci = 0; ci<MAX_CHANNELS; ci++) {
334-
if ((chnl = (chnl + 1)) >= MAX_CHANNELS)
335-
chnl -= MAX_CHANNELS;
336-
if ((LMIC.channelMap & (1 << chnl)) != 0 && // channel enabled
337-
(LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) != 0 &&
338-
band == (LMIC.channelFreq[chnl] & 0x3)) { // in selected band
339-
LMIC.txChnl = LMIC.bands[band].lastchnl = chnl;
340-
return mintime;
341-
}
342-
}
343-
if ((bmap &= ~(1 << band)) == 0) {
344-
// No feasible channel found!
345-
return mintime;
346-
}
347-
} while (1);
357+
ostime_t mintime = now + /*8h*/sec2osticks(28800);
358+
u2_t availMap;
359+
u2_t feasibleMap;
360+
u1_t bandMap;
361+
362+
// set mintime to the earliest time of all enabled channels
363+
// (can't just look at bands); and for a given channel, we
364+
// can't tell if we're ready till we've checked all possible
365+
// avail times.
366+
bandMap = 0;
367+
for (u1_t chnl = 0; chnl < MAX_CHANNELS; ++chnl) {
368+
u2_t chnlBit = 1 << chnl;
369+
370+
// none at any higher numbers?
371+
if (LMIC.channelMap < chnlBit)
372+
break;
373+
374+
// not enabled?
375+
if ((LMIC.channelMap & chnlBit) == 0)
376+
continue;
377+
378+
// not feasible?
379+
if ((LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) == 0)
380+
continue;
381+
382+
u1_t const band = LMIC.channelFreq[chnl] & 0x3;
383+
u1_t const thisBandBit = 1 << band;
384+
// already considered?
385+
if ((bandMap & thisBandBit) != 0)
386+
continue;
387+
388+
// consider this band.
389+
bandMap |= thisBandBit;
390+
391+
// enabled, not considered, feasible: adjust the min time.
392+
if ((s4_t)(mintime - LMIC.bands[band].avail) > 0)
393+
mintime = LMIC.bands[band].avail;
394+
}
395+
396+
// make a mask of candidates available for use
397+
availMap = 0;
398+
for (u1_t chnl = 0; chnl < MAX_CHANNELS; ++chnl) {
399+
u2_t chnlBit = 1 << chnl;
400+
401+
// none at any higher numbers?
402+
if (LMIC.channelMap < chnlBit)
403+
break;
404+
405+
// not enabled?
406+
if ((LMIC.channelMap & chnlBit) == 0)
407+
continue;
408+
409+
// not feasible?
410+
if ((LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) == 0)
411+
continue;
412+
413+
// not available yet?
414+
feasibleMap |= chnlBit;
415+
416+
u1_t const band = LMIC.channelFreq[chnl] & 0x3;
417+
if ((s4_t)(LMIC.bands[band].avail - mintime) > 0)
418+
continue;
419+
420+
// ok: this is a candidate.
421+
availMap |= chnlBit;
422+
}
423+
424+
// find the next available chennel.
425+
u2_t saveShuffleMap = LMIC.channelShuffleMap;
426+
int candidateCh = LMIC_findNextChannel(&LMIC.channelShuffleMap, &availMap, 1, LMIC.txChnl == 0xFF ? -1 : LMIC.txChnl);
427+
428+
// restore bits in the shuffleMap that were on, but might have reset
429+
// if availMap was used to refresh shuffleMap. These are channels that
430+
// are feasble but not yet candidates due to band saturation
431+
LMIC.channelShuffleMap |= saveShuffleMap & feasibleMap & ~availMap;
432+
433+
if (candidateCh >= 0) {
434+
// update the channel; otherwise we'll just use the
435+
// most recent one.
436+
LMIC.txChnl = candidateCh;
437+
}
438+
return mintime;
348439
}
349440

350441
#if !defined(DISABLE_BEACONS)

src/lmic/lmic_au915.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Copyright (c) 2014-2016 IBM Corporation.
3-
* Copyright (c) 2017, 2019 MCCI Corporation.
3+
* Copyright (c) 2017, 2019-2021 MCCI Corporation.
44
* All rights reserved.
55
*
66
* Redistribution and use in source and binary forms, with or without
@@ -55,6 +55,14 @@ CONST_TABLE(u1_t, _DR2RPS_CRC)[] = {
5555
ILLEGAL_RPS
5656
};
5757

58+
bit_t
59+
LMICau915_validDR(dr_t dr) {
60+
// use subtract here to avoid overflow
61+
if (dr >= LENOF_TABLE(_DR2RPS_CRC) - 2)
62+
return 0;
63+
return TABLE_GET_U1(_DR2RPS_CRC, dr+1)!=ILLEGAL_RPS;
64+
}
65+
5866
static CONST_TABLE(u1_t, maxFrameLens_dwell0)[] = {
5967
59+5, 59+5, 59+5, 123+5, 250+5, 250+5, 250+5, 0,
6068
61+5, 137+5, 250+5, 250+5, 250+5, 250+5 };
@@ -144,7 +152,24 @@ u4_t LMICau915_convFreq(xref2cu1_t ptr) {
144152
return freq;
145153
}
146154

147-
// au915: no support for xchannels.
155+
///
156+
/// \brief query number of default channels.
157+
///
158+
/// \note
159+
/// For AU, we have no programmable channels; all channels
160+
/// are fixed. Return the total channel count.
161+
///
162+
u1_t LMIC_queryNumDefaultChannels() {
163+
return 64 + 8;
164+
}
165+
166+
167+
///
168+
/// \brief LMIC_setupChannel for AU915
169+
///
170+
/// \note there are no progammable channels for US915, so this API
171+
/// always returns FALSE.
172+
///
148173
bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
149174
LMIC_API_PARAMETER(chidx);
150175
LMIC_API_PARAMETER(freq);

0 commit comments

Comments
 (0)