@ -15,33 +15,79 @@
# endif
# ifdef USE_LORA
# include <ArduinoUniqueID.h>
# include < Lo Ra.h>
# include < RadioLib .h>
# endif
// enable to get detailed info from where single configuration macros have been taken
# define LORA_ACK_TIMEOUT 400 // LoRa ACK timeout in ms. (Minimum = 200)
# define LORA_RETRIES 2 // LoRa ACK automatic retries [0 - 3]
// Internal Globals
// Default values that are assigned if none are present in config
# ifdef USE_LORA
# define GLOBAL_ACK_TIMEOUT 400 // LoRa ACK timeout in ms. (Minimum = 200)
# define GLOBAL_LORA_RETRIES 2 // LoRa ACK automatic retries [0 - 3]
# define GLOBAL_LORA_TXPWR 17 // LoRa TX power in dBm (: +2dBm - +17dBm (for SX1276-7) +20dBm (for SX1278))
# ifdef USE_LORA
// select LoRa band configuration
# if defined(LORA_BAND)
# define FDRS_BAND LORA_BAND
# elif defined (GLOBAL_LORA_BAND)
# define FDRS_BAND GLOBAL_LORA_BAND
# if defined(LORA_FREQUENCY)
# define FDRS_LORA_FREQUENCY LORA_FREQUENCY
# else
// ASSERT("NO LORA-BAND defined! Please define in fdrs_globals.h (recommended) or in fdrs_sensor_config.h");
# endif //LORA_ BAND
# define FDRS_LORA_FREQUENCY GLOBAL_LORA_FREQUENCY
# endif //LORA_ FREQUENCY
// select LoRa SF configuration
# if defined(LORA_SF)
# define FDRS_SF LORA_SF
# elif defined (GLOBAL_LORA_SF)
# define FDRS_SF GLOBAL_LORA_SF
# define FDRS_LORA_SF LORA_SF
# else
// ASSERT("NO LORA-SF defined! Please define in fdrs_globals.h (recommended) or in fdrs_sensor_config.h");
# define FDRS_LORA_SF GLOBAL_LORA_SF
# endif //LORA_SF
// select LoRa ACK configuration
# if defined(LORA_ACK) || defined(GLOBAL_LORA_ACK)
# define FDRS_LORA_ACK
# endif //LORA_ACK
// select LoRa ACK Timeout configuration
# if defined(LORA_ACK_TIMEOUT)
# define FDRS_ACK_TIMEOUT LORA_ACK_TIMEOUT
# else
# define FDRS_ACK_TIMEOUT GLOBAL_ACK_TIMEOUT
# endif //LORA_ACK_TIMEOUT
// select LoRa Retry configuration
# if defined(LORA_RETRIES)
# define FDRS_LORA_RETRIES LORA_RETRIES
# else
# define FDRS_LORA_RETRIES GLOBAL_LORA_RETRIES
# endif //LORA_RETRIES
// select LoRa Tx Power configuration
# if defined(LORA_TXPWR)
# define FDRS_LORA_TXPWR LORA_TXPWR
# else
# define FDRS_LORA_TXPWR GLOBAL_LORA_TXPWR
# endif //LORA_TXPWR
// select LoRa BANDWIDTH configuration
# if defined(LORA_BANDWIDTH)
# define FDRS_LORA_BANDWIDTH LORA_BANDWIDTH
# else
# define FDRS_LORA_BANDWIDTH GLOBAL_LORA_BANDWIDTH
# endif //LORA_BANDWIDTH
// select LoRa Coding Rate configuration
# if defined(LORA_CR)
# define FDRS_LORA_CR LORA_CR
# else
# define FDRS_LORA_CR GLOBAL_LORA_CR
# endif //LORA_CR
// select LoRa SyncWord configuration
# if defined(LORA_SYNCWORD)
# define FDRS_LORA_SYNCWORD LORA_SYNCWORD
# else
# define FDRS_LORA_SYNCWORD GLOBAL_LORA_SYNCWORD
# endif //LORA_SYNCWORD
# endif //USE_LORA
# ifdef FDRS_DEBUG
@ -87,6 +133,10 @@ uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t gatewayAddress [ ] = { MAC_PREFIX , GTWY_MAC } ;
uint16_t gtwyAddress = ( ( gatewayAddress [ 4 ] < < 8 ) | GTWY_MAC ) ;
# ifdef USE_LORA
RADIOLIB_MODULE radio = new Module ( LORA_SS , LORA_DIO0 , LORA_RST , LORA_DIO1 ) ;
bool transmitFlag = false ; // flag to indicate transmission or reception state
volatile bool enableInterrupt = true ; // disable interrupt when it's not needed
volatile bool operationDone = false ; // flag to indicate that a packet was sent or received
uint16_t LoRaAddress = ( ( UniqueID8 [ 6 ] < < 8 ) | UniqueID8 [ 7 ] ) ;
unsigned long transmitLoRaMsgwAck = 0 ; // Number of total LoRa packets destined for us and of valid size
unsigned long msgOkLoRa = 0 ; // Number of total LoRa packets with valid CRC
@ -96,7 +146,9 @@ uint8_t incMAC[6];
uint32_t wait_time = 0 ;
DataReading fdrsData [ espnow_size ] ;
DataReading incData [ espnow_size ] ;
crcResult esp_now_ack_flag ;
crcResult getLoRa ( ) ;
uint8_t data_count = 0 ;
bool is_ping = false ;
@ -106,6 +158,7 @@ void (*callback_ptr)(DataReading);
uint16_t subscription_list [ 256 ] = { } ;
bool active_subs [ 256 ] = { } ;
# ifdef USE_ESPNOW
// Set ESP-NOW send and receive callbacks for either ESP8266 or ESP32
# if defined(ESP8266)
void OnDataSent ( uint8_t * mac_addr , uint8_t sendStatus ) {
@ -155,8 +208,61 @@ void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
}
}
}
# endif // USE_ESPNOW
# ifdef USE_LORA
# if defined(ESP8266) || defined(ESP32)
ICACHE_RAM_ATTR
# endif
void setFlag ( void ) {
if ( ! enableInterrupt ) { // check if the interrupt is enabled
return ;
}
operationDone = true ; // we sent or received packet, set the flag
}
# endif
void handleLoRa ( ) {
# ifdef USE_LORA
if ( operationDone ) { // the interrupt was triggered
enableInterrupt = false ;
operationDone = false ;
if ( transmitFlag ) { // the previous operation was transmission,
radio . startReceive ( ) ; // return to listen mode
enableInterrupt = true ;
transmitFlag = false ;
} else { // the previous operation was reception
returnCRC = getLoRa ( ) ;
radio . startReceive ( ) ; // fixes the problem?
enableInterrupt = true ;
}
}
# endif //USE_LORA
}
void begin_lora ( ) {
// #ifdef ESP32
// SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
// #endif
# ifdef USE_LORA
int state = radio . begin ( FDRS_LORA_FREQUENCY , FDRS_LORA_BANDWIDTH , FDRS_LORA_SF , FDRS_LORA_CR , FDRS_LORA_SYNCWORD , FDRS_LORA_TXPWR , 8 , 0 ) ;
if ( state = = RADIOLIB_ERR_NONE ) {
DBG ( " RadioLib initialization successful! " ) ;
} else {
DBG ( " RadioLib initialization failed, code " + String ( state ) ) ;
while ( true ) ;
}
DBG ( " LoRa Initialized. Frequency: " + String ( FDRS_LORA_FREQUENCY ) + " Bandwidth: " + String ( FDRS_LORA_BANDWIDTH ) + " SF: " + String ( FDRS_LORA_SF ) + " CR: " + String ( FDRS_LORA_CR ) + " SyncWord: " + String ( FDRS_LORA_SYNCWORD ) + " Tx Power: " + String ( FDRS_LORA_TXPWR ) + " dBm " ) ;
radio . setDio0Action ( setFlag ) ;
radio . setCRC ( false ) ;
state = radio . startReceive ( ) ; // start listening for LoRa packets
if ( state = = RADIOLIB_ERR_NONE ) {
} else {
DBG ( " failed, code " + String ( state ) ) ;
while ( true ) ;
}
# endif // USE_LORA
}
void beginFDRS ( ) {
# ifdef FDRS_DEBUG
Serial . begin ( 115200 ) ;
@ -173,7 +279,7 @@ void beginFDRS() {
digitalWrite ( POWER_CTRL , 1 ) ;
delay ( 50 ) ;
# endif
// Init ESP-NOW for either ESP8266 or ESP32 and set MAC address
// Init ESP-NOW for either ESP8266 or ESP32
# ifdef USE_ESPNOW
DBG ( " Initializing ESP-NOW! " ) ;
WiFi . mode ( WIFI_STA ) ;
@ -214,22 +320,7 @@ void beginFDRS() {
# endif
DBG ( " ESP-NOW Initialized. " ) ;
# endif //USE_ESPNOW
# ifdef USE_LORA
DBG ( " Initializing LoRa! " ) ;
# ifdef ESP32
SPI . begin ( SPI_SCK , SPI_MISO , SPI_MOSI ) ;
# endif
LoRa . setPins ( LORA_SS , LORA_RST , LORA_DIO0 ) ;
if ( ! LoRa . begin ( FDRS_BAND ) ) {
DBG ( " Unable to initialize LoRa! " ) ;
while ( 1 ) ;
}
LoRa . setSpreadingFactor ( FDRS_SF ) ;
DBG ( " LoRa Initialized. " ) ;
DBG ( " LoRa Band: " + String ( FDRS_BAND ) ) ;
DBG ( " LoRa SF : " + String ( FDRS_SF ) ) ;
# endif // USE_LORA
begin_lora ( ) ;
# ifdef DEBUG_CONFIG
// if (resetReason != ESP_RST_DEEPSLEEP) {
//checkConfig();
@ -264,7 +355,6 @@ static uint16_t crc16_update(uint16_t crc, uint8_t a) {
return crc ;
}
crcResult getLoRa ( ) ;
void transmitLoRa ( uint16_t * destMAC , DataReading * packet , uint8_t len ) {
# ifdef USE_LORA
@ -286,22 +376,26 @@ void transmitLoRa(uint16_t* destMAC, DataReading * packet, uint8_t len) {
pkt [ len * sizeof ( DataReading ) + 4 ] = ( calcCRC > > 8 ) ;
pkt [ len * sizeof ( DataReading ) + 5 ] = ( calcCRC & 0x00FF ) ;
# ifdef LORA_ACK // Wait for ACK
int retries = LORA_RETRIES + 1 ;
int retries = FDRS_ LORA_RETRIES + 1 ;
while ( retries ! = 0 ) {
if ( transmitLoRaMsgwAck ! = 0 )
DBG ( " Transmitting LoRa message of size " + String ( sizeof ( pkt ) ) + " bytes with CRC 0x " + String ( calcCRC , HEX ) + " to gateway 0x " + String ( * destMAC , HEX ) + " . Retries remaining: " + String ( retries - 1 ) + " , Ack Ok " + String ( ( float ) msgOkLoRa / transmitLoRaMsgwAck * 100 ) + " % " ) ;
else
DBG ( " Transmitting LoRa message of size " + String ( sizeof ( pkt ) ) + " bytes with CRC 0x " + String ( calcCRC , HEX ) + " to gateway 0x " + String ( * destMAC , HEX ) + " . Retries remaining: " + String ( retries - 1 ) ) ;
//printLoraPacket(pkt,sizeof(pkt));
LoRa . beginPacket ( ) ;
LoRa . write ( ( uint8_t * ) & pkt , sizeof ( pkt ) ) ;
LoRa . endPacket ( ) ;
int state = radio . transmit ( pkt , sizeof ( pkt ) ) ;
transmitFlag = true ;
if ( state = = RADIOLIB_ERR_NONE ) {
} else {
DBG ( " failed, code " + String ( state ) ) ;
while ( true ) ;
}
transmitLoRaMsgwAck + + ;
unsigned long loraAckTimeout = millis ( ) + LORA_ACK_TIMEOUT ;
unsigned long loraAckTimeout = millis ( ) + FDRS _ACK_TIMEOUT;
retries - - ;
delay ( 10 ) ;
while ( returnCRC = = CRC_NULL & & ( millis ( ) < loraAckTimeout ) ) {
returnCRC = get LoRa( ) ;
handle LoRa( ) ;
}
if ( returnCRC = = CRC_OK ) {
//DBG("LoRa ACK Received! CRC OK");
@ -320,9 +414,13 @@ void transmitLoRa(uint16_t* destMAC, DataReading * packet, uint8_t len) {
# else // Send and do not wait for ACK reply
DBG ( " Transmitting LoRa message of size " + String ( sizeof ( pkt ) ) + " bytes with CRC 0x " + String ( calcCRC , HEX ) + " to gateway 0x " + String ( * destMAC , HEX ) ) ;
//printLoraPacket(pkt,sizeof(pkt));
LoRa . beginPacket ( ) ;
LoRa . write ( ( uint8_t * ) & pkt , sizeof ( pkt ) ) ;
LoRa . endPacket ( ) ;
int state = radio . transmit ( pkt , sizeof ( pkt ) ) ;
transmitFlag = true ;
if ( state = = RADIOLIB_ERR_NONE ) {
} else {
DBG ( " failed, code " + String ( state ) ) ;
while ( true ) ;
}
transmitLoRaMsgwAck + + ;
# endif // LORA_ACK
# endif // USE_LORA
@ -348,19 +446,22 @@ void transmitLoRa(uint16_t* destMAC, SystemPacket* packet, uint8_t len) {
pkt [ len * sizeof ( SystemPacket ) + 5 ] = ( calcCRC & 0x00FF ) ;
DBG ( " Transmitting LoRa message of size " + String ( sizeof ( pkt ) ) + " bytes with CRC 0x " + String ( calcCRC , HEX ) + " to destination 0x " + String ( * destMAC , HEX ) ) ;
//printLoraPacket(pkt,sizeof(pkt));
LoRa . beginPacket ( ) ;
LoRa . write ( ( uint8_t * ) & pkt , sizeof ( pkt ) ) ;
LoRa . endPacket ( ) ;
int state = radio . startTransmit ( pkt , sizeof ( pkt ) ) ;
transmitFlag = true ;
if ( state = = RADIOLIB_ERR_NONE ) {
} else {
DBG ( " failed, code " + String ( state ) ) ;
while ( true ) ;
}
# endif // USE_LORA
}
// getLoRa for Sensors
// USED to get ACKs (SystemPacket type) from LoRa gateway at this point. May be used in the future to get other data
// Return type is crcResult struct - CRC_OK, CRC_BAD, CRC_NULL. CRC_NULL used for non-ack data
crcResult getLoRa ( ) {
# ifdef USE_LORA
int packetSize = LoRa. parsePacket ( ) ;
int packetSize = radio. getPacketLength ( ) ;
if ( ( packetSize - 6 ) % sizeof ( SystemPacket ) = = 0 & & packetSize > 0 ) { // packet size should be 6 bytes plus multiple of size of SystemPacket
uint8_t packet [ packetSize ] ;
uint16_t packetCRC = 0x0000 ; // CRC Extracted from received LoRa packet
@ -368,15 +469,15 @@ crcResult getLoRa() {
uint16_t sourceMAC = 0x0000 ;
uint16_t destMAC = 0x0000 ;
u int ln = ( packetSize - 6 ) / sizeof ( SystemPacket ) ;
unsigned int ln = ( packetSize - 6 ) / sizeof ( SystemPacket ) ;
SystemPacket receiveData [ ln ] ;
LoRa. readBytes ( ( uint8_t * ) & packet , packetSize ) ;
radio. readData ( ( uint8_t * ) & packet , packetSize ) ;
destMAC = ( packet [ 0 ] < < 8 ) | packet [ 1 ] ;
sourceMAC = ( packet [ 2 ] < < 8 ) | packet [ 3 ] ;
packetCRC = ( ( packet [ packetSize - 2 ] < < 8 ) | packet [ packetSize - 1 ] ) ;
DBG ( " Incoming LoRa. Size: " + String ( packetSize ) + " Bytes, RSSI: " + String ( LoRa. packetRssi ( ) ) + " dBm, SNR: " + String ( LoRa. packetSnr ( ) ) + " dB, PacketCRC: 0x " + String ( packetCRC , HEX ) ) ;
DBG ( " Incoming LoRa. Size: " + String ( packetSize ) + " Bytes, RSSI: " + String ( radio. getRSSI ( ) ) + " dBm, SNR: " + String ( radio. getSNR ( ) ) + " dB, PacketCRC: 0x " + String ( packetCRC , HEX ) ) ;
if ( destMAC = = LoRaAddress ) { // The packet is for us so let's process it
//printLoraPacket(packet,sizeof(packet));
for ( int i = 0 ; i < ( packetSize - 2 ) ; i + + ) { // Last 2 bytes of packet are the CRC so do not include them in calculation
@ -464,7 +565,6 @@ bool sendFDRS() {
DBG ( " Sending FDRS Packet! " ) ;
# ifdef USE_ESPNOW
esp_now_send ( gatewayAddress , ( uint8_t * ) & fdrsData , data_count * sizeof ( DataReading ) ) ;
esp_now_ack_flag = CRC_NULL ;
while ( esp_now_ack_flag = = CRC_NULL ) {
delay ( 0 ) ;
@ -476,7 +576,6 @@ bool sendFDRS() {
data_count = 0 ;
return false ;
}
# endif
# ifdef USE_LORA
transmitLoRa ( & gtwyAddress , fdrsData , data_count ) ;
@ -523,7 +622,6 @@ void sleepFDRS(int sleep_time) {
delay ( sleep_time * 1000 ) ;
}
void loopFDRS ( ) {
if ( is_added ) {
if ( ( millis ( ) - last_refresh ) > = gtwy_timeout ) {
@ -532,9 +630,6 @@ void loopFDRS() {
}
}
bool seekFDRS ( int timeout ) {
SystemPacket sys_packet = { . cmd = cmd_ping , . param = 0 } ;
# ifdef USE_ESPNOW
@ -550,14 +645,11 @@ bool seekFDRS(int timeout) {
}
}
return false ;
# endif
}
bool addFDRS ( int timeout , void ( * new_cb_ptr ) ( DataReading ) ) {
bool addFDRS ( int timeout , void ( * new_cb_ptr ) ( DataReading ) ) {
callback_ptr = new_cb_ptr ;
SystemPacket sys_packet = { . cmd = cmd_add , . param = 0 } ;
# ifdef USE_ESPNOW
esp_now_send ( gatewayAddress , ( uint8_t * ) & sys_packet , sizeof ( SystemPacket ) ) ;
@ -612,7 +704,6 @@ bool subscribeFDRS(uint16_t sub_id){
return true ;
}
}
DBG ( " No subscription could be established! " ) ;
return false ;