From 7d57a5f6c7d4321e57112aa786ccd6d146411671 Mon Sep 17 00:00:00 2001 From: jgromes Date: Sat, 18 Nov 2023 16:27:29 +0100 Subject: [PATCH] [LoRaWAN] Fixed example naming --- .../LoRaWAN_End_Device_Persistent.ino | 145 +++++++++++ .../LoRaWAN_End_Device_Reference.ino | 246 ++++++++++++++++++ 2 files changed, 391 insertions(+) create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino create mode 100644 examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino new file mode 100644 index 000000000..3c96fb913 --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Persistent/LoRaWAN_End_Device_Persistent.ino @@ -0,0 +1,145 @@ +/* + RadioLib LoRaWAN End Device Persistent Example + + This example assumes you have tried one of the OTAA or ABP + examples and are familiar with the required keys and procedures. + This example restores and saves a session such that you can use + deepsleep or survive power cycles. Before you start, you will + have to register your device at https://www.thethingsnetwork.org/ + and join the network using either OTAA or ABP. + Please refer to one of the other LoRaWAN examples for more + information regarding joining a network. + + NOTE: LoRaWAN requires storing some parameters persistently! + RadioLib does this by using EEPROM, by default + starting at address 0 and using 384 bytes. + If you already use EEPROM in your application, + you will have to either avoid this range, or change it + by setting a different start address by changing the value of + RADIOLIB_HAL_PERSISTENT_STORAGE_BASE macro, either + during build or in src/BuildOpt.h. + + 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/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // first we need to initialize the device storage + // this will reset all persistently stored parameters + // NOTE: This should only be done once prior to first joining a network! + // After wiping persistent storage, you will also have to reset + // the end device in TTN and perform the join procedure again! + // Here, a delay is added to make sure that during re-flashing + // the .wipe() is not triggered and the session is lost + //delay(5000); + //node.wipe(); + + // now we can start the activation + // Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + // uint64_t joinEUI = 0x12AD1011B0C0FFEE; + // uint64_t devEUI = 0x70B3D57ED005E120; + // uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + // 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + // uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + // 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + // state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + // after the device has been activated, + // the session can be restored without rejoining after device power cycle + // on EEPROM-enabled boards by calling "restore" + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.restore(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + +} + +// counter to keep track of transmitted packets +int count = 0; + +void loop() { + // send uplink to port 10 + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello World! #" + String(count++); + String strDown; + int state = node.sendReceive(strUp, 10, strDown); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("received a downlink!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // 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")); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("no downlink!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + node.saveSession(); + + // wait before sending another packet + // alternatively, call a deepsleep function here + // make sure to send the radio to sleep as well using radio.sleep() + delay(30000); +} diff --git a/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino new file mode 100644 index 000000000..c31752e7e --- /dev/null +++ b/examples/LoRaWAN/LoRaWAN_End_Device_Reference/LoRaWAN_End_Device_Reference.ino @@ -0,0 +1,246 @@ +/* + 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). + Please refer to the 'persistent' example once you are familiar + with LoRaWAN. + Running this examples REQUIRES you to check "Resets DevNonces" + on your LoRaWAN dashboard. Refer to the network's + documentation on how to do this. + + 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/ +*/ + +// include the library +#include + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// create the node instance on the EU-868 band +// using the radio module and the encryption key +// make sure you are using the correct band +// based on your geographical location! +LoRaWANNode node(&radio, &EU868); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // application identifier - pre-LoRaWAN 1.1.0, this was called appEUI + // when adding new end device in TTN, you will have to enter this number + // you can pick any number you want, but it has to be unique + uint64_t joinEUI = 0x12AD1011B0C0FFEE; + + // device identifier - this number can be anything + // when adding new end device in TTN, you can generate this number, + // or you can set any value you want, provided it is also unique + uint64_t devEUI = 0x70B3D57ED005E120; + + // select some encryption keys which will be used to secure the communication + // there are two of them - network key and application key + // because LoRaWAN uses AES-128, the key MUST be 16 bytes (or characters) long + + // network key is the ASCII string "topSecretKey1234" + uint8_t nwkKey[] = { 0x74, 0x6F, 0x70, 0x53, 0x65, 0x63, 0x72, 0x65, + 0x74, 0x4B, 0x65, 0x79, 0x31, 0x32, 0x33, 0x34 }; + + // application key is the ASCII string "aDifferentKeyABC" + uint8_t appKey[] = { 0x61, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, + 0x6E, 0x74, 0x4B, 0x65, 0x79, 0x41, 0x42, 0x43 }; + + // prior to LoRaWAN 1.1.0, only a single "nwkKey" is used + // when connecting to LoRaWAN 1.0 network, "appKey" will be disregarded + // and can be set to NULL + + // some frequency bands only use a subset of the available channels + // you can select the specific band or set the first channel and last channel + // for example, either of the following corresponds to US915 FSB2 in TTN + /* + node.selectSubband(2); + node.selectSubband(8, 15); + */ + + // now we can start the activation + // this can take up to 10 seconds, and requires a LoRaWAN gateway in range + // a specific starting-datarate can be selected in dynamic bands (e.g. EU868): + /* + uint8_t joinDr = 4; + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey, joinDr); + */ + Serial.print(F("[LoRaWAN] Attempting over-the-air activation ... ")); + state = node.beginOTAA(joinEUI, devEUI, nwkKey, appKey); + + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after the device has been activated, + // the session can be restored without rejoining after device power cycle + // on EEPROM-enabled boards by calling "restore" + /* + Serial.print(F("[LoRaWAN] Resuming previous session ... ")); + state = node.restore(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + */ + + // disable the ADR algorithm + node.setADR(false); + + // set a fixed datarate + node.setDatarate(5); + + // enable CSMA + // this tries to minimize packet loss by searching for a free channel + // before actually sending an uplink + node.setCSMA(6, 2, true); +} + +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); + + // retrieve the last uplink frame counter + uint32_t fcntUp = node.getFcntUp(); + + Serial.print(F("[LoRaWAN] Sending uplink packet ... ")); + String strUp = "Hello World! #" + String(fcntUp); + + // send a confirmed uplink to port 10 every 64th frame + if(fcntUp % 64 == 0) { + state = node.uplink(strUp, 10, true); + } else { + state = node.uplink(strUp, 10); + } + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // after uplink, you can call downlink(), + // to receive any possible reply from the server + // this function must be called within a few seconds + // after uplink to receive the downlink! + Serial.print(F("[LoRaWAN] Waiting for downlink ... ")); + String strDown; + + // you can also retrieve additional information about + // uplink or downlink by passing a reference to + // LoRaWANEvent_t structure + LoRaWANEvent_t event; + state = node.downlink(strDown, &event); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + + // print data of the packet (if there are any) + Serial.print(F("[LoRaWAN] Data:\t\t")); + if(strDown.length() > 0) { + Serial.println(strDown); + } else { + Serial.println(F("")); + } + + // 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] Direction:\t")); + if(event.dir == RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK) { + Serial.println(F("uplink")); + } else { + Serial.println(F("downlink")); + } + Serial.print(F("[LoRaWAN] Confirmed:\t")); + Serial.println(event.confirmed); + Serial.print(F("[LoRaWAN] Confirming:\t")); + Serial.println(event.confirming); + Serial.print(F("[LoRaWAN] Frequency:\t")); + Serial.print(event.freq, 3); + Serial.println(F(" MHz")); + Serial.print(F("[LoRaWAN] Output power:\t")); + Serial.print(event.power); + Serial.println(F(" dBm")); + Serial.print(F("[LoRaWAN] Frame count:\t")); + Serial.println(event.fcnt); + Serial.print(F("[LoRaWAN] Port:\t\t")); + Serial.println(event.port); + + Serial.print(radio.getFrequencyError()); + + } else if(state == RADIOLIB_ERR_RX_TIMEOUT) { + Serial.println(F("timeout!")); + + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + } + + // on EEPROM enabled boards, you can save the current session + // by calling "saveSession" which allows retrieving the session after reboot or deepsleep + /* + node.saveSession(); + */ + + // wait before sending another packet + delay(30000); +}