Skip to content

Commit 42da75b

Browse files
committed
Fix #442: make RX timing closer to Semtech's
1 parent 76f7bd5 commit 42da75b

File tree

6 files changed

+90
-52
lines changed

6 files changed

+90
-52
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ void printAllRegisters(void) {
310310
printNl();
311311
printHex2(i);
312312
}
313+
Serial.print(((i % 8) == 0) ? F(" - ") : F(" "));
313314
printHex2(regbuf[i]);
314-
Serial.print(((i % 16) == 8) ? F(" - ") : F(" "));
315315
}
316316

317317
// reset the radio, just in case the register dump caused issues.
@@ -630,7 +630,8 @@ void setup() {
630630
// Reset the MAC state. Session and pending data transfers will be discarded.
631631
LMIC_reset();
632632

633-
LMIC_setClockError(1 * MAX_CLOCK_ERROR / 100);
633+
// set clock rate error to 0.1%
634+
LMIC_setClockError(1 * MAX_CLOCK_ERROR / 1000);
634635

635636
// do the network-specific setup prior to join.
636637
setupForNetwork(false);

src/lmic/lmic.c

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,11 @@ static ostime_t calcRxWindow (u1_t secs, dr_t dr) {
306306
rxoff = (LMIC.drift * (ostime_t)secs) >> BCN_INTV_exp;
307307
err = (LMIC.lastDriftDiff * (ostime_t)secs) >> BCN_INTV_exp;
308308
}
309-
u1_t rxsyms = MINRX_SYMS;
309+
u1_t rxsyms = LMICbandplan_MINRX_SYMS_LoRa_ClassB;
310310
err += (ostime_t)LMIC.maxDriftDiff * LMIC.missedBcns;
311-
LMIC.rxsyms = MINRX_SYMS + (err / dr2hsym(dr));
311+
LMIC.rxsyms = LMICbandplan_MINRX_SYMS_LoRa_ClassB + (err / dr2hsym(dr));
312312

313-
return (rxsyms-PAMBL_SYMS) * dr2hsym(dr) + rxoff;
313+
return (rxsyms-LMICbandplan_PAMBL_SYMS) * dr2hsym(dr) + rxoff;
314314
}
315315

316316

@@ -323,8 +323,8 @@ static void calcBcnRxWindowFromMillis (u1_t ms, bit_t ini) {
323323
LMIC.bcninfo.flags |= BCN_NODRIFT|BCN_NODDIFF;
324324
}
325325
ostime_t hsym = dr2hsym(DR_BCN);
326-
LMIC.bcnRxsyms = MINRX_SYMS + ms2osticksCeil(ms) / hsym;
327-
LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - (LMIC.bcnRxsyms-PAMBL_SYMS) * hsym;
326+
LMIC.bcnRxsyms = LMICbandplan_MINRX_SYMS_LoRa_ClassB + ms2osticksCeil(ms) / hsym;
327+
LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - (LMIC.bcnRxsyms-LMICbandplan_PAMBL_SYMS) * hsym;
328328
}
329329
#endif // !DISABLE_BEACONS
330330

@@ -1421,14 +1421,7 @@ static void setupRx2 (void) {
14211421
radioRx();
14221422
}
14231423

