mcci-catena / arduino-lorawan

User-friendly library for using arduino-lmic with The Things Network and other LoRaWAN® networks
MIT License
274 stars 54 forks source link

Getting state save/restore to work? NetSaveSessionInfo/NetSaveSessionState/NetGetSessionState/GetAbpProvisioningInfo/GetProvisioningStyle #189

Open ObviousInRetrospect opened 2 years ago

ObviousInRetrospect commented 2 years ago

I'm not having much luck getting session save/restore to work.

Multiple examples show that you need to implement NetSaveSessionInfo/NetSaveSessionState/NetGetSessionState.

Based on issue #165 I also added GetAbpProvisioningInfo. When that wasn't actually being called I overrode GetProvisioningStyle to check for a saved session and return ProvisioningStyle::kABP.

At the moment I am using EEPROM as a placeholder. I know it will have endurance problems and once I get it working will switch to storing it in sram on a 2nd mcu acting as an i2c slave (that also acts as a watchdog).

The SessionState gets stored starting at EEPROM address 0. The SessionInfo gets stored starting at EEPROM address sizeof(SessionState):

bool
cMyLoRaWAN::GetOtaaProvisioningInfo(
    OtaaProvisioningInfo *pInfo
    ) {
    Serial.println("GetOtaaProvisioningInfo");
    memcpy(pInfo->DevEUI, DEVEUI,8);
    memcpy(pInfo->AppEUI, APPEUI,8);
    memcpy(pInfo->AppKey, APPKEY,16);
    return true;
}
bool cMyLoRaWAN::GetAbpProvisioningInfo(
                        Arduino_LoRaWAN::AbpProvisioningInfo *pInfo
                        ){
    SessionInfo si;
    SessionState ss;
    Serial.println("GetAbpProvisioningInfo:");
    Serial.print("Loading SessionInfo:");
    uint8_t * pb = (uint8_t *) &si;
    for(int i=0; i<sizeof(SessionInfo); i++){
      pb[i]=EEPROM.read(sizeof(SessionState)+i);
      printHex2(pb[i]);
    }
    Serial.println("");
    if(si.Header.Tag != kSessionInfoTag_V2){
      Serial.print("SessionInfo from EEPROM has tag: ");
      Serial.print(si.Header.Tag);
      Serial.println(" aborting restore.");
      return(false);      
    }
    this->NetGetSessionState(ss);
    if(ss.Header.Tag != kSessionStateTag_V1){
      Serial.print("SessionState from EEPROM has tag: ");
      Serial.print(si.Header.Tag);
      Serial.println(" aborting restore.");
      return(false);      
    }
    pInfo->NetID = si.V2.NetID;
    pInfo->DevAddr = si.V2.DevAddr;
    memcpy(pInfo->NwkSKey, si.V2.NwkSKey, 16);
    memcpy(pInfo->AppSKey, si.V2.AppSKey, 16);    
    pInfo->FCntUp=ss.V1.FCntUp;
    pInfo->FCntDown=ss.V1.FCntDown;
    return true;
}
void
cMyLoRaWAN::NetSaveSessionInfo(
    const SessionInfo &Info,
    const uint8_t *pExtraInfo,
    size_t nExtraInfo
    ) {
    // save Info somewhere.
    const uint8_t * pb = (uint8_t *) (&Info);   
    Serial.print("NSSI: "); 
    for(int i=0; i<sizeof(SessionInfo); i++){
      EEPROM.write(sizeof(SessionState)+i, pb[i]);
      printHex2(pb[i]);
    }
    Serial.print(" exI: "); 
    for(int i=0; i<nExtraInfo; i++){
      EEPROM.write(sizeof(SessionState)+sizeof(SessionInfo)+i, pExtraInfo[i]);
      printHex2(pExtraInfo[i]);
    }
    Serial.println();
    EEPROM.commit();
    Serial.print("Saved SI ");
    Serial.print(sizeof(SessionInfo) + nExtraInfo);
    Serial.println(" Bytes.");
}
void
cMyLoRaWAN::NetSaveSessionState(const SessionState &State) {
    // save State somwwhere. Note that it's often the same;
    // often only the frame counters change.
    Serial.print("NSSS: ");
    const uint8_t * pb = (uint8_t *) (&State);    
    for(int i=0; i<sizeof(SessionState); i++){
      EEPROM.write(i, pb[i]);
      printHex2(pb[i]);
    }
    Serial.println("");
    Serial.print("Saved SS ");
    Serial.print(sizeof(SessionState));
    Serial.println(" Bytes.");
    EEPROM.commit();
}
Arduino_LoRaWAN::ProvisioningStyle cMyLoRaWAN::GetProvisioningStyle(void){
  uint8_t tag = EEPROM.read(sizeof(SessionState)+0);
  if(tag == kSessionInfoTag_V2){
    Serial.println("Have a SessionInfo, ABP");    
    return Arduino_LoRaWAN::ProvisioningStyle::kABP;
  }
  Serial.println("No SessionInfo, OTAA");
  return Arduino_LoRaWAN::ProvisioningStyle::kOTAA;
}
bool
cMyLoRaWAN::NetGetSessionState(SessionState &State) {
  Serial.print("NGSS: ");
    // either fetch SessionState from somewhere and return true or...
    uint8_t * pb = (uint8_t *) (&State); 
    for(int i=0; i<sizeof(SessionState); i++){
      pb[i]=EEPROM.read(i);
      printHex2(pb[i]);
    }
    Serial.println("");
    return true;
}

