#include "hal.h" #include "rf.h" #include "timesync.h" #include "lowpass2.h" // =============================================================================================== // OGN SYNC: 0x0AF3656C encoded in Manchester static const uint8_t OGN_SYNC[8] = { 0xAA, 0x66, 0x55, 0xA5, 0x96, 0x99, 0x96, 0x5A }; static 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 RF_RxFIFO; // buffer for received packets FIFO RF_TxFIFO; // buffer for transmitted packets 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 RX_RSSI; // low pass filter to average the RX noise static Delay 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 #ifdef WITH_RFM95 TRX.WriteTxPower(Parameters.getTxPower()); // set TX for transmission #endif TRX.setChannel(TxChan&0x7F); TRX.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.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 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_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.ReadPacket(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; } TRX.WriteMode(RF_OPMODE_STANDBY); // switch to standby // vTaskPrioritySet(0, tskIDLE_PRIORITY+2); vTaskDelay(1); SetTxChannel(TxChan); TRX.ClearIrqFlags(); TRX.WritePacket(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 SetFreqPlan(void) { 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(10*Parameters.RFchipFreqCorr); // set the fine correction (to counter the Xtal error) } static uint8_t StartRFchip(void) { TRX.RESET(1); // RESET active vTaskDelay(10); // wait 10ms TRX.RESET(0); // RESET released vTaskDelay(10); // wait 10ms SetFreqPlan(); // set TRX base frequency and channel separation after the frequency hopp$ TRX.Configure(0, OGN_SYNC); // setup RF chip parameters and set to channel #0 TRX.WriteMode(RF_OPMODE_STANDBY); // set RF chip mode to STANDBY return TRX.ReadVersion(); } // read the RF chip version and return it extern "C" void vTaskRF(void* pvParameters) { RF_RxFIFO.Clear(); // clear receive/transmit packet FIFO's RF_TxFIFO.Clear(); #ifdef USE_BLOCK_SPI TRX.TransferBlock = RFM_TransferBlock; #else TRX.Select = RFM_Select; TRX.Deselect = RFM_Deselect; TRX.TransferByte = RFM_TransferByte; #endif TRX.DIO0_isOn = RFM_IRQ_isOn; TRX.RESET = RFM_RESET; RF_FreqPlan.setPlan(0); // 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: "); CONS_UART_Write('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( ; ; ) { 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 TRX.WriteMode(RF_OPMODE_STANDBY); // switch to standy vTaskDelay(1); SetFreqPlan(); RX_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 second$ 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 RF_Temp= 165-TRX.ReadTemp(); // [degC] read RF chip temperature #endif #ifdef WITH_RFM95 RF_Temp= 15-TRX.ReadTemp(); // [degC] read RF chip temperature #endif RF_Temp+=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); RxRssiSum=0; 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 *TxPkt0 = RF_TxFIFO.getRead(0); // get 1st packet from TxFIFO const OGN_TxPacket *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.RelayCount==0) ) { const uint8_t *Tmp=TxPktData0; TxPktData0=TxPktData1; TxPktData1=Tmp; } // swap 1st and 2nd packet data } TimeSlot(TxChan, 800-TimeSync_msTime(), TxPktData0, RX_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; SetRxChannel(); TRX.WriteMode(RF_OPMODE_RECEIVER); // switch to receive mode XorShift32(RX_Random); TxTime = (RX_Random&0x3F)+1; TxTime*=6; TimeSlot(TxChan, 1250-TimeSync_msTime(), TxPktData1, RX_AverRSSI, 0, TxTime); if(TxPkt0) RF_TxFIFO.Read(); if(TxPkt1) RF_TxFIFO.Read(); } } // ======================================================================================