From e9caf1f353108c802af9f05ba762b50e5e52664a Mon Sep 17 00:00:00 2001 From: Pawel Jalocha Date: Fri, 9 Oct 2020 14:08:50 +0100 Subject: [PATCH] LoRaWAN code can join and send positions, proof of concept, far from stable --- main/LoRaMacCrypto.h | 8 +++ main/disp.cpp | 5 +- main/disp_oled.cpp | 24 ++++++- main/disp_oled.h | 1 + main/format.h | 13 ++-- main/hal.cpp | 2 + main/hal.h | 1 + main/lorawan.h | 32 ++++----- main/main.cpp | 18 ++--- main/parameters.h | 5 +- main/rf.cpp | 168 +++++++++++++++++++++++++++++++++++++------ main/rfm.h | 10 ++- 12 files changed, 224 insertions(+), 63 deletions(-) diff --git a/main/LoRaMacCrypto.h b/main/LoRaMacCrypto.h index 0c579fa..1bd975b 100644 --- a/main/LoRaMacCrypto.h +++ b/main/LoRaMacCrypto.h @@ -42,6 +42,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /*! * Computes the LoRaMAC frame MIC field * @@ -124,4 +128,8 @@ void LoRaMacBeaconComputePingOffset( uint64_t beaconTime, uint32_t address, uint /*! \} defgroup LORAMAC */ +#ifdef __cplusplus +} // extern "C" +#endif + #endif // __LORAMAC_CRYPTO_H__ diff --git a/main/disp.cpp b/main/disp.cpp index 16e946c..bfbdad7 100644 --- a/main/disp.cpp +++ b/main/disp.cpp @@ -25,7 +25,7 @@ #include "disp_lcd.h" #ifdef WITH_U8G2_OLED -const uint8_t DISP_Pages = 11; +const uint8_t DISP_Pages = 12; static uint8_t DISP_Page = 0; #endif #if defined(WITH_ST7789) || defined(WITH_ILI9341) @@ -191,7 +191,8 @@ void vTaskDISP(void* pvParameters) case 7: OLED_DrawRelay (&U8G2_OLED, GPS); break; case 8: OLED_DrawLookout (&U8G2_OLED, GPS); break; case 9: OLED_DrawTrafWarn (&U8G2_OLED, GPS); break; - case 10: OLED_DrawLoRaWAN (&U8G2_OLED, GPS); break; + case 10: OLED_DrawFlight (&U8G2_OLED, GPS); break; + case 11: OLED_DrawLoRaWAN (&U8G2_OLED, GPS); break; } } //if ( DISP_Page != 6 ) diff --git a/main/disp_oled.cpp b/main/disp_oled.cpp index 8ab25c4..bac7171 100644 --- a/main/disp_oled.cpp +++ b/main/disp_oled.cpp @@ -815,6 +815,12 @@ void OLED_DrawAltitudeAndSpeed(u8g2_t *OLED, GPS_Position *GPS) u8g2_DrawXBM(OLED, 118, 47, kmh_width, kmh_height, kmh_bits); } +void OLED_DrawFlight(u8g2_t *OLED, GPS_Position *GPS) // draw flight status page +{ u8g2_SetFont(OLED, u8g2_font_7x13_tf); + u8g2_DrawStr(OLED, 0, 28, "Flight"); + +} + void OLED_DrawLoRaWAN(u8g2_t *OLED, GPS_Position *GPS) // draw LoRaWAN status page { u8g2_SetFont(OLED, u8g2_font_7x13_tf); @@ -822,13 +828,25 @@ void OLED_DrawLoRaWAN(u8g2_t *OLED, GPS_Position *GPS) // draw LoRaWAN status pa u8g2_DrawStr(OLED, 0, 28, "LoRaWAN: -OFF-"); #endif #ifdef WITH_LORAWAN - const char *StateName[3] = { "Idle", "Join-Req", "Joined" } ; + const char *StateName[4] = { "Not-Joined", "Join-Req", "+Joined+", "PktSend" } ; int Len=Format_String(Line, "LoRaWAN: "); - if(WANdev.State<=2) Len+=Format_String(Line+Len, StateName[WANdev.State]); + if(WANdev.State<=3) Len+=Format_String(Line+Len, StateName[WANdev.State]); else Len+=Format_Hex(Line+Len, WANdev.State); Line[Len]=0; u8g2_DrawStr(OLED, 0, 24, Line); - + Len =Format_String(Line , "Up: "); Len+=Format_Hex(Line+Len, (uint16_t)WANdev.UpCount); + Len+=Format_String(Line+Len, " Dn: "); Len+=Format_Hex(Line+Len, (uint16_t)WANdev.DnCount); + Line[Len]=0; + u8g2_DrawStr(OLED, 0, 36, Line); + // if(WANdev.State>=2) { } +/* + Len=0; + for(int Idx=0; Idx<16; Idx++) + { Len+=Format_Hex(Line+Len, WANdev.AppKey[Idx]); } + Line[Len]=0; + u8g2_SetFont(OLED, u8g2_font_5x8_tr); + u8g2_DrawStr(OLED, 0, 48, Line); +*/ #endif // WITH_LORAWAN } diff --git a/main/disp_oled.h b/main/disp_oled.h index fec64fe..0467db0 100644 --- a/main/disp_oled.h +++ b/main/disp_oled.h @@ -23,5 +23,6 @@ void OLED_DrawStatusBar(u8g2_t *OLED, GPS_Position *GPS=0); void OLED_DrawSystem (u8g2_t *OLED, GPS_Position *GPS=0); void OLED_DrawID (u8g2_t *OLED, GPS_Position *GPS=0); void OLED_DrawAltitudeAndSpeed(u8g2_t *OLED, GPS_Position *GPS=0); +void OLED_DrawFlight (u8g2_t *OLED, GPS_Position *GPS=0); void OLED_DrawLoRaWAN (u8g2_t *OLED, GPS_Position *GPS=0); #endif diff --git a/main/format.h b/main/format.h index 808c311..b92e600 100644 --- a/main/format.h +++ b/main/format.h @@ -33,11 +33,14 @@ uint8_t Format_String(char *Out, const char *String, uint8_t MinLen, uint8_t Max uint8_t Format_UnsDec (char *Out, uint32_t Value, uint8_t MinDigits=1, uint8_t DecPoint=0); uint8_t Format_SignDec(char *Out, int32_t Value, uint8_t MinDigits=1, uint8_t DecPoint=0, uint8_t NoPlus=0); -uint8_t Format_Hex( char *Output, uint8_t Byte ); -uint8_t Format_Hex( char *Output, uint16_t Word ); -uint8_t Format_Hex( char *Output, uint32_t Word ); -uint8_t Format_Hex( char *Output, uint32_t Word, uint8_t Digits); -uint8_t Format_Hex( char *Output, uint64_t Word ); +uint8_t Format_Hex(char *Output, uint8_t Byte ); +uint8_t Format_Hex(char *Output, uint16_t Word ); +uint8_t Format_Hex(char *Output, uint32_t Word ); +uint8_t Format_Hex(char *Output, uint32_t Word, uint8_t Digits); +uint8_t Format_Hex(char *Output, uint64_t Word ); + +// uint8_t Format_Hex(char *Output, const uint8_t *Bytes, uint8_t Len ); + // uint8_t Format_Hex( char *Output, uint64_t Word, uint8_t Digits); template diff --git a/main/hal.cpp b/main/hal.cpp index f8db915..5be87bf 100644 --- a/main/hal.cpp +++ b/main/hal.cpp @@ -919,6 +919,8 @@ void RFM_RESET(uint8_t On) { } void RFM_IRQ_SetInput(void) { gpio_set_direction(PIN_RFM_IRQ, GPIO_MODE_INPUT); } bool RFM_IRQ_isOn(void) { return gpio_get_level(PIN_RFM_IRQ); } +void RFM_Delay(int ms) { vTaskDelay(ms); } + static spi_device_handle_t RFM_SPI; void RFM_TransferBlock(uint8_t *Data, uint8_t Len) diff --git a/main/hal.h b/main/hal.h index 9e8f2aa..89d0707 100644 --- a/main/hal.h +++ b/main/hal.h @@ -94,6 +94,7 @@ void AERO_UART_SetBaudrate(int BaudRate); void RFM_TransferBlock(uint8_t *Data, uint8_t Len); void RFM_RESET(uint8_t On); // RF module reset bool RFM_IRQ_isOn(void); // query the IRQ state +void RFM_Delay(int ms); // [ms] idle delay #ifdef WITH_OLED int OLED_DisplayON(uint8_t ON, uint8_t DispIdx=0); // when OFF then low-power mode diff --git a/main/lorawan.h b/main/lorawan.h index 09f0f4f..7341816 100644 --- a/main/lorawan.h +++ b/main/lorawan.h @@ -25,7 +25,7 @@ class LoRaWANnode 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 State; // 0:disconencted, 1:join-request sent, 2:join-accept received + 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 uint32_t DnCount; // [seq] Downlink frame counter: reset when joining the network @@ -105,9 +105,10 @@ class LoRaWANnode int getJoinRequest(uint8_t *Req) { Req[0] = 0x00; // MHDR, Join-Request: 000 000 00 - memcpy(Req+1, &AppEUI, 8); // - memcpy(Req+9, &DevEUI, 8); - Req[17] = DevNonce; + memcpy(Req+1, &AppEUI, 8); // AppEUI + memcpy(Req+9, &DevEUI, 8); // DevEUI + DevNonce++; // increment DevNonce for a new request + Req[17] = DevNonce; // DevNonce Req[18] = DevNonce>>8; uint32_t MIC=0; LoRaMacJoinComputeMic(Req, 19, AppKey, &MIC); // compute MIC @@ -123,7 +124,7 @@ class LoRaWANnode RxRSSI = RxPacket.RSSI; return Ret; } - int procJoinAccept(const uint8_t *PktData, int PktLen) + int procJoinAccept(const uint8_t *PktData, int PktLen) // process Join-Accept packet (5sec after Join-Request) { if(PktLen<13) return -1; uint8_t Type = PktData[0]>>5; if(Type!=1) return -1; Packet[0] = PktData[0]; @@ -137,7 +138,7 @@ class LoRaWANnode DevAddr = readInt(Packet+7, 4); DLsetting = Packet[11]; RxDelay = Packet[12]; - State = 2; // State = accepted on network + State = 2; // State = accepted on network UpCount = 0; DnCount = 0; #ifdef WITH_PRINTF @@ -151,23 +152,21 @@ class LoRaWANnode return 0; } int getDataPacket(uint8_t *Packet, const uint8_t *Data, int DataLen, uint8_t Port=1, bool Confirm=0) - { uint8_t Type = Confirm?0x04:0x02; + { if(State<2) return 0; // not joined to the network yet + uint8_t Type = Confirm?0x04:0x02; // request confirmation or not ? int PktLen=0; Packet[PktLen++] = Type<<5; // packet-type PktLen+=writeInt(Packet+PktLen, DevAddr, 4); // Device Address - uint8_t Ctrl=0; - if(TxACK) { Ctrl|=0x20; TxACK=0; } + uint8_t Ctrl=0; // Frame Control + if(TxACK) { Ctrl|=0x20; TxACK=0; } // if there is ACK to be transmitted Packet[PktLen++] = Ctrl; // Frame Control: ADR | ADR-ACK-Req | ACK | ClassB | FOptsLen[4] PktLen+=writeInt(Packet+PktLen, UpCount, 2); // uplink frame counter Packet[PktLen++] = Port; // port LoRaMacPayloadEncrypt(Data, DataLen, AppSesKey, DevAddr, 0, UpCount, Packet+PktLen); PktLen+=DataLen; // copy+encrypt user data uint32_t MIC=0; LoRaMacComputeMic(Packet, PktLen, NetSesKey, DevAddr, 0x00, UpCount, &MIC); // calc. MIC - // uint8_t MIC2[4]; - // Tiny.Calculate_MIC(Packet, MIC2, PktLen, UpCount, 0x00); - // printf("Data packet MIC: %08X <=> %02X%02X%02X%02X\n", MIC, MIC2[3], MIC2[2], MIC2[1], MIC2[0]); memcpy(Packet+PktLen, &MIC, 4); PktLen+=4; // append MIC - UpCount++; return PktLen; } + UpCount++; State=3; return PktLen; } // return the packet size int getDataPacket(uint8_t **Pkt, const uint8_t *Data, int DataLen, uint8_t Port=1, bool Confirm=0) { int Len=getDataPacket(Packet, Data, DataLen, Port, Confirm); *Pkt = Packet; return Len; } @@ -185,17 +184,11 @@ class LoRaWANnode if(Addr!=DevAddr) return 0; uint8_t Ctrl = PktData[5]; // Frame control: ADR | RFU | ACK | FPending | FOptLen[4] uint32_t Count=readInt(PktData+6, 2); - // Count |= DnCount&0xFFFF0000; int16_t CountDiff = Count-DnCount; // if(CountDiff<=0) return -1; // attempt to reuse the counter: drop this packet - // if(Diff<=(-0x4000)) Count+=0x10000; - // else if(Diff>0x4000) Count-=0x10000; - // printf("RxData: %08X\n", Count); uint32_t MIC=0; LoRaMacComputeMic(PktData, PktLen-4, NetSesKey, Addr, 0x01, Count, &MIC); - // printf("RxData: %08X\n", MIC); if(memcmp(PktData+PktLen-4, &MIC, 4)) return -1; // give up if MIC does not match - // if(Count==DnCount) return 0; uint8_t DataOfs = 8 + (Ctrl&0x0F); // where the port byte should be uint8_t DataLen = PktLen-DataOfs-4; // number of bytes of the user data field if(DataLen) // if non-zero @@ -211,6 +204,7 @@ class LoRaWANnode if(Ctrl&0x40) RxACK=1; // we got ACK to our ACK request if(Type==5) TxACK=1; // if ACK requested RxPend = Ctrl&0x10; // is there more data pending to be received on next round ? + State=2; return DataLen; } #ifdef WITH_ESP32 diff --git a/main/main.cpp b/main/main.cpp index a343f4b..bc09427 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -46,12 +46,6 @@ void app_main(void) Parameters.setDefault(getUniqueAddress()); // set default parameter values if(Parameters.ReadFromNVS()!=ESP_OK) // try to get parameters from NVS { Parameters.WriteToNVS(); } // if did not work: try to save (default) parameters to NVS -#ifdef WITH_LORAWAN - WANdev.Reset(getUniqueID(), Parameters.AppKey); - if(WANdev.ReadFromNVS()!=ESP_OK) - { WANdev.WriteToNVS(); } - if(memcpy(WANdev.AppKey, Parameters.AppKey, 16)) WANdev.Reset(getUniqueID(), Parameters.AppKey); -#endif #ifdef WITH_SPIFFS SPIFFS_Register(); // initialize the file system in the Flash @@ -68,6 +62,14 @@ void app_main(void) // #endif } #endif +#ifdef WITH_LORAWAN + WANdev.Reset(getUniqueID(), Parameters.AppKey); // set default LoRaWAN config. + if(WANdev.ReadFromNVS()!=ESP_OK) // if can't read the LoRaWAN setup from NVS + { WANdev.WriteToNVS(); } // then store the default + // if(memcmp(WANdev.AppKey, Parameters.AppKey, 16)) // if LoRaWAN key different from the one in Parameters + // { WANdev.Reset(getUniqueID(), Parameters.AppKey); // then reset LoRaWAN to this key + // WANdev.WriteToNVS(); } // and save LoRaWAN config. to NVS +#endif CONS_UART_SetBaudrate(Parameters.CONbaud); @@ -92,7 +94,7 @@ void app_main(void) xTaskCreate(vTaskLOG , "LOG", 4096, 0, tskIDLE_PRIORITY+1, 0); #endif - xTaskCreate(vTaskRF, "RF", 2048, 0, tskIDLE_PRIORITY+4, 0); + xTaskCreate(vTaskRF, "RF", 2048, 0, tskIDLE_PRIORITY+5, 0); xTaskCreate(vTaskPROC, "PROC", 2048, 0, tskIDLE_PRIORITY+3, 0); xTaskCreate(vTaskGPS, "GPS", 2048, 0, tskIDLE_PRIORITY+4, 0); @@ -107,7 +109,7 @@ void app_main(void) xTaskCreate(vTaskKNOB, "KNOB", 2048, 0, tskIDLE_PRIORITY+3, 0); #endif #ifdef WITH_AERO - xTaskCreate(vTaskAERO, "AERO", 2048, 0, tskIDLE_PRIORITY+4, 0); + xTaskCreate(vTaskAERO, "AERO", 2048, 0, tskIDLE_PRIORITY+3, 0); #endif #ifdef WITH_WIFI xTaskCreate(vTaskWIFI, "WIFI", 4096, 0, tskIDLE_PRIORITY+2, 0); diff --git a/main/parameters.h b/main/parameters.h index 38d5c8e..6e691ef 100644 --- a/main/parameters.h +++ b/main/parameters.h @@ -518,11 +518,12 @@ class FlashParameters Verbose=Mode; return 1; } #ifdef WITH_LORAWAN if(strcmp(Name, "AppKey")==0) - { for( uint8_t Idx=0; Idx<16; Idx++) + { for(uint8_t Idx=0; Idx<16; Idx++) { uint8_t Byte; uint8_t Len=Read_Hex(Byte, Value); if(Len!=2) break; - AppKey[Idx]=Byte; } + AppKey[Idx]=Byte; + Value+=2; } return 1; } #endif #ifdef WITH_ENCRYPT diff --git a/main/rf.cpp b/main/rf.cpp index b1a8d0c..eded8e9 100644 --- a/main/rf.cpp +++ b/main/rf.cpp @@ -159,11 +159,15 @@ static void TimeSlot(uint8_t TxChan, uint32_t SlotLen, const uint8_t *PacketByte ReceiveUntil(End); // listen till the end of the time-slot } -static void SetFreqPlan(void) // set the RF TRX according to the selected frequency hopping plan +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) -} + 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); @@ -172,7 +176,7 @@ static uint8_t StartRFchip(void) vTaskDelay(1); // wait 10ms TRX.RESET(0); // RESET released vTaskDelay(5); // wait 10ms - SetFreqPlan(); // set TRX base frequency and channel separation after the frequency hopping plan + 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); @@ -200,6 +204,11 @@ static uint8_t StartRFchip(void) #endif return Version; } // read the RF chip version and return it +static TickType_t WAN_RespTick = xTaskGetTickCount(); // when to expect the WAN response +static RFM_LoRa_RxPacket WAN_RxPacket; // packet received from WAN +// static WAN_Setup() +// static WAN_Back() + extern "C" void vTaskRF(void* pvParameters) { @@ -213,12 +222,13 @@ extern "C" #ifdef USE_BLOCK_SPI TRX.TransferBlock = RFM_TransferBlock; #else - TRX.Select = RFM_Select; - TRX.Deselect = RFM_Deselect; - TRX.TransferByte = RFM_TransferByte; + TRX.Select = RFM_Select; // [call] + TRX.Deselect = RFM_Deselect; // [call] + TRX.TransferByte = RFM_TransferByte; // [call] #endif - TRX.DIO0_isOn = RFM_IRQ_isOn; - TRX.RESET = RFM_RESET; + 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 @@ -256,18 +266,73 @@ extern "C" // RF_Print(); // #endif - uint32_t RxRssiSum=0; uint16_t RxRssiCount=0; // measure the average RSSI for lower frequency - do - { ReceivePacket(); // keep checking for received packets +#ifdef WITH_LORAWAN + bool WANrx=0; + int WAN_RespLeft = WAN_RespTick-xTaskGetTickCount(); + if(WANdev.State==1 || WANdev.State==3) + { if(WAN_RespLeft<=5) WANdev.State--; + else if(WAN_RespLeft<200) { WANrx=1; } + xSemaphoreTake(CONS_Mutex, portMAX_DELAY); + Format_String(CONS_UART_Write, "LoRaWAN Rx: "); + Format_SignDec(CONS_UART_Write, WAN_RespLeft); + Format_String(CONS_UART_Write, "ms "); + Format_UnsDec(CONS_UART_Write, xTaskGetTickCount()); + Format_String(CONS_UART_Write, "ms\n"); + xSemaphoreGive(CONS_Mutex); + } + + if(WANrx) + { 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; + for( ; Wait>0; Wait--) + { vTaskDelay(1); + if(TRX.readIRQ()) break; } + if(Wait) + { TRX.LoRa_ReceivePacket(WAN_RxPacket); + xSemaphoreTake(CONS_Mutex, portMAX_DELAY); + Format_String(CONS_UART_Write, "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 "); + Format_UnsDec(CONS_UART_Write, xTaskGetTickCount()); + Format_String(CONS_UART_Write, "ms\n"); + xSemaphoreGive(CONS_Mutex); + if(WANdev.State==1) WANdev.procJoinAccept(WAN_RxPacket); + else if(WANdev.State==3) WANdev.procRxData(WAN_RxPacket); + } + else WANdev.State--; + WANdev.WriteToNVS(); + 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 + } + 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(); + 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 - 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); @@ -279,7 +344,7 @@ extern "C" TRX.WriteMode(RF_OPMODE_STANDBY); vTaskDelay(1); } - SetFreqPlan(); + SetFreqPlanOGN(); TRX.averRSSI=RX_RSSI.getOutput(); @@ -307,7 +372,7 @@ extern "C" TRX.WriteMode(RF_OPMODE_RECEIVER); // switch to receive mode vTaskDelay(1); - RxRssiSum=0; RxRssiCount=0; // measure the average RSSI for the upper frequency + 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 @@ -349,6 +414,7 @@ extern "C" { TRX.setLoRa(); // switch TRX to LoRa TRX.FNT_Configure(); // TRX.setChannel(0); // configure for FANET + TRX.WriteTxPower(Parameters.getTxPower()); TRX.WriteMode(RF_OPMODE_LORA_RX_CONT); vTaskDelay(2); for(uint8_t Wait=50; Wait; Wait--) @@ -389,9 +455,65 @@ extern "C" TRX.WriteMode(RF_OPMODE_RECEIVER); // switch to receive mode XorShift32(RX_Random); - TxTime = (RX_Random&0x3F)+1; TxTime*=6; - + TxTime = (RX_Random&0x3F)+1; TxTime*=6; // [ms] (1..64)*6 = 6..384ms +#ifdef WITH_LORAWAN + bool WANtx = 0; // decide if send Join-Request + uint16_t SlotEnd = 1240; + if(WANdev.State==0 || WANdev.State==2) + { XorShift32(RX_Random); if((RX_Random&0x3F)==0x20) WANtx=1; SlotEnd=1200; } + TimeSlot(TxChan, SlotEnd-TimeSync_msTime(), TxPktData1, TRX.averRSSI, 0, TxTime); +#else TimeSlot(TxChan, 1250-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; int TxPktLen=WANdev.getJoinRequest(&TxPacket); // produce Join-Request packet + TRX.LoRa_SendPacket(TxPacket, TxPktLen); RespDelay=5000; // transmit join-request packet + } else if(WANdev.State==2) + { const uint8_t *PktData=TxPktData0; + if(PktData==0) PktData=TxPktData1; + if(PktData) + { ((OGN1_Packet *)PktData)->Dewhiten(); + uint8_t *TxPacket; + TxPktLen=WANdev.getDataPacket(&TxPacket, PktData, 20, 1, ((RX_Random>>16)&0xF)==0x8 ); + TRX.LoRa_SendPacket(TxPacket, TxPktLen); RespDelay=1000; } + } + 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_String(CONS_UART_Write, "LoRaWAN Tx: "); + Format_UnsDec(CONS_UART_Write, (unsigned)TxPktLen); + Format_String(CONS_UART_Write, "B "); + Format_UnsDec(CONS_UART_Write, xTaskGetTickCount()); + Format_String(CONS_UART_Write, "ms\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(); diff --git a/main/rfm.h b/main/rfm.h index a0a1a43..5e838ec 100644 --- a/main/rfm.h +++ b/main/rfm.h @@ -47,6 +47,7 @@ class RFM_LoRa_Config } ; const RFM_LoRa_Config RFM_FNTcfg { 0xF1587190 } ; // LoRa seting for FANET +const RFM_LoRa_Config RFM_WANcfg { 0x34877190 } ; // LoRa WAN setting for TX class RFM_LoRa_RxPacket { public: @@ -246,6 +247,8 @@ class RFM_TRX // bool (*DIO4_isOn)(void); void (*RESET)(uint8_t On); // activate or desactivate the RF chip reset + bool readIRQ(void) { return (*DIO0_isOn)(); } + // the following are in units of the synthesizer with 8 extra bits of precision uint32_t BaseFrequency; // [32MHz/2^19/2^8] base frequency = channel #0 // int32_t FrequencyCorrection; // [32MHz/2^19/2^8] frequency correction (due to Xtal offset) @@ -613,6 +616,11 @@ class RFM_TRX RFM_LoRa_Config CFG = RFM_FNTcfg; CFG.CR=CR; return LoRa_Configure(CFG, FANET_Packet::MaxBytes); } + int WAN_Configure(uint8_t CR=1) // configure for FANET/LoRa + { WriteTxPower(0); + RFM_LoRa_Config CFG = RFM_WANcfg; CFG.CR=CR; + return LoRa_Configure(CFG, 40); } + void LoRa_setIRQ(uint8_t Mode=0) // 0:on RX, 1:on TX, 2: on CAD { WriteByte(Mode<<6, REG_DIOMAPPING1); } @@ -662,7 +670,7 @@ class RFM_TRX Packet.FreqOfs = (FreqOfs*1718+0x8000)>>16; // [10Hz] Packet.BitErr = 0; Packet.CodeErr = 0; - int Len=LoRa_ReceivePacket(Packet.Byte, Packet.MaxBytes); + int Len=LoRa_ReceivePacket(Packet.Byte, Packet.MaxBytes); // read packet data // printf("ReceivePacketFNT() => %d %02X %3.1fdB %+ddBm 0x%08X=%+6.3fkHz, %02X%02X%02X%02X\n", // Packet.Len, Stat, 0.25*Packet.SNR, Packet.RSSI, FreqOfs, 0.5*0x1000000/32e9*FreqOfs, // Packet.Byte[0], Packet.Byte[1], Packet.Byte[2], Packet.Byte[3]);