Here is the output from the first boot with the EEPROM cleared:

eeprom cleared
BOOTING....
NGSS: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
No SessionInfo, OTAA
No SessionInfo, OTAA
Packet queued
NSSS: 01D802000000000000000000000000004D19FBFFA0700837A0700837000080FF14000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
NSSI: 02340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 exI: 
Saved SI 52 Bytes.
NSSS: 01D8020000000000000000000000000062FCFAFFA0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
331357: EV_JOINING
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
NSSI: 023400004865320026000048F22C117AD48428A5691BCF974A225B60AE076996F3F9DB1ADE315B7B5D647075301DFB3F00000000 exI: 
Saved SI 52 Bytes.
NSSS: 01D8020000000000000000000000000029B8F5FFA0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
682414: EV_JOINED
netid: 3302728
devaddr: 48000026
AppSKey: AE-07-69-96-F3-F9-DB-1A-DE-31-5B-7B-5D-64-70-75
NwkSKey: F2-2C-11-7A-D4-84-28-A5-69-1B-CF-97-4A-22-5B-60
NSSS: 01D802000000000000000000000000006B95F5FFA0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
686013: EV_TXCOMPLETE (includes waiting for RX windows)
5302 ms: TX: ch=8 rps=0x04 (SF10 BW125 CR 4/5 Crc IH=0)
Packet queued
NSSS: 01D80201010000000100000000000000127A0000A0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
NSSS: 01D8020101000000010000000000000078630000A0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
4523406: EV_TXCOMPLETE (includes waiting for RX windows)
NSSS: 01D80201020000000100000000000000117A0000A0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
4687540: EV_TXCOMPLETE (includes waiting for RX windows)
70977 ms: TX: ch=13 rps=0x03 (SF9 BW125 CR 4/5 Crc IH=0)
72727 ms: TX: ch=15 rps=0x03 (SF9 BW125 CR 4/5 Crc IH=0)

Here is the reboot,