1424-
1425-
static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) {
1426-
ostime_t hsym = dr2hsym(dr);
1427-
1428-
LMIC.rxsyms = MINRX_SYMS;
1429-
1430-
// If a clock error is specified, compensate for it by extending the
1431-
// receive window
1424+
ostime_t LMICcore_adjustForDrift (ostime_t delay, ostime_t hsym) {
14321425
if (LMIC.client.clockError != 0) {
14331426
// Calculate how much the clock will drift maximally after delay has
14341427
// passed. This indicates the amount of time we can be early
@@ -1437,20 +1430,47 @@ static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) {
14371430

14381431
// Increase the receive window by twice the maximum drift (to
14391432
// compensate for a slow or a fast clock).
1440-
// decrease the rxtime to compensate for. Note that hsym is a
1441-
// *half* symbol time, so the factor 2 is hidden. First check if
1442-
// this would overflow (which can happen if the drift is very
1443-
// high, or the symbol time is low at high datarates).
1444-
if ((255 - LMIC.rxsyms) * hsym < drift)
1433+
delay -= drift;
1434+
1435+
// adjust rxsyms (the size of the window in syms) according to our
1436+
// uncertainty. do this in a strange order to avoid a divide if we can.
1437+
// rely on hsym = Tsym / 2
1438+
if ((255 - LMIC.rxsyms) * hsym < drift) {
14451439
LMIC.rxsyms = 255;
1446-
else
1447-
LMIC.rxsyms += drift / hsym;
1440+
} else {
1441+
LMIC.rxsyms = (u1_t) (LMIC.rxsyms + drift / hsym);
1442+
}
1443+
}
1444+
return delay;
1445+
}
1446+
1447+
ostime_t LMICcore_RxWindowOffset (ostime_t hsym, u1_t rxsyms_in) {
1448+
ostime_t const Tsym = 2 * hsym;
1449+
ostime_t rxsyms;
1450+
ostime_t rxoffset;
14481451

1452+
rxsyms = ((2 * (int)rxsyms_in - 8) * Tsym + LMICbandplan_RX_ERROR_ABS_osticks * 2 + Tsym - 1) / Tsym;
1453+
if (rxsyms < rxsyms_in) {
1454+
rxsyms = rxsyms_in;
14491455
}
1456+
LMIC.rxsyms = (u1_t) rxsyms;
1457+
1458+
rxoffset = (8 - rxsyms) * hsym - LMICbandplan_RX_EXTRA_MARGIN_osticks;
1459+
1460+
return rxoffset;
1461+
}
14501462

1451-
// Center the receive window on the center of the expected preamble
1463+
static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) {
1464+
ostime_t hsym = dr2hsym(dr);
1465+
1466+
// Center the receive window on the center of the expected preamble and timeout.
14521467
// (again note that hsym is half a sumbol time, so no /2 needed)
1453-
LMIC.rxtime = LMIC.txend + delay + PAMBL_SYMS * hsym - LMIC.rxsyms * hsym;
1468+
// we leave RX_RAMPUP unadjusted for the clock drift. The IBM LMIC generates delays
1469+
// that are too long for SF12, and too short for other SFs, so we follow the
1470+
// Semtech reference code.
1471+
//
1472+
// This also sets LMIC.rxsyms.
1473+
LMIC.rxtime = LMIC.txend + LMICcore_adjustForDrift(delay + LMICcore_RxWindowOffset(hsym, LMICbandplan_MINRX_SYMS_LoRa_ClassA), hsym);
14541474

14551475
LMIC_X_DEBUG_PRINTF("%"LMIC_PRId_ostime_t": sched Rx12 %"LMIC_PRId_ostime_t"\n", os_getTime(), LMIC.rxtime - RX_RAMPUP);
14561476
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);

src/lmic/lmic.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,9 @@ extern "C"{
103103

104104
// Arduino LMIC version
105105
#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \
106-
(((major) << UINT32_C(24)) | ((minor) << UINT32_C(16)) | ((patch) << UINT32_C(8)) | ((local << UINT32_C(0))))
106+
(((major) << 24ul) | ((minor) << 16ul) | ((patch) << 8ul) | ((local) << 0ul))
107107

108-
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 1) /* v3.0.99.1 */
108+
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(3, 0, 99, 2) /* v3.0.99.2 */
109109

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

src/lmic/lmic_bandplan.h

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,35 @@
169169
//
170170
// Things common to lmic.c code
171171
//
172+
#define LMICbandplan_MINRX_SYMS_LoRa_ClassA 6
173+
#define LMICbandplan_RX_ERROR_ABS_osticks ms2osticks(10)
174+
175+
// Semtech inherently (by calculating in ms and taking ceilings)
176+
// rounds up to the next higher ms. It's a lot easier for us
177+
// to just add margin for things like hardware ramp-up time
178+
// and clock calibration when running from the LSE and HSI
179+
// clocks on an STM32.
180+
#define LMICbandplan_RX_EXTRA_MARGIN_osticks us2osticks(2000)
181+
182+
// probably this should be the same as the Class-A value, but
183+
// we have not the means to thoroughly test this. This is the
184+
// number of rxsyms used in the computations for ping and beacon
185+
// windows.
186+
#define LMICbandplan_MINRX_SYMS_LoRa_ClassB 5
187+
188+
#define LMICbandplan_PAMBL_SYMS 8
189+
#define LMICbandplan_PAMBL_FSK 5
190+
#define LMICbandplan_PRERX_FSK 1
191+
#define LMICbandplan_RXLEN_FSK (1+5+2)
192+
193+
// Legacy names
172194
#if !defined(MINRX_SYMS)
173-
#define MINRX_SYMS 5
195+
# define MINRX_SYMS LMICbandplan_MINRX_SYMS_LoRa_ClassB
174196
#endif // !defined(MINRX_SYMS)
175-
#define PAMBL_SYMS 8
176-
#define PAMBL_FSK 5
177-
#define PRERX_FSK 1
178-
#define RXLEN_FSK (1+5+2)
197+
#define PAMBL_SYMS LMICbandplan_PAMBL_SYMS
198+
#define PAMBL_FSK LMICbandplan_PAMBL_FSK
199+
#define PRERX_FSK LMICbandplan_PRERX_FSK
200+
#define RXLEN_FSK LMICbandplan_RXLEN_FSK
179201

