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