01234BOOTING....
NGSS: 01D80201020000000100000000000000117A0000A0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Have a SessionInfo, ABP
Have a SessionInfo, ABP
GetAbpProvisioningInfo:
Loading SessionInfo:023400004865320026000048F22C117AD48428A5691BCF974A225B60AE076996F3F9DB1ADE315B7B5D647075301DFB3F00000000
NGSS: 01D80201020000000100000000000000117A0000A0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Packet queued
NSSS: 01D802000000000000000000000000005A0CFBFFA0700837A0700837000080FF14000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
NSSI: 02340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 exI: 
Saved SI 52 Bytes.
NSSS: 01D802000000000000000000000000009DE3FAFFA0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
337701: EV_JOINING
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
GetOtaaProvisioningInfo
NSSI: 023400004865320027000048CE118DD36177D3F1517C03781D38C79098B2F48C0DD0B9D80183B7C84E1707AB901EFB3FD702FC3F exI: 
Saved SI 52 Bytes.
NSSS: 01D80200000000000000000000000000ED93F5FFA0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
685906: EV_JOINED
netid: 3302728
devaddr: 48000027
AppSKey: 98-B2-F4-8C-0D-D0-B9-D8-01-83-B7-C8-4E-17-07-AB
NwkSKey: CE-11-8D-D3-61-77-D3-F1-51-7C-03-78-1D-38-C7-90
NSSS: 01D80200000000000000000000000000C887F5FFA0700837A0700837000080FF15000000080100000A000000011600FF000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Saved SS 216 Bytes.
689500: EV_TXCOMPLETE (includes waiting for RX windows)
5404 ms: TX: ch=8 rps=0x04 (SF10 BW125 CR 4/5 Crc IH=0)

You can see it does a rejoin and gets a new AppSKey/NwkSKey

What am I doing wrong? Any chance a fixed version of this could be added as an example?

ObviousInRetrospect commented 2 years ago

Is there any other information that would be helpful? Thanks.

ObviousInRetrospect commented 2 years ago

in case anyone else is stuck on this:

while I still can't get the convoluted NetGetSessionState flow to work, the underlying arduino-lmic library has a far simpler to use set of functions that work fine.

The following example code works (and will wear out eeprom if used as below)


typedef struct{
  uint32_t seqnoUp;
  uint32_t netid;
  devaddr_t devaddr;
  uint8_t nwkKey[16];
  uint8_t artKey[16];
} eep_sstate_t;

void store_joininfo(u4_t netid, devaddr_t devaddr, uint8_t *nwkKey, uint8_t *artKey){
  eep_sstate_t st;
  st.seqnoUp=LMIC_getSeqnoUp();
  st.netid=netid;
  st.devaddr=devaddr;
  memcpy(st.nwkKey,nwkKey,16);
  memcpy(st.artKey,artKey,16);
  uint8_t *r = (uint8_t*)&st;
  for(int i=0; i<sizeof(eep_sstate_t); i++){
    EEPROM.write(i,r[i]);
  }
  EEPROM.commit();
}

bool eep_rejoin(){
  eep_sstate_t st;
  uint8_t *r = (uint8_t*)&st;
  for(int i=0; i<sizeof(eep_sstate_t); i++){
    r[i]=EEPROM.read(i);
  }
  if(st.netid == 0xFFFFFFFF || st.netid == 0x0){
    Serial.println("no session in EEPROM");
    return false;
  }
  LMIC_reset();
  LMIC_setSession(st.netid, st.devaddr, st.nwkKey, st.artKey);
  LMIC_setSeqnoUp(st.seqnoUp);
  return(true);
}

and then in onEvent:


and then in onEvent:

case EV_JOINED:
...
    store_joininfo(netid,devaddr,nwkKey,artKey);

case EV_TXCOMPLETE:
...
            uint32_t su = LMIC_getSeqnoUp();
            uint8_t *sup = (uint8_t*)&su;
            EEPROM.write(0,sup[0]);
            EEPROM.write(1,sup[1]);
            EEPROM.write(2,sup[2]);
            EEPROM.write(3,sup[3]);
            EEPROM.commit();

and finally call eep_rejoin(); at startup.

Also, the state this way is 44 bytes instead of far more.