@ -88,7 +88,7 @@ uint8_t gatewayAddress[] = {MAC_PREFIX, GTWY_MAC};
uint16_t gtwyAddress = ( ( gatewayAddress [ 4 ] < < 8 ) | GTWY_MAC ) ;
uint16_t gtwyAddress = ( ( gatewayAddress [ 4 ] < < 8 ) | GTWY_MAC ) ;
# ifdef USE_LORA
# ifdef USE_LORA
uint16_t LoRaAddress = ( ( UniqueID8 [ 6 ] < < 8 ) | UniqueID8 [ 7 ] ) ;
uint16_t LoRaAddress = ( ( UniqueID8 [ 6 ] < < 8 ) | UniqueID8 [ 7 ] ) ;
unsigned long transmitLoRaMsg = 0 ; // Number of total LoRa packets destined for us and of valid size
unsigned long transmitLoRaMsg wAck = 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
unsigned long msgOkLoRa = 0 ; // Number of total LoRa packets with valid CRC
# endif
# endif
uint32_t gtwy_timeout = 0 ;
uint32_t gtwy_timeout = 0 ;
@ -265,56 +265,84 @@ static uint16_t crc16_update(uint16_t crc, uint8_t a) {
return crc ;
return crc ;
}
}
// USED to get ACKs from LoRa gateway at this point. May be used in the future to get other data
// 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
// Return type is crcResult struct - CRC_OK, CRC_BAD, CRC_NULL. CRC_NULL used for non-ack data
crcResult getLoRa ( ) {
crcResult getLoRa ( ) {
# ifdef USE_LORA
# ifdef USE_LORA
int packetSize = LoRa . parsePacket ( ) ;
int packetSize = LoRa . parsePacket ( ) ;
if ( ( packetSize - 6 ) % sizeof ( SystemPacket ) = = 0 & & packetSize > 0 ) { // packet size should be 6 bytes plus multiple of size of SystemPacket
if ( ( packetSize - 6 ) % sizeof ( SystemPacket ) = = 0 & & packetSize > 0 ) { // packet size should be 6 bytes plus multiple of size of SystemPacket
uint8_t packet [ packetSize ] ;
uint8_t packet [ packetSize ] ;
uint16_t sourceMAC = 0x0000 ;
uint16_t destMAC = 0x0000 ;
uint16_t packetCRC = 0x0000 ; // CRC Extracted from received LoRa packet
uint16_t packetCRC = 0x0000 ; // CRC Extracted from received LoRa packet
uint16_t calcCRC = 0x0000 ; // CRC calculated from received LoRa packet
uint16_t calcCRC = 0x0000 ; // CRC calculated from received LoRa packet
uint16_t sourceMAC = 0x0000 ;
uint16_t destMAC = 0x0000 ;
uint ln = ( packetSize - 6 ) / sizeof ( SystemPacket ) ;
uint ln = ( packetSize - 6 ) / sizeof ( SystemPacket ) ;
SystemPacket receiveData [ ln ] ;
SystemPacket receiveData [ ln ] ;
LoRa . readBytes ( ( uint8_t * ) & packet , packetSize ) ;
LoRa . readBytes ( ( uint8_t * ) & packet , packetSize ) ;
destMAC = ( packet [ 0 ] < < 8 ) | packet [ 1 ] ;
destMAC = ( packet [ 0 ] < < 8 ) | packet [ 1 ] ;
sourceMAC = ( packet [ 2 ] < < 8 ) | packet [ 3 ] ;
sourceMAC = ( packet [ 2 ] < < 8 ) | packet [ 3 ] ;
packetCRC = ( ( packet [ packetSize - 2 ] < < 8 ) | packet [ packetSize - 1 ] ) ;
packetCRC = ( ( packet [ packetSize - 2 ] < < 8 ) | packet [ packetSize - 1 ] ) ;
DBG ( " Incoming LoRa. Size: " + String ( packetSize ) + " Bytes, RSSI: " + String ( LoRa . packetRssi ( ) ) + " dB i , SNR: " + String ( LoRa . packetSnr ( ) ) + " dB, PacketCRC: 0x " + String ( packetCRC , 16 ) ) ;
DBG ( " Incoming LoRa. Size: " + String ( packetSize ) + " Bytes, RSSI: " + String ( LoRa . packetRssi ( ) ) + " dB m , SNR: " + String ( LoRa . packetSnr ( ) ) + " dB, PacketCRC: 0x " + String ( packetCRC , HEX ) ) ;
if ( destMAC = = LoRaAddress ) {
if ( destMAC = = LoRaAddress ) { // The packet is for us so let's process it
//printLoraPacket(packet,sizeof(packet));
//printLoraPacket(packet,sizeof(packet));
memcpy ( receiveData , & packet [ 4 ] , packetSize - 6 ) ; //Split off data portion of packet (N bytes)
for ( int i = 0 ; i < ( packetSize - 2 ) ; i + + ) { // Last 2 bytes of packet are the CRC so do not include them in calculation
if ( ln = = 1 & & receiveData [ 0 ] . cmd = = cmd_ack ) { // We have received an ACK packet
//printf("CRC: %02X : %d\n",calcCRC, i);
if ( packetCRC = = 0xFFFF ) {
calcCRC = crc16_update ( calcCRC , packet [ i ] ) ;
DBG ( " ACK Received - address 0x " + String ( sourceMAC , 16 ) + " (hex) does not want ACKs " ) ;
}
return CRC_OK ;
if ( calcCRC = = packetCRC ) {
memcpy ( receiveData , & packet [ 4 ] , packetSize - 6 ) ; //Split off data portion of packet (N bytes)
if ( ln = = 1 & & receiveData [ 0 ] . cmd = = cmd_ack ) {
DBG ( " ACK Received - CRC Match " ) ;
}
}
else {
else if ( ln = = 1 & & receiveData [ 0 ] . cmd = = cmd_ping ) { // We have received a ping request or reply??
for ( int i = 0 ; i < ( packetSize - 2 ) ; i + + ) { // Last 2 bytes of packet are the CRC so do not include them in calculation
if( receiveData [ 0 ] . param = = 1 ) { // This is a reply to our ping request
//printf("CRC: %02X : %d\n",calcCRC, i);
is_ping = true ;
calcCRC = crc16_update ( calcCRC , packet [ i ] ) ;
DBG ( " We have received a ping reply via LoRa from address 0x " + String ( sourceMAC , HEX ) ) ;
}
}
if ( calcCRC = = packetCRC ) {
else if ( receiveData [ 0 ] . param = = 0 ) {
DBG ( " ACK Received - CRC Match " ) ;
DBG ( " We have received a ping request from 0x " + String ( sourceMAC , HEX ) + " , Replying. " ) ;
return CRC_OK ;
SystemPacket pingReply = { . cmd = cmd_ping , . param = 1 } ;
transmitLoRa ( & sourceMAC , & pingReply , 1 ) ;
}
}
else {
}
DBG ( " ACK Received CRC Mismatch! Packet CRC is 0x " + String ( packetCRC , 16 ) + " , Calculated CRC is 0x " + String ( calcCRC , 16 ) ) ;
else { // data we have received is not yet programmed. How we handle is future enhancement.
return CRC_BAD ;
DBG ( " Received some LoRa SystemPacket data that is not yet handled. To be handled in future enhancement. " ) ;
DBG ( " ln: " + String ( ln ) + " data type: " + String ( receiveData [ 0 ] . cmd ) ) ;
}
return CRC_OK ;
}
else if ( packetCRC = = crc16_update ( calcCRC , 0xA1 ) ) { // Sender does not want ACK and CRC is valid
memcpy ( receiveData , & packet [ 4 ] , packetSize - 6 ) ; //Split off data portion of packet (N bytes)
if ( ln = = 1 & & receiveData [ 0 ] . cmd = = cmd_ack ) {
DBG ( " ACK Received - CRC Match " ) ;
}
else if ( ln = = 1 & & receiveData [ 0 ] . cmd = = cmd_ping ) { // We have received a ping request or reply??
if ( receiveData [ 0 ] . param = = 1 ) { // This is a reply to our ping request
is_ping = true ;
DBG ( " We have received a ping reply via LoRa from address 0x " + String ( sourceMAC , HEX ) ) ;
}
else if ( receiveData [ 0 ] . param = = 0 ) {
DBG ( " We have received a ping request from 0x " + String ( sourceMAC , HEX ) + " , Replying. " ) ;
SystemPacket pingReply = { . cmd = cmd_ping , . param = 1 } ;
transmitLoRa ( & sourceMAC , & pingReply , 1 ) ;
}
}
}
}
else { // data we have received is not yet programmed. How we handle is future enhancement.
DBG ( " Received some LoRa SystemPacket data that is not yet handled. To be handled in future enhancement. " ) ;
DBG ( " ln: " + String ( ln ) + " data type: " + String ( receiveData [ 0 ] . cmd ) ) ;
}
return CRC_OK ;
}
}
else { // data we have received is not of type ACK_T. How we handle is future enhancement.
else {
DBG ( " Received some LoRa SystemPacket data that is not of type ACK. To be handled in future enhancement. " ) ;
DBG ( " ACK Received CRC Mismatch! Packet CRC is 0x " + String ( packetCRC , HEX ) + " , Calculated CRC is 0x " + String ( calcCRC , HEX ) ) ;
DBG ( " ln: " + String ( ln ) + " data type: " + String ( receiveData [ 0 ] . cmd ) ) ;
return CRC_BAD ;
return CRC_NULL ;
}
}
}
}
else if ( ( packetSize - 6 ) % sizeof ( DataReading ) = = 0 ) { // packet size should be 6 bytes plus multiple of size of DataReading)
else if ( ( packetSize - 6 ) % sizeof ( DataReading ) = = 0 & & packetSize > 0 ) { // packet size should be 6 bytes plus multiple of size of DataReading)
DBG ( " Incoming LoRa packet of " + String ( packetSize ) + " bytes received, with DataReading data to be processed. " ) ;
DBG ( " Incoming LoRa packet of " + String ( packetSize ) + " bytes received, with DataReading data to be processed. " ) ;
return CRC_NULL ;
return CRC_NULL ;
}
}
@ -323,25 +351,17 @@ crcResult getLoRa() {
return CRC_NULL ;
return CRC_NULL ;
}
}
}
}
else {
else {
if ( packetSize ! = 0 ) {
if ( packetSize ! = 0 ) {
DBG ( " Incoming LoRa packet of " + String ( packetSize ) + " bytes received " ) ;
DBG ( " Incoming LoRa packet of " + String ( packetSize ) + " bytes received " ) ;
return CRC_NULL ;
}
}
}
}
return CRC_NULL ;
return CRC_NULL ;
# endif
# endif
}
}
void printLoraPacket ( uint8_t * p , int size ) {
void transmitLoRa ( uint16_t * destMAC , DataReading * packet , uint8_t len ) {
printf ( " Printing packet of size %d. " , size ) ;
for ( int i = 0 ; i < size ; i + + ) {
if ( i % 2 = = 0 ) printf ( " \n %02d: " , i ) ;
printf ( " %02X " , p [ i ] ) ;
}
printf ( " \n " ) ;
}
bool transmitLoRa ( uint16_t * destMAC , DataReading * packet , uint8_t len ) {
# ifdef USE_LORA
# ifdef USE_LORA
uint8_t pkt [ 6 + ( len * sizeof ( DataReading ) ) ] ;
uint8_t pkt [ 6 + ( len * sizeof ( DataReading ) ) ] ;
uint16_t calcCRC = 0x0000 ;
uint16_t calcCRC = 0x0000 ;
@ -351,7 +371,7 @@ bool transmitLoRa(uint16_t* destMAC, DataReading * packet, uint8_t len) {
pkt [ 2 ] = ( LoRaAddress > > 8 ) ;
pkt [ 2 ] = ( LoRaAddress > > 8 ) ;
pkt [ 3 ] = ( LoRaAddress & 0x00FF ) ;
pkt [ 3 ] = ( LoRaAddress & 0x00FF ) ;
memcpy ( & pkt [ 4 ] , packet , len * sizeof ( DataReading ) ) ;
memcpy ( & pkt [ 4 ] , packet , len * sizeof ( DataReading ) ) ;
for ( int i = 0 ; i < ( sizeof ( pkt ) - 2 ) ; i + + ) { // Last 2 bytes are CRC so do not include them in the calculation itself
for ( int i = 0 ; i < ( sizeof ( pkt ) - 2 ) ; i + + ) { // Last 2 bytes are CRC so do not include them in the calculation itself
//printf("CRC: %02X : %d\n",calcCRC, i);
//printf("CRC: %02X : %d\n",calcCRC, i);
calcCRC = crc16_update ( calcCRC , pkt [ i ] ) ;
calcCRC = crc16_update ( calcCRC , pkt [ i ] ) ;
}
}
@ -362,50 +382,83 @@ bool transmitLoRa(uint16_t* destMAC, DataReading * packet, uint8_t len) {
pkt [ len * sizeof ( DataReading ) + 5 ] = ( calcCRC & 0x00FF ) ;
pkt [ len * sizeof ( DataReading ) + 5 ] = ( calcCRC & 0x00FF ) ;
# ifdef LORA_ACK // Wait for ACK
# ifdef LORA_ACK // Wait for ACK
int retries = LORA_RETRIES + 1 ;
int retries = LORA_RETRIES + 1 ;
while ( retries ! = 0 ) {
while ( retries ! = 0 ) {
if ( transmitLoRaMsg ! = 0 ) {
if ( transmitLoRaMsgwAck ! = 0 )
DBG ( " Transmitting LoRa message of size " + String ( sizeof ( pkt ) ) + " bytes with CRC 0x " + String ( calcCRC , 16 ) + " to gateway 0x " + String ( * destMAC , 16 ) + " . Retries remaining: " + String ( retries - 1 ) + " , CRC OK " + String ( ( float ) msgOkLoRa / transmitLoRaMsg * 100 ) + " % " ) ;
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 {
else
DBG ( " Transmitting LoRa message of size " + String ( sizeof ( pkt ) ) + " bytes with CRC 0x " + String ( calcCRC , 16 ) + " to gateway 0x " + String ( * destMAC , 16 ) + " . Retries remaining: " + String ( retries - 1 ) ) ;
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));
//printLoraPacket(pkt,sizeof(pkt));
LoRa . beginPacket ( ) ;
LoRa . beginPacket ( ) ;
LoRa . write ( ( uint8_t * ) & pkt , sizeof ( pkt ) ) ;
LoRa . write ( ( uint8_t * ) & pkt , sizeof ( pkt ) ) ;
LoRa . endPacket ( ) ;
LoRa . endPacket ( ) ;
transmitLoRaMsg + + ;
transmitLoRaMsg wAck + + ;
unsigned long loraAckTimeout = millis ( ) + LORA_ACK_TIMEOUT ;
unsigned long loraAckTimeout = millis ( ) + LORA_ACK_TIMEOUT ;
retries - - ;
retries - - ;
delay ( 10 ) ;
delay ( 10 ) ;
while ( returnCRC = = CRC_NULL & & ( millis ( ) < loraAckTimeout ) ) {
while ( returnCRC = = CRC_NULL & & ( millis ( ) < loraAckTimeout ) ) {
returnCRC = getLoRa ( ) ;
returnCRC = getLoRa ( ) ;
}
}
if ( returnCRC = = CRC_OK ) {
if ( returnCRC = = CRC_OK ) {
//DBG("LoRa ACK Received! CRC OK");
//DBG("LoRa ACK Received! CRC OK");
msgOkLoRa + + ;
msgOkLoRa + + ;
return true ; // we're done
return ; // we're done
}
}
else if ( returnCRC = = CRC_BAD ) {
else if ( returnCRC = = CRC_BAD ) {
//DBG("LoRa ACK Received! CRC BAD");
//DBG("LoRa ACK Received! CRC BAD");
// Resend original packet again if retries are available
// Resend original packet again if retries are available
}
}
else {
else {
DBG ( " LoRa Timeout waiting for ACK! " ) ;
DBG ( " LoRa Timeout waiting for ACK! " ) ;
// resend original packet again if retries are available
// resend original packet again if retries are available
}
}
}
}
return false ;
# else // Send and do not wait for ACK reply
# else // Send and do not wait for ACK reply
DBG ( " Transmitting LoRa message of size " + String ( sizeof ( pkt ) ) + " bytes with CRC 0x " + String ( calcCRC , 16 ) + " to gateway 0x " + String ( * destMAC , 16 ) ) ;
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));
//printLoraPacket(pkt,sizeof(pkt));
LoRa . beginPacket ( ) ;
LoRa . beginPacket ( ) ;
LoRa . write ( ( uint8_t * ) & pkt , sizeof ( pkt ) ) ;
LoRa . write ( ( uint8_t * ) & pkt , sizeof ( pkt ) ) ;
LoRa . endPacket ( ) ;
LoRa . endPacket ( ) ;
transmitLoRaMsg + + ;
transmitLoRaMsgwAck + + ;
return true ;
# endif // LORA_ACK
# endif // LORA_ACK
# endif // USE_LORA
# endif // USE_LORA
}
}
// For now SystemPackets will not use ACK but will calculate CRC
void transmitLoRa ( uint16_t * destMAC , SystemPacket * packet , uint8_t len ) {
# ifdef USE_LORA
uint8_t pkt [ 6 + ( len * sizeof ( SystemPacket ) ) ] ;
uint16_t calcCRC = 0x0000 ;
pkt [ 0 ] = ( * destMAC > > 8 ) ;
pkt [ 1 ] = ( * destMAC & 0x00FF ) ;
pkt [ 2 ] = ( LoRaAddress > > 8 ) ;
pkt [ 3 ] = ( LoRaAddress & 0x00FF ) ;
memcpy ( & pkt [ 4 ] , packet , len * sizeof ( SystemPacket ) ) ;
for ( int i = 0 ; i < ( sizeof ( pkt ) - 2 ) ; i + + ) { // Last 2 bytes are CRC so do not include them in the calculation itself
//printf("CRC: %02X : %d\n",calcCRC, i);
calcCRC = crc16_update ( calcCRC , pkt [ i ] ) ;
}
calcCRC = crc16_update ( calcCRC , 0xA1 ) ; // Recalculate CRC for No ACK
pkt [ len * sizeof ( SystemPacket ) + 4 ] = ( calcCRC > > 8 ) ;
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 ( ) ;
# endif // USE_LORA
}
void printLoraPacket ( uint8_t * p , int size ) {
printf ( " Printing packet of size %d. " , size ) ;
for ( int i = 0 ; i < size ; i + + ) {
if ( i % 2 = = 0 ) printf ( " \n %02d: " , i ) ;
printf ( " %02X " , p [ i ] ) ;
}
printf ( " \n " ) ;
}
bool sendFDRS ( ) {
bool sendFDRS ( ) {
DBG ( " Sending FDRS Packet! " ) ;
DBG ( " Sending FDRS Packet! " ) ;
# ifdef USE_ESPNOW
# ifdef USE_ESPNOW
@ -425,17 +478,12 @@ bool sendFDRS() {
# endif
# endif
# ifdef USE_LORA
# ifdef USE_LORA
if ( transmitLoRa ( & gtwyAddress , fdrsData , data_count ) ) {
transmitLoRa ( & gtwyAddress , fdrsData , data_count ) ;
data_count = 0 ;
DBG ( " LoRa sent. " ) ;
returnCRC = CRC_NULL ;
data_count = 0 ;
return true ;
returnCRC = CRC_NULL ;
} else {
data_count = 0 ;
returnCRC = CRC_NULL ;
return false ;
}
# endif
# endif
return fals e;
return true ;
}
}
void loadFDRS ( float d , uint8_t t ) {
void loadFDRS ( float d , uint8_t t ) {