master for Nano using LCD - the display of received data is executed in loop() avoiding crashes due to calling LCD functions in callback functions
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <LoRa.h>
#include <SPI.h>
#include <LoRa.h>
// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x3F, 16, 2);
// three different structures may be received
struct __attribute__((packed)) Struct1 {
byte StructureID; // identifies the structure type
byte NodeID; // ID of transmitting node
int16_t seq; // sequence number
float distance;
float voltage;
//char z[10];
} struct1;
struct __attribute__((packed)) Struct2 {
byte StructureID; // identifies the structure type
byte NodeID; // ID of transmitting node
int16_t seq; // sequence number
float distance;
float voltage;
} struct2;
struct __attribute__((packed)) Struct3 {
byte StructureID; // identifies the structure type
byte NodeID; // ID of transmitting node
int16_t seq; // sequence number
float distance;
float voltage;
} struct3;
// used for polling
byte nodeIDs[] = { 1, 2, 3 }; // list of nodeIDs to poll
byte polledOK[] = { 2, 2, 2 }; // indicate polling sucess/failure
int nodeIndex = 0; // index into above arrays
// function prototypes
void onReceive(int packetSize);
void LoRa_rxMode();
void LoRa_txMode();
void onRxDataReceived(void);
void setup() {
lcd.init();
lcd.backlight();
lcd.print("LoRa RA-02 Rx");
Serial.begin(115200);
while (!Serial)
;
Serial.println("LoRa Receiver");
//lcd.print ("I'm working!");
if (!LoRa.begin(433E6)) {
Serial.println("Starting LoRa failed!");
}
Serial.println("Lora Receiver started");
LoRa.onReceive(onReceive); // set receive callback
LoRa_rxMode(); // set receive mode
}
void loop() { // polling nodes
static long timer = millis();
if (millis() - timer > 5000) {
timer = millis();
if (--polledOK[nodeIndex] == 0) { // did last receive response?
Serial.print("Node failed to respons to polling ID = ");
Serial.println(nodeIDs[nodeIndex]);
polledOK[nodeIndex] = 1;
}
Serial.print("polling ID = "); // poll next node
Serial.println(nodeIDs[nodeIndex]);
LoRa_txMode(); // set to transmit
LoRa.beginPacket(); // start packet
LoRa.write(nodeIDs[nodeIndex]); // transmit packet
LoRa.endPacket(true); // finish packet and send it
if (++nodeIndex >= sizeof(nodeIDs)) nodeIndex = 0;
LoRa_rxMode(); // set receive mode
}
onRxDataReceived(); // check if data received
}
// set receive mode
void LoRa_rxMode() {
LoRa.disableInvertIQ(); // normal mode
LoRa.receive(); // set receive mode
}
// set transmit mode
void LoRa_txMode() {
LoRa.idle(); // set standby mode
LoRa.disableInvertIQ(); // normal mode
}
// set transmit mode
void checkSeqNumber(int NodeID, int seq) {
static int seqNumbers[] = { 0, 0, 0, 0 }, seqErrors = 0;
if (NodeID >= sizeof(seqNumbers) / sizeof(int)) return;
if (seq != seqNumbers[NodeID]) { // check for sequence error!
Serial.print(" seq number error expected ");
Serial.print(seqNumbers[NodeID]);
Serial.print(" received ");
Serial.print(seq);
Serial.print(" seq errors ");
Serial.println(++seqErrors);
seqNumbers[NodeID] = seq;
}
seqNumbers[NodeID]++; // next sequence nunber expected
polledOK[NodeID - 1] = 2; // indicate polling sucess
}
volatile int onRxData = 0; // set when data is received
// receive packet
void onReceive(int packetSize) {
onRxData = packetSize; // set to indivcate data received
}
void onRxDataReceived(void) {
if (onRxData == 0) return; // if data received
int packetSize = onRxData; // process it
onRxData = 0;
Serial.print("Lora receive RSSI ");
Serial.print(LoRa.packetRssi());
Serial.print(" packet size ");
Serial.print(packetSize);
byte structureID = LoRa.read(); // read first byte the structure ID
// switch to correct structure to decode
switch (structureID) {
case 1:
LoRa.readBytes((byte *)&struct1 + 1, packetSize - 1); // receive struct1 packet
struct1.StructureID = structureID;
Serial.println(" Tank 1 ");
Serial.print(struct1.seq);
Serial.print(" distance 1 = ");
Serial.print(struct1.distance);
Serial.print(" voltage 1 = ");
Serial.println(struct1.voltage);
Serial.println();
checkSeqNumber(struct1.NodeID, struct1.seq);
lcd.setCursor(0, 0); //First line
lcd.print("distance 1 = ");
lcd.print(struct1.distance);
lcd.setCursor(0, 1); //second line
lcd.print("voltage 1 = ");
lcd.print(struct1.voltage);
break;
case 2:
LoRa.readBytes((byte *)&struct2 + 1, packetSize - 1); // receive struct2 packet
struct2.StructureID = structureID;
Serial.print(" Tank 2 ");
Serial.print(" distance 2 = ");
Serial.print(struct2.distance);
Serial.print("voltage 2 = ");
Serial.println(struct2.voltage);
checkSeqNumber(struct2.NodeID, struct2.seq);
lcd.setCursor(0, 0); //First line
lcd.print("distance 2 = ");
lcd.print(struct2.distance);
lcd.setCursor(0, 1); //second line
lcd.print(" voltage 2 = ");
lcd.print(struct2.voltage);
break;
case 3:
LoRa.readBytes((byte *)&struct3 + 1, packetSize - 1); // receive struct3 packet
struct3.StructureID = structureID;
Serial.print(" Tank 3 ");
Serial.print(" distance 3 = ");
Serial.println(struct3.distance);
Serial.print(" voltage 3 = ");
Serial.println(struct3.voltage);
checkSeqNumber(struct3.NodeID, struct3.seq);
lcd.clear();
lcd.setCursor(0, 0); //First line
lcd.print("distance 3 = ");
lcd.print(struct3.distance);
lcd.setCursor(0, 1); //second line lcd.print(" voltage 3 = ");
lcd.print("voltage 3 = ");
lcd.print(struct3.voltage);
}
}
serial monitor
polling ID = 1
Lora receive RSSI -121 packet size 12 Tank 1
120 distance 1 = 121.00 voltage 1 = 124.50
Node failed to respons to polling ID = 2
polling ID = 2
Node failed to respons to polling ID = 3
polling ID = 3
polling ID = 1
Lora receive RSSI -121 packet size 12 Tank 1
121 distance 1 = 122.00 voltage 1 = 125.50
LCD displays
