Correct LoRaWAN timing

pull/46/head
Pawel Jalocha 2021-12-07 10:26:35 +00:00
rodzic 9837f79c88
commit c2380d81be
3 zmienionych plików z 63 dodań i 48 usunięć

Wyświetl plik

@ -23,8 +23,8 @@ class LoRaWANnode
uint32_t JoinNonce; // from Join-Accept: unique must not be reused
uint32_t HomeNetID; // from Join-Accept: Home Network ID
uint32_t DevAddr; // from Join-Accept: Device Address
uint8_t DLsetting; // from Join-Accept: DownLink configuration: OptNeg | RX1DRoffset | RX2 data rate
uint8_t RxDelay; // from Join-Accept:
uint8_t DLsetting; // from Join-Accept: DownLink configuration: OptNeg:1 | RX1 data rate offset:3 | RX2 data rate:4
uint8_t RxDelay; // from Join-Accept: RFU:4 | Del:4 Del=1..15s for the RX1, RX2 delay is Del+1
uint8_t State; // 0:disconencted, 1:join-request sent, 2:join-accept received, 3:uplink-packet sent
uint8_t Chan; // [0..7] Current channel being used
uint32_t UpCount; // [seq] Uplink frame counter: reset when joining the network
@ -175,24 +175,26 @@ class LoRaWANnode
{ int Len=getDataPacket(Packet, Data, DataLen, Port, Confirm); *Pkt = Packet; return Len; }
int procRxData(const RFM_LoRa_RxPacket &RxPacket)
{ int Ret=procRxData(RxPacket.Byte, RxPacket.Len); if(Ret<0) return Ret;
RxSNR += (RxPacket.SNR-RxSNR+1)/2;
{ int Ret = procRxData(RxPacket.Byte, RxPacket.Len); if(Ret<0) return Ret;
RxSNR += (RxPacket.SNR-RxSNR+1)/2; // if good packet then update the signal statistics
RxRSSI += (RxPacket.RSSI-RxRSSI+1)/2;
return Ret; }
int procRxData(const uint8_t *PktData, int PktLen)
{ if(PktLen<12) return -1;
uint8_t Type = PktData[0]>>5; if(Type!=3 && Type!=5) return -1;
uint32_t Addr=readInt<uint32_t>(PktData+1, 4);
if(Addr!=DevAddr) return 0;
uint8_t Ctrl = PktData[5]; // Frame control: ADR | RFU | ACK | FPending | FOptLen[4]
uint32_t Count=readInt<uint32_t>(PktData+6, 2);
int16_t CountDiff = Count-DnCount; //
if(CountDiff<=0) return -1; // attempt to reuse the counter: drop this packet
uint8_t Type = PktData[0]>>5; if(Type!=3 && Type!=5) return -1; // Frame Type: 3=unconfirmed data downlink, 5=confirmed data downlink
uint32_t Addr=readInt<uint32_t>(PktData+1, 4); // device address
if(Addr!=DevAddr) return 0; // check if packet is for us (it could be for somebody else)
uint8_t Ctrl = PktData[5]; // Frame Control: ADR | RFU | ACK | FPending | FOptLen[4]
uint32_t Count = readInt<uint32_t>(PktData+6, 2); // download counter
int16_t CountDiff = Count-DnCount; // how many we have missed ?
if(CountDiff<=0) return -1; // attempt to reuse the counter: drop this packet
uint32_t MIC=0;
LoRaMacComputeMic(PktData, PktLen-4, NetSesKey, Addr, 0x01, Count, &MIC);
if(memcmp(PktData+PktLen-4, &MIC, 4)) return -1; // give up if MIC does not match
uint8_t DataOfs = 8 + (Ctrl&0x0F); // where the port byte should be
uint8_t OptLen = Ctrl&0x0F; // Options: how many bytes
uint8_t DataOfs = 8 + OptLen; // where the port byte should be
if(OptLen) procRxOpt(PktData+8, OptLen); // process the options (these are not encrypted)
uint8_t DataLen = PktLen-DataOfs-4; // number of bytes of the user data field
if(DataLen) // if non-zero
{ Packet[0] = PktData[DataOfs]; // copy port number
@ -208,8 +210,20 @@ class LoRaWANnode
if(Type==5) TxACK=1; // if ACK requested
RxPend = Ctrl&0x10; // is there more data pending to be received on next round ?
State=2;
// if(DataLen==0)
// { Packet[0]=0x00; DataLen++; // copy MAC commands to user buffer for debug
// for(uint8_t Idx=0; Idx<OptLen; Idx++)
// { Packet[DataLen++] = PktData[8+Idx]; }
// }
return DataLen; }
void procRxOpt(const uint8_t *Opt, uint8_t Len) // process the options
{ }
// { Format_String(CONS_UART_Write, "LoRaWAN Opt: ");
// for(uint8_t Idx=0; Idx<Len; Idx++)
// Format_Hex(CONS_UART_Write, Opt[Idx]);
// Format_String(CONS_UART_Write, "\n"); }
#ifdef WITH_ESP32
esp_err_t WriteToNVS(const char *Name="LoRaWAN", const char *NameSpace="TRACKER")
{ nvs_handle Handle;

Wyświetl plik

@ -410,19 +410,20 @@ extern "C"
if(WANdev.State==1 || WANdev.State==3) // if State indicates we are waiting for the response
{ if(WAN_RespLeft<=5) WANdev.State--; // if time below 5 ticks we have not enough time
else if(WAN_RespLeft<200) { WANrx=1; } // if more than 200ms then we can't wait this long now
// xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
// Format_UnsDec(CONS_UART_Write, xTaskGetTickCount(), 4, 3);
// Format_String(CONS_UART_Write, "s LoRaWAN Rx: ");
// Format_SignDec(CONS_UART_Write, WAN_RespLeft);
// Format_String(CONS_UART_Write, "ms\n");
// xSemaphoreGive(CONS_Mutex);
if(WANrx==0 && WAN_RespLeft<=5)
{ xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_UnsDec(CONS_UART_Write, xTaskGetTickCount(), 4, 3);
Format_String(CONS_UART_Write, "s LoRaWAN missed Rx: ");
Format_SignDec(CONS_UART_Write, WAN_RespLeft);
Format_String(CONS_UART_Write, "ms\n");
xSemaphoreGive(CONS_Mutex); }
}
if(WANrx) // if reception expected from WAN
{ int RxLen=0;
TRX.setModeStandby(); // TRX to standby
TRX.setModeStandby(); // TRX to standby
TRX.setLoRa(); // switch to LoRa mode (through sleep)
TRX.setModeLoRaStandby(); // TRX in standby
TRX.setModeLoRaStandby(); // TRX in LoRa (not FSK) standby
SetFreqPlanWAN(); // WAN frequency plan
TRX.WAN_Configure(); // LoRa for WAN config.
TRX.setChannel(WANdev.Chan); // set the channel
@ -432,7 +433,7 @@ extern "C"
for( ; Wait>0; Wait--)
{ vTaskDelay(1);
if(TRX.readIRQ()) break; } // IRQ signals packet reception
if(Wait)
if(Wait) // if no timeout thus a packet has been received.
{ TRX.LoRa_ReceivePacket(WAN_RxPacket);
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_UnsDec(CONS_UART_Write, xTaskGetTickCount(), 4, 3);
@ -442,42 +443,42 @@ extern "C"
Format_UnsDec(CONS_UART_Write, (unsigned)Wait);
Format_String(CONS_UART_Write, "ms\n");
xSemaphoreGive(CONS_Mutex);
if(WANdev.State==1) WANdev.procJoinAccept(WAN_RxPacket); // if join-request state then expect a join-accept packet
if(WANdev.State==1) WANdev.procJoinAccept(WAN_RxPacket); // if join-request state then expect a join-accept packet
else if(WANdev.State==3) RxLen=WANdev.procRxData(WAN_RxPacket); // if data send then respect ACK and/or downlink data packet
}
else WANdev.State--;
TRX.setFSK(); // back to FSK
SetFreqPlanOGN(); // OGN frequency plan
TRX.OGN_Configure(0, OGN_SYNC); // OGN config
else WANdev.State--; // if no packet received then retreat the State
TRX.setFSK(); // back to FSK
SetFreqPlanOGN(); // OGN frequency plan
TRX.OGN_Configure(0, OGN_SYNC); // OGN config
SetRxChannel();
TRX.setModeRX(); // switch to receive mode
TRX.setModeRX(); // switch to receive mode
TRX.ClearIrqFlags();
WANdev.WriteToNVS(); // store new WAN state in flash
if(RxLen>0) // if Downlink data received
WANdev.WriteToNVS(); // store new WAN state in flash
if(RxLen>0) // if Downlink data received
{ xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_String(CONS_UART_Write, "LoRaWAN Msg: ");
// Format_UnsDec(CONS_UART_Write, (uint16_t)RxLen);
// Format_String(CONS_UART_Write, "B");
for(int Idx=0; Idx<RxLen; Idx++)
{ Format_Hex(CONS_UART_Write, WANdev.Packet[Idx]); }
{ Format_Hex(CONS_UART_Write, WANdev.Packet[Idx]); } //
Format_String(CONS_UART_Write, "\n");
xSemaphoreGive(CONS_Mutex); }
}
else
else // if no WAN reception expected or possible
#else // WITH_LORAWAN
// if(TimeSync_msTime()<260);
{ uint32_t RxRssiSum=0; uint16_t RxRssiCount=0; // measure the average RSSI for lower frequency
{ uint32_t RxRssiSum=0; uint16_t RxRssiCount=0; // measure the average RSSI for lower frequency
do
{ ReceivePacket(); // keep checking for received packets
{ ReceivePacket(); // keep checking for received packets
#ifdef WITH_RFM69
TRX.TriggerRSSI();
#endif
vTaskDelay(1);
uint8_t RxRSSI=TRX.ReadRSSI(); // measure the channel noise level
uint8_t RxRSSI=TRX.ReadRSSI(); // measure the channel noise level
RX_Random = (RX_Random<<1) | (RxRSSI&1);
RxRssiSum+=RxRSSI; RxRssiCount++;
} while(TimeSync_msTime()<270); // until 300ms from the PPS
RX_RSSI.Process(RxRssiSum/RxRssiCount); // [-0.5dBm] average noise on channel
} while(TimeSync_msTime()<270); // until 300ms from the PPS
RX_RSSI.Process(RxRssiSum/RxRssiCount); // [-0.5dBm] average noise on channel
#ifdef DEBUG_PRINT
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_String(CONS_UART_Write, "RSSI: ");
@ -619,7 +620,7 @@ extern "C"
if(WAN_BackOff) WAN_BackOff--;
else if(Parameters.TxPower!=(-32)) // decide to transmit in this slot
{ if(WANdev.State==0 || WANdev.State==2) //
{ WANtx=1; SlotEnd=1200; }
{ WANtx=1; SlotEnd=1220; }
}
TimeSlot(TxChan, SlotEnd-TimeSync_msTime(), TxPktData1, TRX.averRSSI, 0, TxTime);
#else
@ -697,7 +698,7 @@ extern "C"
{ TxPktLen=WANdev.getDataPacket(&TxPacket, PktData+4, 16, 1, ((RX_Random>>16)&0xF)==0x8 ); }
else
{ TxPktLen=WANdev.getDataPacket(&TxPacket, PktData, 20, 1, ((RX_Random>>16)&0xF)==0x8 ); }
TRX.LoRa_SendPacket(TxPacket, TxPktLen); RespDelay=1000;
TRX.LoRa_SendPacket(TxPacket, TxPktLen); RespDelay = WANdev.RxDelay&0x0F; if(RespDelay<1) RespDelay=1; RespDelay*=1000;
WAN_BackOff=50+(RX_Random%21); XorShift32(RX_Random); }
}
if(RespDelay)
@ -706,7 +707,7 @@ extern "C"
{ vTaskDelay(1); if(!TRX.isModeLoRaTX()) break; }
// uint8_t Mode=TRX.ReadMode();
// if(Mode!=RF_OPMODE_LORA_TX) break; }
WAN_RespTick=xTaskGetTickCount()+RespDelay; // when to expect the response: 5sec after the end of Join-Request packet
WAN_RespTick=xTaskGetTickCount()+RespDelay; // when to expect the response after the end of transmitted packet
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_UnsDec(CONS_UART_Write, xTaskGetTickCount(), 4, 3);
Format_String(CONS_UART_Write, "s LoRaWAN Tx: ");

Wyświetl plik

@ -243,12 +243,12 @@ SX1262 setup calls
#ifdef WITH_SX1262
#include "sx1262.h"
#define RF_IRQ_PacketSent 0x0001 // packet transmission was completed
#define RF_IRQ_PayloadReady 0x0002 //
#define RF_IRQ_PreambleDetect 0x0004 //
#define RF_IRQ_SyncAddrMatch 0x0008 //
#define RF_IRQ_CrcErr 0x0040 //
#define RF_IRQ_Timeout 0x0200 //
// #define RF_IRQ_PacketSent 0x0001 // packet transmission was completed
// #define RF_IRQ_PayloadReady 0x0002 //
// #define RF_IRQ_PreambleDetect 0x0004 //
// #define RF_IRQ_SyncAddrMatch 0x0008 //
// #define RF_IRQ_CrcErr 0x0040 //
// #define RF_IRQ_Timeout 0x0200 //
#endif
@ -738,7 +738,6 @@ class RFM_TRX
void LoRa_Configure(RFM_LoRa_Config CFG, uint8_t MaxSize=64)
{ setChannel(0);
setDioMode(IRQ_TXDONE | IRQ_RXDONE);
uint8_t Param[8];
Param[0] = CFG.SF; // Spreading Factor
Param[1] = CFG.BW-3; // work only for 62.5/125/256/512kHz
@ -752,13 +751,13 @@ class RFM_TRX
Param[4] = CFG.CRC; // check or not CRC
Param[5] = CFG.InvIQ; // common flag for Tx/Rx
Cmd_Write(CMD_SETPACKETPARAMS, Param, 6); // 0x8C, PacketParam
setDioMode( /* IRQ_TXDONE | */ IRQ_RXDONE);
Param[0] = (CFG.SYNC&0xF0) | 0x04;
Param[1] = (CFG.SYNC<<4) | 0x04;
Regs_Write(REG_LORASYNCWORD, Param, 2); }
void OGN_Configure(int16_t Channel, const uint8_t *SyncData)
{ setChannel(Channel);
setDioMode(IRQ_TXDONE | IRQ_RXDONE);
uint8_t Param[12];
Pack3bytes(Param, 10240); // data bitrate = 32*Xtal/100e3 for OGN 100kbps
Param[3] = 0x09; // 0x00:no filter, 0x08:BT=0.3, 0x09:BT=0.5, 0x0A:BT=0.7, 0x0B:BT=1.0
@ -775,11 +774,11 @@ class RFM_TRX
Param[7] = 0x01; // no CRC
Param[8] = 0x00; // no whitening
Cmd_Write(CMD_SETPACKETPARAMS, Param, 9); // 0x8C, PacketParam
setDioMode(/* IRQ_TXDONE | */ IRQ_RXDONE);
Regs_Write(REG_SYNCWORD0, SyncData, 8); } // Write the SYNC word
void PAW_Configure(const uint8_t *Sync)
{ setFrequency(869525000);
setDioMode(IRQ_TXDONE | IRQ_RXDONE);
uint8_t Param[12];
Pack3bytes(Param, 26667); // data bitrate = 32*Xtal/38.4e3 for PAW 38.4kbps
Param[3] = 0x09; // 0x00:no filter, 0x08:BT=0.3, 0x09:BT=0.5, 0x0A:BT=0.7, 0x0B:BT=1.0
@ -796,6 +795,7 @@ class RFM_TRX
Param[7] = 0x01; // no CRC
Param[8] = 0x00; // no whitening
Cmd_Write(CMD_SETPACKETPARAMS, Param, 9); // 0x8C, PacketParam
setDioMode( /* IRQ_TXDONE | */ IRQ_RXDONE);
Regs_Write(REG_SYNCWORD0, Sync, 8); } // Write the SYNC word
void ClearIrqFlags(uint16_t Mask=IRQ_ALL) { uint8_t Data[2]; Data[0]=Mask>>8; Data[1]=Mask; Cmd_Write(CMD_CLEARIRQSTATUS, Data, 2); }