Some help with lora please :-)

the example referenced in post 7 is complicated in that there are multiple slave nodes which transmit different structures

the following example is simpler in that only a single structure is used by all nodes
LoRa slave transmitter node 1
EDIT: edited structure and added more comments

// Lora transmit structure Node using Feather 32u4

#include <SPI.h>
#include <LoRa.h>

#define nodeID 1  //  <<< set up required node ID

// test packet - must match receiver
struct __attribute__((packed)) Struct1 {
  byte NodeID;  // ID of transmitting node
  int16_t seq;  // sequence number
  int16_t distance;
  float voltage;
  char text[20];
};
Struct1 struct1 = { nodeID, 0, 1, 4.5, "hello" };  // test data

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
  Serial.print("\nLoRa slave transmitter Node ID ");
  Serial.println(nodeID);
  // void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN);
  LoRa.setPins(8, 4, 7);  // for Lora 32u4
  if (!LoRa.begin(866E6)) {
    Serial.println("Starting LoRa failed!");
    while (1)
      ;
  }
  LoRa.onTxDone(onTxDone);    // setup transmit callback
  LoRa.onReceive(onReceive);  // setup receive callback
  LoRa_rxMode();
}

// poll for packets - check if packet received
void loop() {
  checkIfPacketReceived();        // if packet received process it
  checkIfPacketTransmitted();     // check if packet has been transmitted
 }

// set transmit mode
void LoRa_txMode() {
  LoRa.idle();             // set standby mode
  LoRa.disableInvertIQ();  // normal mode
}

// set receive mode
void LoRa_rxMode() {
  LoRa.disableInvertIQ();  // normal mode
  LoRa.receive();          // set receive mode
}

// ***************** code called when message transmitted  ********************
volatile bool transmittedPacketOK = false;  // set true when packet has been transmitted
// transmit finished -set flag
void onTxDone() {
  transmittedPacketOK = true;  // indicate Tx done
  LoRa_rxMode();               // set receive mode
}

// poll for packets - check if packet received
void checkIfPacketTransmitted(void) {
  if (!transmittedPacketOK) return;    // check if packet has been transmitted
  transmittedPacketOK = false;         // clear ready for next transmission
  Serial.print(" Node ");              // packet recived display data
  Serial.print(nodeID);
  Serial.print(" TxDone seq number ");
  Serial.print(" seq number ");
  Serial.print(struct1.seq);
  Serial.print(" distance = ");
  Serial.print(struct1.distance);
  Serial.print(" voltage = ");
  Serial.print(struct1.voltage);
  Serial.print(" text = ");
  Serial.println(struct1.text);
}

// ***************** code to receive a message ********************

volatile int packetReceived = 0;  // set when packet received
// receive packet - check it is a poll size 1 byte if not ignore
void onReceive(int packetSize) {
  if (packetSize != 1) return;  // if not a poll packet return
  packetReceived = packetSize;
}

// called to check if packet has been received - if so process it
void checkIfPacketReceived(void) {
  if (!packetReceived) return;  // if no packet has been received return
  Serial.print("Lora receive RSSI ");
  Serial.print(LoRa.packetRssi());
  Serial.print(" packet size ");
  Serial.print(packetReceived);
  byte nodeIDreceived = LoRa.read();  // read first byte
  Serial.print(" nodeID polled ");
  Serial.print(nodeIDreceived);
  if (nodeID == nodeIDreceived) {  // polled for this structID?
    Serial.println(" sending packet!");
    sendMessage();  // send a message
  } else Serial.println();
  packetReceived = 0;  // clear reday for next poll
}

// transmit a message packet
void sendMessage() {
  LoRa_txMode();          // set transmit mode
  struct1.seq++;          // increment packet sequence number
  struct1.distance += 1;  // setup next test values
  struct1.voltage += 1;
  struct1.text[4]++;
  //struct1.z[0] += 1;
  LoRa_txMode();                                  // set tx mode
  LoRa.beginPacket();                             // start packet
  LoRa.write((byte *)&struct1, sizeof(struct1));  // transmit packet
  // display packet contents
  //for (unsigned int i = 0; i < sizeof(struct);i++) {
  // Serial.print(' ');
  // Serial.print(((byte *) &struct1)[i]);
  //}
  LoRa.endPacket(true);  // finish packet and send it
}

LoRa Master receiver

// Lora master receiver using using Feather 32u4 - polled version

#include <SPI.h>
#include <LoRa.h>

// test packet - must match transmitter
struct __attribute__((packed)) Struct1 {
  byte NodeID;  // ID of transmitting node
  int16_t seq;  // sequence number
  int16_t distance;
  float voltage;
  char text[20];
} struct1;

