201 lines
6.7 KiB
C++
201 lines
6.7 KiB
C++
/*
|
|
RadioLib LoRaWAN End Device Reference Example
|
|
|
|
This example joins a LoRaWAN network and will send
|
|
uplink packets. Before you start, you will have to
|
|
register your device at https://www.thethingsnetwork.org/
|
|
After your device is registered, you can run this example.
|
|
The device will join the network and start uploading data.
|
|
|
|
Also, most of the possible and available functions are
|
|
shown here for reference.
|
|
|
|
LoRaWAN v1.1 requires the use of EEPROM (persistent storage).
|
|
Running this examples REQUIRES you to check "Resets DevNonces"
|
|
on your LoRaWAN dashboard. Refer to the notes or the
|
|
network's documentation on how to do this.
|
|
To comply with LoRaWAN v1.1's persistent storage, refer to
|
|
https://github.com/radiolib-org/radiolib-persistence
|
|
|
|
For default module settings, see the wiki page
|
|
https://github.com/jgromes/RadioLib/wiki/Default-configuration
|
|
|
|
For full API reference, see the GitHub Pages
|
|
https://jgromes.github.io/RadioLib/
|
|
|
|
For LoRaWAN details, see the wiki page
|
|
https://github.com/jgromes/RadioLib/wiki/LoRaWAN
|
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
// include the library
|
|
#include <RadioLib.h>
|
|
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
while (!Serial); // Wait for serial to be initalised
|
|
delay(5000); // Give time to switch to the serial monitor
|
|
Serial.println(F("\nSetup"));
|
|
|
|
int16_t state = 0; // return value for calls to RadioLib
|
|
|
|
Serial.println(F("Initalise the radio"));
|
|
state = radio.begin();
|
|
debug(state != RADIOLIB_ERR_NONE, F("Initalise radio failed"), state, true);
|
|
|
|
// Override the default join rate
|
|
// uint8_t joinDR = 3;
|
|
|
|
Serial.println(F("Join ('login') to the LoRaWAN Network"));
|
|
state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, true);
|
|
debug(state < RADIOLIB_ERR_NONE, F("Join failed"), state, true);
|
|
|
|
// Print the DevAddr
|
|
Serial.print("[LoRaWAN] DevAddr: ");
|
|
Serial.println(node.getDevAddr(), HEX);
|
|
|
|
// Disable the ADR algorithm (on by default which is preferable)
|
|
node.setADR(false);
|
|
|
|
// Set a fixed datarate & make it persistent (not normal)
|
|
node.setDatarate(4);
|
|
|
|
// Enable CSMA which tries to minimize packet loss by searching
|
|
// for a free channel before actually sending an uplink
|
|
node.setCSMA(6, 2, true);
|
|
|
|
// Manages uplink intervals to the TTN Fair Use Policy
|
|
node.setDutyCycle(true, 1250);
|
|
|
|
// Enable the dwell time limits - 400ms is the limit for the US
|
|
node.setDwellTime(true, 400);
|
|
|
|
Serial.println(F("Ready!\n"));
|
|
} // setup
|
|
|
|
|
|
void loop() {
|
|
int state = RADIOLIB_ERR_NONE;
|
|
|
|
// set battery fill level - the LoRaWAN network server
|
|
// may periodically request this information
|
|
// 0 = external power source
|
|
// 1 = lowest (empty battery)
|
|
// 254 = highest (full battery)
|
|
// 255 = unable to measure
|
|
uint8_t battLevel = 146;
|
|
node.setDeviceStatus(battLevel);
|
|
|
|
|
|
// Read some inputs
|
|
uint8_t Digital1 = digitalRead(2);
|
|
uint16_t Analog1 = analogRead(A0);
|
|
|
|
// Build payload byte array
|
|
uint8_t uplinkPayload[3];
|
|
uplinkPayload[0] = Digital1;
|
|
uplinkPayload[1] = highByte(Analog1); // See notes for high/lowByte functions
|
|
uplinkPayload[2] = lowByte(Analog1);
|
|
|
|
uint8_t downlinkPayload[10]; // Make sure this fits your plans!
|
|
size_t downlinkSize; // To hold the actual payload size rec'd
|
|
|
|
// you can also retrieve additional information about an uplink or
|
|
// downlink by passing a reference to LoRaWANEvent_t structure
|
|
LoRaWANEvent_t uplinkDetails;
|
|
LoRaWANEvent_t downlinkDetails;
|
|
|
|
uint8_t Port = 10;
|
|
|
|
// Retrieve the last uplink frame counter
|
|
uint32_t fcntUp = node.getFcntUp();
|
|
// Send a confirmed uplink every 64th frame
|
|
// and also request the LinkCheck and DeviceTime MAC commands
|
|
if(fcntUp % 64 == 0) {
|
|
Serial.println(F("[LoRaWAN] Requesting LinkCheck and DeviceTime"));
|
|
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK);
|
|
node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME);
|
|
state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails);
|
|
} else {
|
|
state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), Port, downlinkPayload, &downlinkSize);
|
|
}
|
|
debug((state != RADIOLIB_ERR_RX_TIMEOUT) && (state != RADIOLIB_ERR_NONE), F("Error in sendReceive"), state, false);
|
|
|
|
if(state == RADIOLIB_ERR_NONE) {
|
|
// Did we get a downlink with data for us
|
|
if (downlinkSize > 0) {
|
|
Serial.println(F("Downlink data: "));
|
|
arrayDump(downlinkPayload, downlinkSize);
|
|
} else {
|
|
Serial.println(F("<MAC commands only>"));
|
|
}
|
|
|
|
// print RSSI (Received Signal Strength Indicator)
|
|
Serial.print(F("[LoRaWAN] RSSI:\t\t"));
|
|
Serial.print(radio.getRSSI());
|
|
Serial.println(F(" dBm"));
|
|
|
|
// print SNR (Signal-to-Noise Ratio)
|
|
Serial.print(F("[LoRaWAN] SNR:\t\t"));
|
|
Serial.print(radio.getSNR());
|
|
Serial.println(F(" dB"));
|
|
|
|
// print frequency error
|
|
Serial.print(F("[LoRaWAN] Frequency error:\t"));
|
|
Serial.print(radio.getFrequencyError());
|
|
Serial.println(F(" Hz"));
|
|
|
|
// print extra information about the event
|
|
Serial.println(F("[LoRaWAN] Event information:"));
|
|
Serial.print(F("[LoRaWAN] Confirmed:\t"));
|
|
Serial.println(downlinkDetails.confirmed);
|
|
Serial.print(F("[LoRaWAN] Confirming:\t"));
|
|
Serial.println(downlinkDetails.confirming);
|
|
Serial.print(F("[LoRaWAN] Datarate:\t"));
|
|
Serial.println(downlinkDetails.datarate);
|
|
Serial.print(F("[LoRaWAN] Frequency:\t"));
|
|
Serial.print(downlinkDetails.freq, 3);
|
|
Serial.println(F(" MHz"));
|
|
Serial.print(F("[LoRaWAN] Output power:\t"));
|
|
Serial.print(downlinkDetails.power);
|
|
Serial.println(F(" dBm"));
|
|
Serial.print(F("[LoRaWAN] Frame count:\t"));
|
|
Serial.println(downlinkDetails.fcnt);
|
|
Serial.print(F("[LoRaWAN] Port:\t\t"));
|
|
Serial.println(downlinkDetails.port);
|
|
|
|
uint8_t margin = 0;
|
|
uint8_t gwCnt = 0;
|
|
if(node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) {
|
|
Serial.print(F("[LoRaWAN] LinkCheck margin:\t"));
|
|
Serial.println(margin);
|
|
Serial.print(F("[LoRaWAN] LinkCheck count:\t"));
|
|
Serial.println(gwCnt);
|
|
}
|
|
|
|
uint32_t networkTime = 0;
|
|
uint8_t fracSecond = 0;
|
|
if(node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) {
|
|
Serial.print(F("[LoRaWAN] DeviceTime Unix:\t"));
|
|
Serial.println(networkTime);
|
|
Serial.print(F("[LoRaWAN] DeviceTime second:\t1/"));
|
|
Serial.println(fracSecond);
|
|
}
|
|
|
|
}
|
|
|
|
// wait before sending another packet
|
|
uint32_t minimumDelay = uplinkIntervalSeconds * 1000UL;
|
|
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per FUP & law!)
|
|
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
|
|
|
|
Serial.print(F("[LoRaWAN] Next uplink in "));
|
|
Serial.print(delayMs/1000);
|
|
Serial.println(F("s"));
|
|
|
|
delay(delayMs);
|
|
|
|
} // loop
|