Decimals, strings, and LoRa

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