// 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

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
  Serial.println("LoRa Receiver");
  // void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN);
  //LoRa.setPins(10, 9, 2);  // 10 for UNO, 53 for Mega
  LoRa.setPins(8, 4, 7);  // for Lora 32u4
  if (!LoRa.begin(866E6)) {
    Serial.println("Starting LoRa failed!");
    while (1)
      ;
  }
  Serial.println("\nLora Master Receiver started");
  LoRa.onReceive(onReceive);  // set receive callback
  LoRa_rxMode();              // set receive mode
}

void loop() {
  checkIfPacketReceived();  // if packet received process it
  pollNextSlave();          // check if time to poll next node
}

// 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
}

// ************* poll next slave node for data  ? ****************
void pollNextSlave(void) {
  static unsigned long timer = 0;       // used to time polling
  if (millis() - timer < 5000) return;  // check if time to poll next node
  timer = millis();                     // poll next slave - reset timer for next poll
  if (--polledOK[nodeIndex] == 0) {     // did last receive response?
    Serial.print("Node failed to respond to polling ID = ");
    Serial.println(nodeIDs[nodeIndex]);
    polledOK[nodeIndex] = 1;
  }
  Serial.print("polling ID = ");  // poll next node
  Serial.println(nodeIDs[nodeIndex]);
  //Serial.println(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
}

//***************code when packet is received ****************

volatile int packetReceived = 0;  // set when packet received
// receive packet
void onReceive(int packetSize) {
  packetReceived = packetSize;  // indicat packet received
}

// called to check if packet has been received - if so process it
void checkIfPacketReceived(void) {
  if (!packetReceived) return;  // if no packet has been received return
  Serial.print("Lora receive RSSI ");
  Serial.print(LoRa.packetRssi());
  Serial.print(" packet size ");
  Serial.print(packetReceived);
  LoRa.readBytes((byte *)&struct1, packetReceived);  // receive struct1 packet
  // display packet
  //for (int i = 0; i < packetSize; i++) {
  // Serial.print(' ');
  // Serial.print(((byte *) &struct1)[i]);
  // }
  Serial.print(" from Node ");  // display packet contents
  Serial.print(struct1.NodeID);
  Serial.print(" seq number ");
  Serial.print(struct1.seq);
  Serial.print(" distance 1 = ");
  Serial.print(struct1.distance);
  Serial.print(" voltage 1 = ");
  Serial.print(struct1.voltage);
  Serial.print(" text = ");
  Serial.println(struct1.text);
  checkSeqNumber(struct1.NodeID, struct1.seq);
  packetReceived = 0;  // clear for next time
}

// check received sequence number
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
}

a test run using two slave nodeID 1 and nodeID 2
LoRa slave transmitter Node ID 1 serial monitor output

LoRa slave transmitter Node ID 1
Lora receive RSSI -83 packet size 1 nodeID polled 2
Lora receive RSSI -79 packet size 1 nodeID polled 3
Lora receive RSSI -83 packet size 1 nodeID polled 1 sending packet!
 Node 1 TxDone seq number  seq number 1 distance = 2 voltage = 5.50 text = hellp
Lora receive RSSI -86 packet size 1 nodeID polled 2
Lora receive RSSI -83 packet size 1 nodeID polled 3
Lora receive RSSI -83 packet size 1 nodeID polled 1 sending packet!
 Node 1 TxDone seq number  seq number 2 distance = 3 voltage = 6.50 text = hellq
Lora receive RSSI -86 packet size 1 nodeID polled 2
Lora receive RSSI -79 packet size 1 nodeID polled 1 sending packet!
 Node 1 TxDone seq number  seq number 3 distance = 4 voltage = 7.50 text = hellr
Lora receive RSSI -79 packet size 1 nodeID polled 2
Lora receive RSSI -83 packet size 1 nodeID polled 3
Lora receive RSSI -83 packet size 1 nodeID polled 1 sending packet!
 Node 1 TxDone seq number  seq number 4 distance = 5 voltage = 8.50 text = hells
Lora receive RSSI -83 packet size 1 nodeID polled 2
Lora receive RSSI -83 packet size 1 nodeID polled 3
Lora receive RSSI -83 packet size 1 nodeID polled 1 sending packet!
 Node 1 TxDone seq number  seq number 5 distance = 6 voltage = 9.50 text = hellt

LoRa slave transmitter Node ID 2 serial monitor output

LoRa slave transmitter Node ID 2
Lora receive RSSI -117 packet size 1 nodeID polled 3
Lora receive RSSI -117 packet size 1 nodeID polled 1
Lora receive RSSI -117 packet size 1 nodeID polled 2 sending packet!
 Node 2 TxDone seq number  seq number 1 distance = 2 voltage = 5.50 text = hellp
Lora receive RSSI -117 packet size 1 nodeID polled 3
Lora receive RSSI -117 packet size 1 nodeID polled 1
Lora receive RSSI -116 packet size 1 nodeID polled 2 sending packet!
 Node 2 TxDone seq number  seq number 2 distance = 3 voltage = 6.50 text = hellq