180202
// this is regional, but so far all regions are the same
181203
#if !defined(LMICbandplan_MAX_FCNT_GAP)
@@ -204,5 +226,7 @@
204226
// internal APIs
205227
ostime_t LMICcore_rndDelay(u1_t secSpan);
206228
void LMICcore_setDrJoin(u1_t reason, u1_t dr);
229+
ostime_t LMICcore_adjustForDrift(ostime_t delay, ostime_t hsym);
230+
ostime_t LMICcore_RxWindowOffset(ostime_t hsym, u1_t rxsyms_in);
207231

208232
#endif // _lmic_bandplan_h_

src/lmic/lmic_eu_like.c

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -254,28 +254,13 @@ void LMICeulike_setRx1Freq(void) {
254254
// Class A txDone handling for FSK.
255255
void
256256
LMICeulike_txDoneFSK(ostime_t delay, osjobcb_t func) {
257-
LMIC.rxsyms = RXLEN_FSK;
257+
ostime_t const hsym = us2osticksRound(80);
258258

259-
// If a clock error is specified, compensate for it by extending the
260-
// receive window
261-
delay -= PRERX_FSK * us2osticksRound(160);
259+
// start a little earlier.
260+
delay -= LMICbandplan_PRERX_FSK * us2osticksRound(160);
262261

263-
if (LMIC.client.clockError != 0) {
264-
// Calculate how much the clock will drift maximally after delay has
265-
// passed. This indicates the amount of time we can be early
266-
// _or_ late.
267-
ostime_t drift = (int64_t)delay * LMIC.client.clockError / MAX_CLOCK_ERROR;
268-
269-
// Increase the receive window by twice the maximum drift (to
270-
// compensate for a slow or a fast clock).
271-
// decrease the rxtime to compensate for. Note that hsym is a
272-
// *half* symbol time, so the factor 2 is hidden. First check if
273-
// this would overflow (which can happen if the drift is very
274-
// high, or the symbol time is low at high datarates).
275-
delay -= drift;
276-
}
277-
278-
LMIC.rxtime = LMIC.txend + delay;
262+
// set LMIC.rxtime and LMIC.rxsyms:
263+
LMIC.rxtime = LMIC.txend + LMICcore_adjustForDrift(delay + LMICcore_RxWindowOffset(hsym, LMICbandplan_RXLEN_FSK), hsym);
279264
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
280265
}
281266

src/lmic/oslmic.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,19 @@ void radio_monitor_rssi(ostime_t n, oslmic_radio_rssi_t *pRssi);
119119

120120
//================================================================================
121121

122-
123122
#ifndef RX_RAMPUP
123+
// RX_RAMPUP specifies the extra time we must allow to set up an RX event due
124+
// to platform issues. It's specified in units of ostime_t. It must reflect
125+
// platform jitter and latency, as well as the speed of the LMIC when running
126+
// on this plaform.
124127
#define RX_RAMPUP (us2osticks(2000))
125128
#endif
129+
126130
#ifndef TX_RAMPUP
131+
// TX_RAMPUP specifies the extra time we must allow to set up a TX event) due
132+
// to platform issues. It's specified in units of ostime_t. It must reflect
133+
// platform jitter and latency, as well as the speed of the LMIC when running
134+
// on this plaform.
127135
#define TX_RAMPUP (us2osticks(2000))
128136
#endif
129137

0 commit comments

Comments
 (0)