esp32-ogn-tracker/main/rf.cpp

567 wiersze
28 KiB
C++

#include "hal.h"
#include "rf.h"
#include "timesync.h"
#include "lowpass2.h"
#ifdef WITH_LORAWAN
#include "lorawan.h"
#endif
// ===============================================================================================
// OGNv1 SYNC: 0x0AF3656C encoded in Manchester
static const uint8_t OGN1_SYNC[8] = { 0xAA, 0x66, 0x55, 0xA5, 0x96, 0x99, 0x96, 0x5A };
// OGNv2 SYNC: 0xF56D3738 encoded in Machester
static const uint8_t OGN2_SYNC[8] = { 0x55, 0x99, 0x96, 0x59, 0xA5, 0x95, 0xA5, 0x6A };
static const uint8_t PAW_SYNC [8] = { 0xB4, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x18, 0x71 };
#ifdef WITH_OGN1
static const uint8_t *OGN_SYNC = OGN1_SYNC;
#endif
#ifdef WITH_OGN2
static const uint8_t *OGN_SYNC = OGN2_SYNC;
#endif
RFM_TRX TRX; // radio transceiver
// uint8_t RX_AverRSSI; // [-0.5dBm] average RSSI
// int8_t RF_Temp; // [degC] temperature of the RF chip: uncalibrated
static uint32_t RF_SlotTime; // [sec] UTC time which belongs to the current time slot (0.3sec late by GPS UTC)
FreqPlan RF_FreqPlan; // frequency hopping pattern calculator
FIFO<RFM_FSK_RxPktData, 16> RF_RxFIFO; // buffer for received packets
FIFO<OGN_TxPacket<OGN_Packet>, 4> RF_TxFIFO; // buffer for transmitted packets
#ifdef WITH_FANET
FIFO<FANET_RxPacket, 8> FNT_RxFIFO;
FIFO<FANET_Packet, 4> FNT_TxFIFO;
#endif
uint16_t TX_Credit =0; // counts transmitted packets vs. time to avoid using more than 1% of the time
uint8_t RX_OGN_Packets=0; // [packets] counts received packets
static LowPass2<uint32_t, 4,2,4> RX_RSSI; // low pass filter to average the RX noise
static Delay<uint8_t, 64> RX_OGN_CountDelay;
uint16_t RX_OGN_Count64=0; // counts received packets for the last 64 seconds
uint32_t RX_Random=0x12345678; // Random number from LSB of RSSI readouts
// void XorShift32(uint32_t &Seed) // simple random number generator
// { Seed ^= Seed << 13;
// Seed ^= Seed >> 17;
// Seed ^= Seed << 5; }
static uint8_t RX_Channel=0; // (hopping) channel currently being received
static void SetTxChannel(uint8_t TxChan=RX_Channel) // default channel to transmit is same as the receive channel
{
#ifdef WITH_RFM69
TRX.WriteTxPower(Parameters.getTxPower(), Parameters.isTxTypeHW()); // set TX for transmission
#endif
#if defined(WITH_RFM95) || defined(WITH_SX1272)
TRX.WriteTxPower(Parameters.getTxPower()); // set TX for transmission
#endif
TRX.setChannel(TxChan&0x7F);
TRX.FSK_WriteSYNC(8, 7, OGN_SYNC); } // Full SYNC for TX
static void SetRxChannel(uint8_t RxChan=RX_Channel)
{ TRX.WriteTxPowerMin(); // setup for RX
TRX.setChannel(RxChan&0x7F);
TRX.FSK_WriteSYNC(7, 7, OGN_SYNC); } // Shorter SYNC for RX
static uint8_t ReceivePacket(void) // see if a packet has arrived
{ if(!TRX.DIO0_isOn()) return 0; // DIO0 line HIGH signals a new packet has arrived
#ifdef WITH_LED_RX
LED_RX_Flash(20);
#endif
uint8_t RxRSSI = TRX.ReadRSSI(); // signal strength for the received packet
RX_Random = (RX_Random<<1) | (RxRSSI&1); // use the lowest bit to add entropy
RFM_FSK_RxPktData *RxPkt = RF_RxFIFO.getWrite();
RxPkt->Time = RF_SlotTime; // store reception time
RxPkt->msTime = TimeSync_msTime(); if(RxPkt->msTime<200) RxPkt->msTime+=1000;
RxPkt->Channel = RX_Channel; // store reception channel
RxPkt->RSSI = RxRSSI; // store signal strength
TRX.ReadPacketOGN(RxPkt->Data, RxPkt->Err); // get the packet data from the FIFO
// PktData.Print(); // for debug
RF_RxFIFO.Write(); // complete the write to the receiver FIFO
// TRX.WriteMode(RFM69_OPMODE_RX); // back to receive (but we already have AutoRxRestart)
return 1; } // return: 1 packet we have received
static uint32_t ReceiveUntil(TickType_t End)
{ uint32_t Count=0;
for( ; ; )
{ Count+=ReceivePacket();
int32_t Left = End-xTaskGetTickCount();
if(Left<=0) break;
vTaskDelay(1); }
return Count; }
// static uint32_t ReceiveFor(TickType_t Ticks) // keep receiving packets for given period of time
// { return ReceiveUntil(xTaskGetTickCount()+Ticks); }
static uint8_t Transmit(uint8_t TxChan, const uint8_t *PacketByte, uint8_t Thresh, uint8_t MaxWait=7)
{
if(PacketByte==0) return 0; // if no packet to send: simply return
if(MaxWait)
{ for( ; MaxWait; MaxWait--) // wait for a given maximum time for a free radio channel
{
#ifdef WITH_RFM69
TRX.TriggerRSSI();
#endif
vTaskDelay(1);
uint8_t RxRSSI=TRX.ReadRSSI();
RX_Random = (RX_Random<<1) | (RxRSSI&1);
if(RxRSSI>=Thresh) break; }
if(MaxWait==0) return 0; }
#ifdef WITH_LED_TX
LED_TX_Flash(20);
#endif
TRX.WriteMode(RF_OPMODE_STANDBY); // switch to standby
// vTaskPrioritySet(0, tskIDLE_PRIORITY+2);
vTaskDelay(1);
SetTxChannel(TxChan);
TRX.ClearIrqFlags();
TRX.WritePacketOGN(PacketByte); // write packet into FIFO
TRX.WriteMode(RF_OPMODE_TRANSMITTER); // transmit
vTaskDelay(5); // wait 5ms
uint8_t Break=0;
for(uint16_t Wait=400; Wait; Wait--) // wait for transmission to end
{ // if(!TRX.DIO0_isOn()) break;
// uint8_t Mode=TRX.ReadMode();
uint16_t Flags=TRX.ReadIrqFlags();
// if(Mode!=RF_OPMODE_TRANSMITTER) break;
if(Flags&RF_IRQ_PacketSent) Break++;
if(Break>=2) break; }
TRX.WriteMode(RF_OPMODE_STANDBY); // switch to standy
// vTaskPrioritySet(0, tskIDLE_PRIORITY+2);
SetRxChannel();
TRX.WriteMode(RF_OPMODE_RECEIVER); // back to receive mode
return 1; }
// make a time-slot: listen for packets and transmit given PacketByte$
static void TimeSlot(uint8_t TxChan, uint32_t SlotLen, const uint8_t *PacketByte, uint8_t Rx_RSSI, uint8_t MaxWait=8, uint32_t TxTime=0)
{ TickType_t Start = xTaskGetTickCount(); // when the slot started
TickType_t End = Start + SlotLen; // when should it end
uint32_t MaxTxTime = SlotLen-8-MaxWait; // time limit when transmision could start
if( (TxTime==0) || (TxTime>=MaxTxTime) ) TxTime = RX_Random%MaxTxTime; // if TxTime out of limits, setup a random TxTime
TickType_t Tx = Start + TxTime; // Tx = the moment to start transmission
ReceiveUntil(Tx); // listen until this time comes
if( (TX_Credit) && (PacketByte) ) // when packet to transmit is given and there is still TX credit left:
TX_Credit-=Transmit(TxChan, PacketByte, Rx_RSSI, MaxWait); // attempt to transmit the packet
ReceiveUntil(End); // listen till the end of the time-slot
}
static void SetFreqPlanOGN(void) // set the RF TRX according to the selected frequency hopping plan
{ TRX.setBaseFrequency(RF_FreqPlan.BaseFreq); // set the base frequency (recalculate to RFM69 internal synth. units)
TRX.setChannelSpacing(RF_FreqPlan.ChanSepar); // set the channel separation
TRX.setFrequencyCorrection(Parameters.RFchipFreqCorr); } // set the fine correction (to counter the Xtal error)
static void SetFreqPlanWAN(void) // set the LoRaWAN EU frequency plan: 8 LoRa channels
{ TRX.setBaseFrequency(867100000);
TRX.setChannelSpacing( 200000);
TRX.setFrequencyCorrection(Parameters.RFchipFreqCorr); }
static uint8_t StartRFchip(void)
{ TRX.WriteMode(RF_OPMODE_STANDBY);
vTaskDelay(1);
TRX.RESET(1); // RESET active
vTaskDelay(1); // wait 10ms
TRX.RESET(0); // RESET released
vTaskDelay(5); // wait 10ms
SetFreqPlanOGN(); // set TRX base frequency and channel separation after the frequency hopping plan
#ifdef DEBUG_PRINT
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
TRX.PrintReg(CONS_UART_Write);
xSemaphoreGive(CONS_Mutex);
#endif
// #ifdef WITH_RFM95
// TRX.WriteDefaultReg();
// #endif
TRX.OGN_Configure(0, OGN_SYNC); // setup RF chip parameters and set to channel #0
TRX.WriteMode(RF_OPMODE_STANDBY); // set RF chip mode to STANDBY
uint8_t Version = TRX.ReadVersion();
#ifdef DEBUG_PRINT
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
TRX.PrintReg(CONS_UART_Write);
Format_String(CONS_UART_Write, "StartRFchip() v");
Format_Hex(CONS_UART_Write, Version);
CONS_UART_Write(' ');
Format_UnsDec(CONS_UART_Write, RF_FreqPlan.BaseFreq, 4, 3);
CONS_UART_Write('+');
Format_UnsDec(CONS_UART_Write, (uint16_t)RF_FreqPlan.Channels, 2);
CONS_UART_Write('x');
Format_UnsDec(CONS_UART_Write, RF_FreqPlan.ChanSepar, 4, 3);
Format_String(CONS_UART_Write, "kHz\n");
xSemaphoreGive(CONS_Mutex);
#endif
return Version; } // read the RF chip version and return it
// some LoRaWAN variables
#ifdef WITH_LORAWAN
static uint8_t WAN_BackOff = 60; // back-off timer
static TickType_t WAN_RespTick = 0; // when to expect the WAN response
static RFM_LoRa_RxPacket WAN_RxPacket; // packet received from WAN
// static WAN_Setup()
// static WAN_Back()
#endif
extern "C"
void vTaskRF(void* pvParameters)
{
RF_RxFIFO.Clear(); // clear receive/transmit packet FIFO's
RF_TxFIFO.Clear();
#ifdef WITH_FANET
FNT_RxFIFO.Clear();
FNT_TxFIFO.Clear();
#endif
#ifdef USE_BLOCK_SPI
TRX.TransferBlock = RFM_TransferBlock;
#else
TRX.Select = RFM_Select; // [call]
TRX.Deselect = RFM_Deselect; // [call]
TRX.TransferByte = RFM_TransferByte; // [call]
#endif
TRX.DIO0_isOn = RFM_IRQ_isOn; // [call] read IRQrfm_reset
TRX.Delay_ms = RFM_Delay; // [call] delay by N miliseconds
TRX.RESET = RFM_RESET; // [call] chip reset control
RF_FreqPlan.setPlan(Parameters.FreqPlan); // 1 = Europe/Africa, 2 = USA/CA, 3 = Australia and South America
vTaskDelay(5);
for( ; ; )
{ uint8_t ChipVersion = StartRFchip();
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_String(CONS_UART_Write, "TaskRF: v");
Format_Hex(CONS_UART_Write, ChipVersion);
CONS_UART_Write('\r'); CONS_UART_Write('\n');
xSemaphoreGive(CONS_Mutex);
if( (ChipVersion!=0x00) && (ChipVersion!=0xFF) ) break; // only break the endless loop then an RF chip is detected
vTaskDelay(1000);
}
TX_Credit = 0; // count slots and packets transmitted: to keep the rule of 1% transmitter duty cycle
RX_OGN_Packets = 0; // count received packets per every second (two time slots)
RX_OGN_Count64 = 0;
RX_OGN_CountDelay.Clear();
RX_Channel = RF_FreqPlan.getChannel(TimeSync_Time(), 0, 1); // set initial RX channel
SetRxChannel();
TRX.WriteMode(RF_OPMODE_RECEIVER);
RX_RSSI.Set(2*112);
for( ; ; )
{
// #ifdef DEBUG_PRINT
// RF_Print();
// #endif
// xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
// Format_UnsDec(CONS_UART_Write, xTaskGetTickCount(), 4, 3);
// Format_String(CONS_UART_Write, " => RF-slot\n");
// xSemaphoreGive(CONS_Mutex);
#ifdef WITH_LORAWAN
bool WANrx=0;
int WAN_RespLeft = WAN_RespTick-xTaskGetTickCount(); // [tick] how much time left before expected response
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) // if reception expected from WAN
{ int RxLen=0;
TRX.WriteMode(RF_OPMODE_STANDBY); // TRX to standby
TRX.setLoRa(); // switch to LoRa mode (through sleep)
TRX.WriteMode(RF_OPMODE_LORA_STANDBY); // TRX in standby
SetFreqPlanWAN(); // WAN frequency plan
TRX.WAN_Configure(); // LoRa for WAN config.
TRX.setChannel(WANdev.Chan); // set the channel
TRX.LoRa_InvertIQ(1); TRX.LoRa_setCRC(0); TRX.LoRa_setIRQ(0); // setup for WAN RX
TRX.WriteMode(RF_OPMODE_LORA_RX_SINGLE); // wait for a single packet
int Wait=WAN_RespLeft+100; // 100ms timeout after the expected reception
for( ; Wait>0; Wait--)
{ vTaskDelay(1);
if(TRX.readIRQ()) break; } // IRQ signals packet reception
if(Wait)
{ TRX.LoRa_ReceivePacket(WAN_RxPacket);
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_UnsDec(CONS_UART_Write, xTaskGetTickCount(), 4, 3);
Format_String(CONS_UART_Write, "s LoRaWAN Rx: ");
Format_UnsDec(CONS_UART_Write, (uint16_t)WAN_RxPacket.Len);
Format_String(CONS_UART_Write, "B/");
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
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
SetRxChannel();
TRX.WriteMode(RF_OPMODE_RECEIVER); // switch to receive mode
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");
Format_String(CONS_UART_Write, "\n");
xSemaphoreGive(CONS_Mutex); }
}
else
#else
// if(TimeSync_msTime()<260);
{ uint32_t RxRssiSum=0; uint16_t RxRssiCount=0; // measure the average RSSI for lower frequency
do
{ ReceivePacket(); // keep checking for received packets
#ifdef WITH_RFM69
TRX.TriggerRSSI();
#endif
vTaskDelay(1);
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
}
#endif
TRX.WriteMode(RF_OPMODE_STANDBY); // switch to standy
vTaskDelay(1);
if(PowerMode==0)
{ TRX.WriteMode(RF_OPMODE_SLEEP);
while(PowerMode==0)
vTaskDelay(1);
TRX.WriteMode(RF_OPMODE_STANDBY);
vTaskDelay(1); }
SetFreqPlanOGN();
TRX.averRSSI=RX_RSSI.getOutput();
RX_OGN_Count64 += RX_OGN_Packets - RX_OGN_CountDelay.Input(RX_OGN_Packets); // add OGN packets received, subtract packets received 64 seconds ago
RX_OGN_Packets=0; // clear the received packet count
StartRFchip(); // reset and rewrite the RF chip config
#ifdef WITH_RFM69
TRX.TriggerTemp(); // trigger RF chip temperature readout
vTaskDelay(1); // while(TRX.RunningTemp()) taskYIELD(); // wait for conversion to be ready
TRX.ReadTemp(); // [degC] read RF chip temperature
#endif
#ifdef WITH_RFM95
TRX.ReadTemp(); // [degC] read RF chip temperature
#endif
TRX.chipTemp+=Parameters.RFchipTempCorr;
// Note: on RFM95 temperature sens does not work in STANDBY
RF_SlotTime = TimeSync_Time();
uint8_t TxChan = RF_FreqPlan.getChannel(RF_SlotTime, 0, 1); // tranmsit channel
RX_Channel = TxChan;
SetRxChannel();
// here we can read the chip temperature
TRX.WriteMode(RF_OPMODE_RECEIVER); // switch to receive mode
vTaskDelay(1);
uint32_t RxRssiSum=0; uint16_t RxRssiCount=0; // measure the average RSSI for the upper frequency
do
{ ReceivePacket(); // check for packets being received ?
#ifdef WITH_RFM69
TRX.TriggerRSSI(); // start RSSI measurement
#endif
vTaskDelay(1);
uint8_t RxRSSI=TRX.ReadRSSI(); // read RSSI
RX_Random = (RX_Random<<1) | (RxRSSI&1); // take lower bit for random number generator
RxRssiSum+=RxRSSI; RxRssiCount++;
} while(TimeSync_msTime()<350); // keep going until 400 ms after PPS
RX_RSSI.Process(RxRssiSum/RxRssiCount); // [-0.5dBm] average noise on channel
TX_Credit+=2; if(TX_Credit>7200) TX_Credit=7200; // count the transmission credit
XorShift32(RX_Random);
uint32_t TxTime = (RX_Random&0x3F)+1; TxTime*=6; TxTime+=50; // random transmission time: (1..64)*6+50 [ms]
const uint8_t *TxPktData0=0;
const uint8_t *TxPktData1=0;
const OGN_TxPacket<OGN_Packet> *TxPkt0 = RF_TxFIFO.getRead(0); // get 1st packet from TxFIFO
const OGN_TxPacket<OGN_Packet> *TxPkt1 = RF_TxFIFO.getRead(1); // get 2nd packet from TxFIFO
if(TxPkt0) TxPktData0=TxPkt0->Byte(); // if 1st is not NULL then get its data
if(TxPkt1) TxPktData1=TxPkt1->Byte(); // if 2nd if not NULL then get its data
else TxPktData1=TxPktData0; // but if NULL then take copy of the 1st packet
if(TxPkt0) // if 1st packet is not NULL
{ if( (RX_Channel!=TxChan) && (TxPkt0->Packet.Header.Relay==0) )
{ const uint8_t *Tmp=TxPktData0; TxPktData0=TxPktData1; TxPktData1=Tmp; } // swap 1st and 2nd packet data
}
TimeSlot(TxChan, 800-TimeSync_msTime(), TxPktData0, TRX.averRSSI, 0, TxTime); // run a Time-Slot till 0.800sec
TRX.WriteMode(RF_OPMODE_STANDBY); // switch to receive mode
TxChan = RF_FreqPlan.getChannel(RF_SlotTime, 1, 1); // transmit channel
RX_Channel = TxChan;
#ifdef WITH_PAW
{ PAW_Packet Packet; Packet.Clear();
Packet.Address = Parameters.Address;
Packet.AcftType = Parameters.AcftType;
Packet.setCRC();
TRX.WriteMode(RF_OPMODE_STANDBY);
TRX.PAW_Configure(PAW_SYNC);
TRX.WriteTxPower(Parameters.getTxPower());
TRX.WritePacketPAW(Packet.Byte, 24);
TRX.WriteMode(RF_OPMODE_TRANSMITTER);
vTaskDelay(10);
TRX.WriteMode(RF_OPMODE_STANDBY);
TRX.OGN_Configure(0, OGN_SYNC); }
#endif
#if defined(WITH_FANET) && defined(WITH_RFM95)
const FANET_Packet *FNTpkt = FNT_TxFIFO.getRead(0); // read the packet from the FANET transmitt queue
if(FNTpkt) // was there any ?
{ TRX.setLoRa(); // switch TRX to LoRa
TRX.FNT_Configure(); // configure for FANET
// TRX.setChannel(0); // configure for FANET
TRX.WriteTxPower(Parameters.getTxPower()); // transmission power
TRX.WriteMode(RF_OPMODE_LORA_RX_CONT); // continous receiver mode
vTaskDelay(2);
for(uint8_t Wait=50; Wait; Wait--) //
{ vTaskDelay(1); // every milisecond
uint8_t Stat = TRX.ReadByte(REG_LORA_MODEM_STATUS); // receiver status
if((Stat&0x0B)==0) break; } // 0:signal-det, 1:signal-sync, 3:header-valid
TRX.WriteMode(RF_OPMODE_LORA_STANDBY);
TRX.FNT_SendPacket(FNTpkt->Byte, FNTpkt->Len); // transmit the FANET packet
FNT_TxFIFO.Read(); // remove the last packet from the queue
/*
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_String(CONS_UART_Write, "TRX: ");
Format_Hex(CONS_UART_Write, TRX.ReadMode());
CONS_UART_Write(':');
Format_Hex(CONS_UART_Write, TRX.ReadByte(REG_LORA_IRQ_FLAGS));
CONS_UART_Write(' ');
Format_Hex(CONS_UART_Write, TRX.ReadByte(REG_LORA_PREAMBLE_LSB));
CONS_UART_Write(':');
Format_Hex(CONS_UART_Write, TRX.ReadByte(REG_LORA_SYNC));
CONS_UART_Write(' ');
Format_Hex(CONS_UART_Write, TRX.ReadByte(REG_LORA_MODEM_CONFIG1));
CONS_UART_Write(':');
Format_Hex(CONS_UART_Write, TRX.ReadByte(REG_LORA_MODEM_CONFIG2));
Format_String(CONS_UART_Write, "\n");
xSemaphoreGive(CONS_Mutex);
*/
vTaskDelay(8);
for( uint8_t Wait=50; Wait; Wait--)
{ vTaskDelay(1);
uint8_t Mode=TRX.ReadMode();
if(Mode!=RF_OPMODE_LORA_TX) break; }
TRX.setFSK();
TRX.OGN_Configure(0, OGN_SYNC);
}
#endif
SetRxChannel();
TRX.WriteMode(RF_OPMODE_RECEIVER); // switch to receive mode
XorShift32(RX_Random);
TxTime = (RX_Random&0x3F)+1; TxTime*=6; // [ms] (1..64)*6 = 6..384ms
#ifdef WITH_LORAWAN
bool WANtx = 0;
uint16_t SlotEnd = 1240;
if(WAN_BackOff) WAN_BackOff--;
else // decide to transmit in this slot
{ if(WANdev.State==0 || WANdev.State==2) //
{ XorShift32(RX_Random); if((RX_Random&0x1F)==0x10) { WANtx=1; SlotEnd=1200; } } // random decision 1/32
}
TimeSlot(TxChan, SlotEnd-TimeSync_msTime(), TxPktData1, TRX.averRSSI, 0, TxTime);
#else
TimeSlot(TxChan, 1240-TimeSync_msTime(), TxPktData1, TRX.averRSSI, 0, TxTime);
#endif
#ifdef WITH_LORAWAN
if(WANtx)
{ TRX.WriteMode(RF_OPMODE_STANDBY); // TRX to standby
TRX.setLoRa(); // switch to LoRa mode (through sleep)
TRX.WriteMode(RF_OPMODE_LORA_STANDBY); // TRX in standby
SetFreqPlanWAN(); // WAN frequency plan
TRX.WAN_Configure(); // LoRa for WAN config.
XorShift32(RX_Random); // random
WANdev.Chan = RX_Random&7; // choose random channel
TRX.setChannel(WANdev.Chan); // set the channel
TRX.LoRa_InvertIQ(0); TRX.LoRa_setCRC(1); // setup for WAN TX
TRX.WriteTxPower(Parameters.getTxPower()); // transmit power
int RespDelay=0;
int TxPktLen=0;
if(WANdev.State==0)
{ uint8_t *TxPacket; TxPktLen=WANdev.getJoinRequest(&TxPacket); // produce Join-Request packet
TRX.LoRa_SendPacket(TxPacket, TxPktLen); RespDelay=5000; // transmit join-request packet
WAN_BackOff=30;
} else if(WANdev.State==2)
{ const uint8_t *PktData=TxPktData0;
if(PktData==0) PktData=TxPktData1;
if(PktData) // if there is a packet to transmit
{ OGN1_Packet *OGN = (OGN1_Packet *)PktData; if(!OGN->Header.Encrypted) OGN->Dewhiten();
uint8_t *TxPacket;
bool Short = !OGN->Header.NonPos && !OGN->Header.Encrypted
&& OGN->Header.AddrType==3 && OGN->Header.Address==(uint32_t)(getUniqueAddress()&0x00FFFFFF);
if(Short)
{ 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;
WAN_BackOff=32; }
}
if(RespDelay)
{ vTaskDelay(8);
for( uint8_t Wait=100; Wait; Wait--) // wait for the end of transmission
{ vTaskDelay(1);
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
xSemaphoreTake(CONS_Mutex, portMAX_DELAY);
Format_UnsDec(CONS_UART_Write, xTaskGetTickCount(), 4, 3);
Format_String(CONS_UART_Write, "s LoRaWAN Tx: ");
Format_UnsDec(CONS_UART_Write, (unsigned)TxPktLen);
Format_String(CONS_UART_Write, "B\n");
xSemaphoreGive(CONS_Mutex);
}
TRX.setFSK(); // back to FSK
SetFreqPlanOGN(); // OGN frequency plan
TRX.OGN_Configure(0, OGN_SYNC); // OGN config
SetRxChannel();
TRX.WriteMode(RF_OPMODE_RECEIVER); // switch to receive mode
}
#endif
if(TxPkt0) RF_TxFIFO.Read();
if(TxPkt1) RF_TxFIFO.Read();
}
}
// ======================================================================================