Skip to content

Commit

Permalink
Fix #442: make RX timing closer to Semtech's
Browse files Browse the repository at this point in the history
  • Loading branch information
terrillmoore committed Sep 10, 2019
1 parent 76f7bd5 commit 42da75b
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ void printAllRegisters(void) {
printNl();
printHex2(i);
}
Serial.print(((i % 8) == 0) ? F(" - ") : F(" "));
printHex2(regbuf[i]);
Serial.print(((i % 16) == 8) ? F(" - ") : F(" "));
}

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

LMIC_setClockError(1 * MAX_CLOCK_ERROR / 100);
// set clock rate error to 0.1%
LMIC_setClockError(1 * MAX_CLOCK_ERROR / 1000);

// do the network-specific setup prior to join.
setupForNetwork(false);
Expand Down
64 changes: 42 additions & 22 deletions src/lmic/lmic.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,11 @@ static ostime_t calcRxWindow (u1_t secs, dr_t dr) {
rxoff = (LMIC.drift * (ostime_t)secs) >> BCN_INTV_exp;
err = (LMIC.lastDriftDiff * (ostime_t)secs) >> BCN_INTV_exp;
}
u1_t rxsyms = MINRX_SYMS;
u1_t rxsyms = LMICbandplan_MINRX_SYMS_LoRa_ClassB;
err += (ostime_t)LMIC.maxDriftDiff * LMIC.missedBcns;
LMIC.rxsyms = MINRX_SYMS + (err / dr2hsym(dr));
LMIC.rxsyms = LMICbandplan_MINRX_SYMS_LoRa_ClassB + (err / dr2hsym(dr));

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


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

Expand Down Expand Up @@ -1421,14 +1421,7 @@ static void setupRx2 (void) {
radioRx();
}


