Skip to content

Commit a035918

Browse files
authored
Merge pull request #174 from mcci-catena/issue169
Fix several issues with saved state
2 parents 9b664f5 + ff209ca commit a035918

File tree

3 files changed

+140
-94
lines changed

3 files changed

+140
-94
lines changed

src/Arduino_LoRaWAN.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Copyright notice:
3434
/// \ref ARDUINO_LORAWAN_VERSION_COMPARE_LT() to compare relative versions.
3535
///
3636
#define ARDUINO_LORAWAN_VERSION \
37-
ARDUINO_LORAWAN_VERSION_CALC(0, 9, 0, 0) /* v0.9.0 */
37+
ARDUINO_LORAWAN_VERSION_CALC(0, 9, 1, 2) /* v0.9.1-pre2 */
3838

3939
#define ARDUINO_LORAWAN_VERSION_GET_MAJOR(v) \
4040
(((v) >> 24u) & 0xFFu)
@@ -194,10 +194,10 @@ class Arduino_LoRaWAN
194194

195195
struct SessionChannelMask_Header
196196
{
197-
enum eMaskKind : uint8_t { kEUlike = 0, kUSlike = 1 };
197+
enum eMaskKind : uint8_t { kEUlike = 0, kUSlike = 1, kCNlike = 2 };
198198

199199
uint8_t Tag; ///< discriminator, eMaskKind.
200-
uint8_t Size; ///< size of SessionChannelMask, in bytes
200+
uint8_t Size; ///< size of actual SessionChannelMask, in bytes
201201
};
202202

203203
template <uint32_t a_nCh>
@@ -541,7 +541,9 @@ class Arduino_LoRaWAN
541541
{
542542
SessionStateHeader Header;
543543
SessionStateV1 V1;
544+
bool isValid() const;
544545
} SessionState;
546+
545547
/*
546548
|| the constructor.
547549
*/
@@ -677,6 +679,8 @@ class Arduino_LoRaWAN
677679
uint8_t *pBuf
678680
);
679681

682+
bool IsValidState(const SessionState &state) const;
683+
680684
// return true iff network seems to be provisioned. Make
681685
// it virtual so it can be overridden if needed.
682686
virtual bool IsProvisioned(void)