Lora receive RSSI -116 packet size 1 nodeID polled 3
Lora receive RSSI -112 packet size 1 nodeID polled 1
Lora receive RSSI -117 packet size 1 nodeID polled 2 sending packet!
 Node 2 TxDone seq number  seq number 3 distance = 4 voltage = 7.50 text = hellr
Lora receive RSSI -112 packet size 1 nodeID polled 3
Lora receive RSSI -114 packet size 1 nodeID polled 1
Lora receive RSSI -117 packet size 1 nodeID polled 2 sending packet!
 Node 2 TxDone seq number  seq number 4 distance = 5 voltage = 8.50 text = hells
Lora receive RSSI -114 packet size 1 nodeID polled 3
Lora receive RSSI -113 packet size 1 nodeID polled 1
Lora receive RSSI -117 packet size 1 nodeID polled 2 sending packet!
 Node 2 TxDone seq number  seq number 5 distance = 6 voltage = 9.50 text = hellt
Lora receive RSSI -117 packet size 1 nodeID polled 3

LoRa master node serial monitor output

Lora Receiver started
polling ID = 1
Lora receive RSSI -65 packet size 29 from Node 1 seq number 3 distance 1 = 4 voltage 1 = 7.50 text = hellr
  seq number error expected 0 received 3  seq  errors 1
polling ID = 2
polling ID = 3
polling ID = 1
Lora receive RSSI -66 packet size 29 from Node 1 seq number 4 distance 1 = 5 voltage 1 = 8.50 text = hells
Node failed to respond to polling ID = 2
polling ID = 2
Lora receive RSSI -111 packet size 29 from Node 2 seq number 1 distance 1 = 2 voltage 1 = 5.50 text = hellp
  seq number error expected 0 received 1  seq  errors 2
Node failed to respond to polling ID = 3
polling ID = 3
polling ID = 1
Lora receive RSSI -65 packet size 29 from Node 1 seq number 5 distance 1 = 6 voltage 1 = 9.50 text = hellt
polling ID = 2
Lora receive RSSI -111 packet size 29 from Node 2 seq number 2 distance 1 = 3 voltage 1 = 6.50 text = hellq
Node failed to respond to polling ID = 3
polling ID = 3
polling ID = 1
Lora receive RSSI -65 packet size 29 from Node 1 seq number 6 distance 1 = 7 voltage 1 = 10.50 text = hellu
polling ID = 2
Lora receive RSSI -111 packet size 29 from Node 2 seq number 3 distance 1 = 4 voltage 1 = 7.50 text = hellr
Node failed to respond to polling ID = 3
polling ID = 3
polling ID = 1
Lora receive RSSI -65 packet size 29 from Node 1 seq number 7 distance 1 = 8 voltage 1 = 11.50 text = hellv
polling ID = 2
Lora receive RSSI -112 packet size 29 from Node 2 seq number 4 distance 1 = 5 voltage 1 = 8.50 text = hells
Node failed to respond to polling ID = 3
polling ID = 3
polling ID = 1
Lora receive RSSI -65 packet size 29 from Node 1 seq number 8 distance 1 = 9 voltage 1 = 12.50 text = hellw
polling ID = 2
Lora receive RSSI -112 packet size 29 from Node 2 seq number 5 distance 1 = 6 voltage 1 = 9.50 text = hellt
Node failed to respond to polling ID = 3
polling ID = 3
polling ID = 1
Lora receive RSSI -66 packet size 29 from Node 1 seq number 9 distance 1 = 10 voltage 1 = 13.50 text = hellx
polling ID = 2
Lora receive RSSI -111 packet size 29 from Node 2 seq number 6 distance 1 = 7 voltage 1 = 10.50 text = hellu
Node failed to respond to polling ID = 3

there are a couple of sequence errors reported on master startup as it synchronises with the slave nodes

to use polling each node must have a unique identifier so that it knows when a packet is received it is the intended recipent
in the abive example each sender node has a definition specifing its ID, e.g. node 1

#define nodeID 1      //  <<< set up required node ID

this is assigned by the programmer when programming each node

when the data structure used for communication is declared it has the NodeID as one of its members

// test packet - must match receiver
struct __attribute__((packed)) Struct1 {
  byte NodeID;  // ID of transmitting node
  int16_t seq;  // sequence number
  int16_t distance;
  float voltage;
  char text[20];
};

when the data stucture variable is defined the member NodeID is initialised

Struct1 struct1 = { nodeID, 0, 1, 4.5, "hello" }; // test data

i.e. the value if struct1.NodeID is initialised to nodeID (in this case 1)

the master node has a array containing is list of slave NodeIDs

byte nodeIDs[] = { 1, 2, 3 };   // list of nodeIDs to poll

which it loops thru transmitting a packet requesting data from each slave in turn

Although the above code is using Adafruit Feather 32u4 LoRa modules the basic concepts can be used for other LoRa and radio modules which transmit and receive packets

1 Like