static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) {
ostime_t hsym = dr2hsym(dr);

LMIC.rxsyms = MINRX_SYMS;

// If a clock error is specified, compensate for it by extending the
// receive window
ostime_t LMICcore_adjustForDrift (ostime_t delay, ostime_t hsym) {
if (LMIC.client.clockError != 0) {
// Calculate how much the clock will drift maximally after delay has
// passed. This indicates the amount of time we can be early
Expand All @@ -1437,20 +1430,47 @@ static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) {

// Increase the receive window by twice the maximum drift (to
// compensate for a slow or a fast clock).
// decrease the rxtime to compensate for. Note that hsym is a
// *half* symbol time, so the factor 2 is hidden. First check if
// this would overflow (which can happen if the drift is very
// high, or the symbol time is low at high datarates).
if ((255 - LMIC.rxsyms) * hsym < drift)
delay -= drift;

// adjust rxsyms (the size of the window in syms) according to our
// uncertainty. do this in a strange order to avoid a divide if we can.
// rely on hsym = Tsym / 2
if ((255 - LMIC.rxsyms) * hsym < drift) {
LMIC.rxsyms = 255;
else
LMIC.rxsyms += drift / hsym;
} else {
LMIC.rxsyms = (u1_t) (LMIC.rxsyms + drift / hsym);
}
}
return delay;
}

ostime_t LMICcore_RxWindowOffset (ostime_t hsym, u1_t rxsyms_in) {
ostime_t const Tsym = 2 * hsym;
ostime_t rxsyms;
ostime_t rxoffset;

rxsyms = ((2 * (int)rxsyms_in - 8) * Tsym + LMICbandplan_RX_ERROR_ABS_osticks * 2 + Tsym - 1) / Tsym;
if (rxsyms < rxsyms_in) {
rxsyms = rxsyms_in;
}
LMIC.rxsyms = (u1_t) rxsyms;

rxoffset = (8 - rxsyms) * hsym - LMICbandplan_RX_EXTRA_MARGIN_osticks;

return rxoffset;
}

// Center the receive window on the center of the expected preamble
static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) {
ostime_t hsym = dr2hsym(dr);

// Center the receive window on the center of the expected preamble and timeout.
// (again note that hsym is half a sumbol time, so no /2 needed)
LMIC.rxtime = LMIC.txend + delay + PAMBL_SYMS * hsym - LMIC.rxsyms * hsym;
// we leave RX_RAMPUP unadjusted for the clock drift. The IBM LMIC generates delays
// that are too long for SF12, and too short for other SFs, so we follow the
// Semtech reference code.
//
// This also sets LMIC.rxsyms.
LMIC.rxtime = LMIC.txend + LMICcore_adjustForDrift(delay + LMICcore_RxWindowOffset(hsym, LMICbandplan_MINRX_SYMS_LoRa_ClassA), hsym);

LMIC_X_DEBUG_PRINTF("%"LMIC_PRId_ostime_t": sched Rx12 %"LMIC_PRId_ostime_t"\n", os_getTime(), LMIC.rxtime - RX_RAMPUP);
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
Expand Down
4 changes: 2 additions & 2 deletions src/lmic/lmic.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ extern "C"{

// Arduino LMIC version
#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \
(((major) << UINT32_C(24)) | ((minor) << UINT32_C(16)) | ((patch) << UINT32_C(8)) | ((local << UINT32_C(0))))
(((major) << 24ul) | ((minor) << 16ul) | ((patch) << 8ul) | ((local) << 0ul))

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

#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \
(((v) >> 24u) & 0xFFu)
Expand Down
34 changes: 29 additions & 5 deletions src/lmic/lmic_bandplan.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,35 @@
//
// Things common to lmic.c code
//
#define LMICbandplan_MINRX_SYMS_LoRa_ClassA 6
#define LMICbandplan_RX_ERROR_ABS_osticks ms2osticks(10)

// Semtech inherently (by calculating in ms and taking ceilings)
// rounds up to the next higher ms. It's a lot easier for us
// to just add margin for things like hardware ramp-up time
// and clock calibration when running from the LSE and HSI
// clocks on an STM32.
#define LMICbandplan_RX_EXTRA_MARGIN_osticks us2osticks(2000)

// probably this should be the same as the Class-A value, but
// we have not the means to thoroughly test this. This is the
// number of rxsyms used in the computations for ping and beacon
// windows.
#define LMICbandplan_MINRX_SYMS_LoRa_ClassB 5

#define LMICbandplan_PAMBL_SYMS 8
#define LMICbandplan_PAMBL_FSK 5
#define LMICbandplan_PRERX_FSK 1
#define LMICbandplan_RXLEN_FSK (1+5+2)

// Legacy names
#if !defined(MINRX_SYMS)
#define MINRX_SYMS 5
# define MINRX_SYMS LMICbandplan_MINRX_SYMS_LoRa_ClassB
#endif // !defined(MINRX_SYMS)
#define PAMBL_SYMS 8
#define PAMBL_FSK 5
#define PRERX_FSK 1
#define RXLEN_FSK (1+5+2)
#define PAMBL_SYMS LMICbandplan_PAMBL_SYMS
#define PAMBL_FSK LMICbandplan_PAMBL_FSK
#define PRERX_FSK LMICbandplan_PRERX_FSK
#define RXLEN_FSK LMICbandplan_RXLEN_FSK

// this is regional, but so far all regions are the same
#if !defined(LMICbandplan_MAX_FCNT_GAP)
Expand Down Expand Up @@ -204,5 +226,7 @@
// internal APIs
ostime_t LMICcore_rndDelay(u1_t secSpan);
void LMICcore_setDrJoin(u1_t reason, u1_t dr);
ostime_t LMICcore_adjustForDrift(ostime_t delay, ostime_t hsym);
ostime_t LMICcore_RxWindowOffset(ostime_t hsym, u1_t rxsyms_in);

#endif // _lmic_bandplan_h_
25 changes: 5 additions & 20 deletions src/lmic/lmic_eu_like.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,28 +254,13 @@ void LMICeulike_setRx1Freq(void) {
// Class A txDone handling for FSK.
void
LMICeulike_txDoneFSK(ostime_t delay, osjobcb_t func) {
LMIC.rxsyms = RXLEN_FSK;
ostime_t const hsym = us2osticksRound(80);

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

if (LMIC.client.clockError != 0) {
// Calculate how much the clock will drift maximally after delay has
// passed. This indicates the amount of time we can be early
// _or_ late.
ostime_t drift = (int64_t)delay * LMIC.client.clockError / MAX_CLOCK_ERROR;

// Increase the receive window by twice the maximum drift (to
// compensate for a slow or a fast clock).
// decrease the rxtime to compensate for. Note that hsym is a
// *half* symbol time, so the factor 2 is hidden. First check if
// this would overflow (which can happen if the drift is very
// high, or the symbol time is low at high datarates).
delay -= drift;
}

LMIC.rxtime = LMIC.txend + delay;
// set LMIC.rxtime and LMIC.rxsyms:
LMIC.rxtime = LMIC.txend + LMICcore_adjustForDrift(delay + LMICcore_RxWindowOffset(hsym, LMICbandplan_RXLEN_FSK), hsym);
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
}

Expand Down
10 changes: 9 additions & 1 deletion src/lmic/oslmic.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,19 @@ void radio_monitor_rssi(ostime_t n, oslmic_radio_rssi_t *pRssi);

//================================================================================


#ifndef RX_RAMPUP
// RX_RAMPUP specifies the extra time we must allow to set up an RX event due
// to platform issues. It's specified in units of ostime_t. It must reflect
// platform jitter and latency, as well as the speed of the LMIC when running
// on this plaform.
#define RX_RAMPUP (us2osticks(2000))
#endif

#ifndef TX_RAMPUP
// TX_RAMPUP specifies the extra time we must allow to set up a TX event) due
// to platform issues. It's specified in units of ostime_t. It must reflect
// platform jitter and latency, as well as the speed of the LMIC when running
// on this plaform.
#define TX_RAMPUP (us2osticks(2000))
#endif

Expand Down

0 comments on commit 42da75b

Please sign in to comment.