src/lib/arduino_lorawan_begin.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ bool Arduino_LoRaWAN::begin(
4949
LMIC_reset();
5050

5151
// if we can get saved state, go on.
52-
if (! this->RestoreSessionState())
52+
auto const fHaveSavedState = this->RestoreSessionState();
53+
if (! fHaveSavedState)
5354
{
5455
// Otherwise set data rate and transmit power, based on regional considerations.
5556
this->NetBeginRegionInit();
@@ -69,7 +70,8 @@ bool Arduino_LoRaWAN::begin(
6970
//
7071
AbpProvisioningInfo abpInfo;
7172

72-
if (this->GetAbpProvisioningInfo(&abpInfo))
73+
if ((fHaveSavedState || this->GetProvisioningStyle() == ProvisioningStyle::kABP) &&
74+
this->GetAbpProvisioningInfo(&abpInfo))
7375
{
7476
LMIC_setSession(
7577
abpInfo.NetID,
@@ -222,6 +224,18 @@ void Arduino_LoRaWAN::StandardEventProcessor(
222224
case EV_BEACON_TRACKED:
223225
break;
224226
case EV_JOINING:
227+
{
228+
// Set data rate and transmit power, based on regional considerations.
229+
// Allows regions to change the channel mask (which otherwise will
230+
// be reset to the region default -- possibly not what you want).
231+
this->NetBeginRegionInit();
232+
233+
// Update the session info
234+
this->SaveSessionInfo();
235+
236+
// save everything else of interest.
237+
this->SaveSessionState();
238+
}
225239
break;
226240

227241
case EV_JOINED:

src/lib/arduino_lorawan_sessionstate.cpp

+117-89
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ Arduino_LoRaWAN::BuildSessionState(
9999
// handle EU like regions
100100
#if CFG_LMIC_EU_like
101101
State.V1.Channels.Header.Tag = State.V1.Channels.Header.kEUlike;
102-
State.V1.Channels.Header.Tag = sizeof(State.V1.Channels.EUlike);
102+
State.V1.Channels.Header.Size = sizeof(State.V1.Channels.EUlike);
103103
State.V1.Channels.EUlike.clearAll();
104104
constexpr unsigned maxCh = MAX_CHANNELS < State.V1.Channels.EUlike.nCh ? MAX_CHANNELS : State.V1.Channels.EUlike.nCh;
105105
State.V1.Channels.EUlike.ChannelMap = LMIC.channelMap;
@@ -135,8 +135,8 @@ Arduino_LoRaWAN::BuildSessionState(
135135
}
136136

137137
#elif CFG_LMIC_US_like
138-
State.V1.Channels.Header.Tag = State.V1.Channels.Header.kEUlike;
139-
State.V1.Channels.Header.Tag = sizeof(State.V1.Channels.USlike);
138+
State.V1.Channels.Header.Tag = State.V1.Channels.Header.kUSlike;
139+
State.V1.Channels.Header.Size = sizeof(State.V1.Channels.USlike);
140140

141141
#if ARDUINO_LMIC_VERSION_COMPARE_GE(ARDUINO_LMIC_VERSION, ARDUINO_LMIC_VERSION_CALC(3,99,0,1))
142142
static_assert(
@@ -257,6 +257,43 @@ Name: Arduino_LoRaWAN::ApplySessionState()
257257
258258
*/
259259

260+
bool Arduino_LoRaWAN::IsValidState(const Arduino_LoRaWAN::SessionState &state) const
261+
{
262+
// do not apply the session state unless it roughly matches our configuration.
263+
if (! state.isValid())
264+
return false;
265+
266+
// make sure region and country match. TODO: make sure network matches.
267+
if (! (Arduino_LoRaWAN::Region(state.V1.Region) == this->GetRegion() &&
268+
state.V1.Country == uint16_t(this->GetCountryCode())))
269+
return false;
270+
271+
// it matches!
272+
return true;
273+
}
274+
275+
bool Arduino_LoRaWAN::SessionState::isValid() const
276+
{
277+
if (! (this->Header.Tag == kSessionStateTag_V1 &&
278+
this->Header.Size == sizeof(*this)))
279+
return false;
280+
281+
switch (this->V1.Channels.Header.Tag)
282+
{
283+
case Arduino_LoRaWAN::SessionChannelMask_Header::eMaskKind::kEUlike:
284+
return this->V1.Channels.Header.Size == sizeof(this->V1.Channels.EUlike);
285+
286+
case Arduino_LoRaWAN::SessionChannelMask_Header::eMaskKind::kUSlike:
287+
return this->V1.Channels.Header.Size == sizeof(this->V1.Channels.USlike);
288+
289+
case Arduino_LoRaWAN::SessionChannelMask_Header::eMaskKind::kCNlike:
290+
return this->V1.Channels.Header.Size == sizeof(this->V1.Channels.CNlike);
291+
292+
default:
293+
return false;
294+
}
295+
}
296+
260297
#define FUNCTION "Arduino_LoRaWAN::ApplySessionState"
261298

262299
bool
@@ -265,124 +302,115 @@ Arduino_LoRaWAN::ApplySessionState(
265302
)
266303
{
267304
// do not apply the session state unless it roughly matches our configuration.
268-
if (State.Header.Tag == kSessionStateTag_V1 &&
269-
Arduino_LoRaWAN::Region(State.V1.Region) == this->GetRegion() &&
270-
State.V1.Country == uint16_t(this->GetCountryCode())
271-
)
272-
{
273-
auto const tNow = os_getTime();
305+
if (! this->IsValidState(State))
306+
return false;
274307

275-
// record that we've done it.
276-
this->m_savedSessionState = State;
308+
auto const tNow = os_getTime();
309+
310+
// record that we've done it.
311+
this->m_savedSessionState = State;
277312

278-
// set FcntUp, FcntDown, and session state
279-
LMIC.datarate = State.V1.LinkDR;
313+
// set FcntUp, FcntDown, and session state
314+
LMIC.datarate = State.V1.LinkDR;
280315

281-
// set the uplink and downlink count
282-
LMIC.seqnoDn = State.V1.FCntDown;
283-
LMIC.seqnoUp = State.V1.FCntUp;
316+
// set the uplink and downlink count
317+
LMIC.seqnoDn = State.V1.FCntDown;
318+
LMIC.seqnoUp = State.V1.FCntUp;
284319

285-
//
286-
// TODO([email protected]): State.V1.gpsTime can be used to tweak the saved cycle
287-
// time and also as a fallback if the system clock is not robust. but right
288-
// now we ignore it.
289-
//
320+
//
321+
// TODO([email protected]): State.V1.gpsTime can be used to tweak the saved cycle
322+
// time and also as a fallback if the system clock is not robust. but right
323+
// now we ignore it.
324+
//
290325

291-
// conservatively set the global avail time.
292-
LMIC.globalDutyAvail = tNow + State.V1.globalAvail;
326+
// conservatively set the global avail time.
327+
LMIC.globalDutyAvail = tNow + State.V1.globalAvail;
293328

294-
// set the Rx2 frequency
295-
LMIC.dn2Freq = State.V1.Rx2Frequency;
329+
// set the Rx2 frequency
330+
LMIC.dn2Freq = State.V1.Rx2Frequency;
296331

297332
#if !defined(DISABLE_PING)
298-
// set the ping frequency
299-
LMIC.ping.freq = State.V1.PingFrequency;
333+
// set the ping frequency
334+
LMIC.ping.freq = State.V1.PingFrequency;
300335
#endif
301336

302-
LMIC.adrAckReq = State.V1.LinkIntegrity;
303-
LMIC.adrTxPow = State.V1.TxPower;
304-
LMIC.upRepeat = State.V1.Redundancy;
305-
LMIC.globalDutyRate = State.V1.DutyCycle;
306-
LMIC.rx1DrOffset = State.V1.Rx1DRoffset;
307-
LMIC.dn2Dr = State.V1.Rx2DataRate;
308-
LMIC.rxDelay = State.V1.RxDelay;
337+
LMIC.adrAckReq = State.V1.LinkIntegrity;
338+
LMIC.adrTxPow = State.V1.TxPower;
339+
LMIC.upRepeat = State.V1.Redundancy;
340+
LMIC.globalDutyRate = State.V1.DutyCycle;
341+
LMIC.rx1DrOffset = State.V1.Rx1DRoffset;
342+
LMIC.dn2Dr = State.V1.Rx2DataRate;
343+
LMIC.rxDelay = State.V1.RxDelay;
309344

310345
#if LMIC_ENABLE_TxParamSetupReq
311-
LMIC.txParam = State.V1.TxParam;
346+
LMIC.txParam = State.V1.TxParam;
312347
#endif
313348
#if !defined(DISABLE_BEACONS)
314-
LMIC.bcnChnl = State.V1.BeaconChannel;
349+
LMIC.bcnChnl = State.V1.BeaconChannel;
315350
#endif
316351
#if !defined(DISABLE_PING)
317-
LMIC.ping.dr = State.V1.PingDr;
352+
LMIC.ping.dr = State.V1.PingDr;
318353
#endif
319-
LMIC.dn2Ans = State.V1.MacRxParamAns;
320-
LMIC.macDlChannelAns = State.V1.MacDlChannelAns;
321-
LMIC.macRxTimingSetupAns = State.V1.MacRxTimingSetupAns;
354+
LMIC.dn2Ans = State.V1.MacRxParamAns;
355+
LMIC.macDlChannelAns = State.V1.MacDlChannelAns;
356+
LMIC.macRxTimingSetupAns = State.V1.MacRxTimingSetupAns;
322357

323358
#if CFG_LMIC_EU_like
324-
// don't turn off bits: user can't fool us here.
325-
// we can get the immutable channels from the
326-
// channelMap value after reset.
327-
auto const resetMap = LMIC.channelMap;
328-
auto const & euLike = State.V1.Channels.EUlike;
329-
LMIC.channelMap |= euLike.ChannelMap;
359+
// don't turn off bits: user can't fool us here.
360+
// we can get the immutable channels from the
361+
// channelMap value after reset.
362+
auto const resetMap = LMIC.channelMap;
363+
auto const & euLike = State.V1.Channels.EUlike;
364+
LMIC.channelMap |= euLike.ChannelMap;
330365
#if ARDUINO_LMIC_VERSION_COMPARE_GE(ARDUINO_LMIC_VERSION, ARDUINO_LMIC_VERSION_CALC(3,99,0,1))
331-
LMIC.channelShuffleMap = euLike.ChannelShuffleMap;
366+
LMIC.channelShuffleMap = euLike.ChannelShuffleMap;
332367
#endif
333-
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch)
368+
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch)
369+
{
370+
if ((resetMap & (decltype(resetMap)(1) << ch)) == 0)
334371
{
335-
if ((resetMap & (decltype(resetMap)(1) << ch)) == 0)
336-
{
337-
// copy data -- note that the saved band number is encoded
338-
LMIC_setupChannel(
339-
ch,
340-
euLike.getFrequency(euLike.UplinkFreq, ch),
341-
euLike.ChannelDrMap[ch],
342-
euLike.getBand(ch)
343-
);
372+
// copy data -- note that the saved band number is encoded
373+
LMIC_setupChannel(
374+
ch,
375+
euLike.getFrequency(euLike.UplinkFreq, ch),
376+
euLike.ChannelDrMap[ch],
377+
euLike.getBand(ch)
378+
);
344379
#if !defined(DISABLE_MCMD_DlChannelReq)
345-
LMIC.channelDlFreq[ch] = euLike.getFrequency(euLike.DownlinkFreq, ch);
380+
LMIC.channelDlFreq[ch] = euLike.getFrequency(euLike.DownlinkFreq, ch);
346381
#endif
347-
}
348382
}
383+
}
349384

350-
for (unsigned band = 0; band < MAX_BANDS; ++band)
351-
{
352-
LMIC.bands[band].txcap = euLike.Bands[band].txDutyDenom;
353-
LMIC.bands[band].txpow = euLike.Bands[band].txPower;
354-
LMIC.bands[band].lastchnl = euLike.Bands[band].lastChannel;
355-
// Heuristic; we don't know how long has passed since we saved
356-
// this, because we don't currently have GPS time available.
357-
// Conservatively reserve time from now.
358-
LMIC.bands[band].avail = tNow + euLike.Bands[band].ostimeAvail;
359-
}
385+
for (unsigned band = 0; band < MAX_BANDS; ++band)
386+
{
387+
LMIC.bands[band].txcap = euLike.Bands[band].txDutyDenom;
388+
LMIC.bands[band].txpow = euLike.Bands[band].txPower;
389+
LMIC.bands[band].lastchnl = euLike.Bands[band].lastChannel;
390+
// Heuristic; we don't know how long has passed since we saved
391+
// this, because we don't currently have GPS time available.
392+
// Conservatively reserve time from now.
393+
LMIC.bands[band].avail = tNow + euLike.Bands[band].ostimeAvail;
394+
}
360395

361396
#elif CFG_LMIC_US_like
362397
# if ARDUINO_LMIC_VERSION_COMPARE_GE(ARDUINO_LMIC_VERSION, ARDUINO_LMIC_VERSION_CALC(3,99,0,1))
363-
static_assert(sizeof(LMIC.channelShuffleMap) == sizeof(State.V1.Channels.USlike.ChannelShuffleMap),
364-
"shuffle map doesn't match");
365-
// copy the shuffle map bits
366-
memcpy(LMIC.channelShuffleMap, State.V1.Channels.USlike.ChannelShuffleMap, sizeof(LMIC.channelShuffleMap));
398+
static_assert(sizeof(LMIC.channelShuffleMap) == sizeof(State.V1.Channels.USlike.ChannelShuffleMap),
399+
"shuffle map doesn't match");
400+
// copy the shuffle map bits
401+
memcpy(LMIC.channelShuffleMap, State.V1.Channels.USlike.ChannelShuffleMap, sizeof(LMIC.channelShuffleMap));
367402
# endif
368-
// copy the enabled states
369-
for (unsigned ch = 0; ch < State.V1.Channels.USlike.nCh; ++ch)
370-
{
371-
const bool state = State.V1.Channels.USlike.isEnabled(ch);
372-
373-
if (state)
374-
LMIC_enableChannel(ch);
375-
else
376-
LMIC_disableChannel(ch);
377-
}
378-
#endif
379-
380-
return true;
381-
}
382-
else
403+
// copy the enabled states
404+
for (unsigned ch = 0; ch < State.V1.Channels.USlike.nCh; ++ch)
383405
{
384-
return false;
406+
const bool state = State.V1.Channels.USlike.isEnabled(ch);
407+
408+
if (state)
409+
LMIC_enableChannel(ch);
410+
else
411+
LMIC_disableChannel(ch);
385412
}
413+
#endif
386414
}
387415

388416
#undef FUNCTION

0 commit comments

Comments
 (0)