My First Dabbling with LoRa
Client Code
This is the client code. It simply generates a pseudo-random number and sends it to the gateway. The gateway then responds with the same number it received. If the number matches, the client beeps three times using the buzzer on pin A0.
I used this setup to do a quick and dirty range test. Using a USB battery bank, I walked around my property until the beeping stopped.
For the client, I'm using an Arduino Compatible Long Range LoRa Shield XC4392. A side note: pin 13 seems to be in use, so you can't use the onboard LED, hence the use of pin A0.
Code:
1/*
2 LoRa Simple Client for Arduino with Random Number Verification and LED Feedback:
3
4 This sketch sends a pseudo-random number to the server. The server is expected to
5 return the same number, and the client will verify if the response is correct.
6
7 The buzzer will beep if the response is correct. If the response is incorrect or there is a timeout, the buzzer will not sound.
8*/
9
10#include <SPI.h>
11#include <RH_RF95.h>
12
13RH_RF95 rf95;
14float frequency = 915.0;
15const int ledPin = A0;
16
17void setup() {
18 Serial.begin(9600);
19 pinMode(ledPin, OUTPUT);
20 digitalWrite(ledPin, LOW);
21 Serial.println("Start LoRa Client");
22
23 if (!rf95.init()) {
24 Serial.println("LoRa init failed");
25 }
26
27 rf95.setFrequency(frequency);
28 rf95.setTxPower(13);
29 rf95.setSpreadingFactor(7);
30 rf95.setSignalBandwidth(125000);
31 rf95.setCodingRate4(5);
32 randomSeed(analogRead(0));
33}
34
35void loop() {
36 Serial.println("Sending to LoRa Server...");
37 uint32_t randomNumber = random(1, 10000);
38
39 Serial.print("Generated Random Number: ");
40 Serial.println(randomNumber);
41
42 uint8_t data[4] = {
43 (randomNumber >> 24) & 0xFF,
44 (randomNumber >> 16) & 0xFF,
45 (randomNumber >> 8) & 0xFF,
46 randomNumber & 0xFF
47 };
48
49 rf95.send(data, sizeof(data));
50 rf95.waitPacketSent();
51
52 uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
53 uint8_t len = sizeof(buf);
54
55 if (rf95.waitAvailableTimeout(3000)) {
56 if (rf95.recv(buf, &len)) {
57 Serial.print("Received reply: ");
58 uint32_t receivedNumber = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
59 Serial.println(receivedNumber);
60
61 if (receivedNumber == randomNumber) {
62 Serial.println("Response is correct!");
63 blinkLED();
64 } else {
65 Serial.println("Response is incorrect!");
66 digitalWrite(ledPin, LOW);
67 }
68
69 Serial.print("RSSI: ");
70 Serial.println(rf95.lastRssi(), DEC);
71 } else {
72 Serial.println("Receive failed");
73 digitalWrite(ledPin, LOW);
74 }
75 } else {
76 Serial.println("No reply, is LoRa server running?");
77 digitalWrite(ledPin, LOW);
78 }
79
80 delay(5000);
81}
82
83void blinkLED() {
84 for (int i = 0; i < 3; i++) {
85 digitalWrite(ledPin, HIGH);
86 delay(50);
87 digitalWrite(ledPin, LOW);
88 delay(50);
89 }
90}
Gateway Code
This is the corresponding code for the gateway module. I'm using a Jaycar Duinotech Arduino Compatible Long Range LoRa IP Gateway XC4394, which is actually a LG01-N Single Channel LoRa IoT Gateway.
Code:
1/*
2 LoRa Simple Yun Server:
3 Support Devices: LG01.
4
5 Example sketch showing how to create a simple messaging server
6 using the RH_RF95 class. This class does not provide addressing
7 or reliability features, so it is ideal for simple applications
8 without complex messaging requirements.
9
10 Modified RadioHead library is required from:
11 https://github.com/dragino/RadioHead
12
13 Modified 16 11 2016 by Edwin Chen <support@dragino.com>
14*/
15
16#define BAUDRATE 115200
17#include <Console.h>
18#include <SPI.h>
19#include <RH_RF95.h>
20
21RH_RF95 rf95;
22int led = A2;
23float frequency = 915.0;
24
25void setup() {
26 pinMode(led, OUTPUT);
27 Bridge.begin(BAUDRATE);
28 Console.begin();
29 while (!Console);
30 Console.println("Start Sketch");
31
32 if (!rf95.init())
33 Console.println("LoRa radio init failed");
34
35 rf95.setFrequency(frequency);
36 rf95.setTxPower(13);
37 rf95.setSpreadingFactor(7);
38 rf95.setSignalBandwidth(125000);
39 rf95.setCodingRate4(5);
40 Console.print("Listening on frequency: ");
41 Console.println(frequency);
42}
43
44void loop() {
45 if (rf95.available()) {
46 uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
47 uint8_t len = sizeof(buf);
48
49 if (rf95.recv(buf, &len)) {
50 digitalWrite(led, HIGH);
51 RH_RF95::printBuffer("request: ", buf, len);
52 Console.print("Received request: ");
53 Console.println((char*)buf);
54 Console.print("Received payload (hex): ");
55 for (uint8_t i = 0; i < len; i++) {
56 Console.print(buf[i], HEX);
57 Console.print(" ");
58 }
59 Console.println();
60 Console.print("RSSI: ");
61 Console.println(rf95.lastRssi(), DEC);
62
63 uint8_t reply[len];
64 memcpy(reply, buf, len);
65
66 Console.print("Sent payload (hex): ");
67 for (uint8_t i = 0; i < len; i++) {
68 Console.print(reply[i], HEX);
69 Console.print(" ");
70 }
71 Console.println();
72
73 rf95.send(reply, len);
74 rf95.waitPacketSent();
75 Console.println("Reply sent");
76 digitalWrite(led, LOW);
77 } else {
78 Console.println("recv failed");
79 }
80 }
81}