From 436ab3def7911949917a49d92ee0bbc0865fefac Mon Sep 17 00:00:00 2001 From: Kent Williams Date: Mon, 1 Feb 2021 17:38:23 -0800 Subject: [PATCH] add feather m0 rfm95 example --- .../longfi-us915-cayenne-dht22/README.md | 37 +++ .../longfi-us915-cayenne-dht22/config.h | 83 ++++++ .../longfi-us915-cayenne-dht22.ino | 254 ++++++++++++++++++ 3 files changed, 374 insertions(+) create mode 100644 Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/README.md create mode 100644 Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/config.h create mode 100644 Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/longfi-us915-cayenne-dht22.ino diff --git a/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/README.md b/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/README.md new file mode 100644 index 0000000..daf9271 --- /dev/null +++ b/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/README.md @@ -0,0 +1,37 @@ +# Adafruit Feather M0 RFM95 - DHT22 CayenneLPP Example + +[Quickstart Guide](https://docs.helium.com/use-the-network/devices/development/adafruit-feather-m0-rfm95/adafruitio) +[Adafruit Feather M0 with RFM95 Product Page](https://www.adafruit.com/product/3178) +[Adafruit Feather M0 with RFM95 Datasheets & Files](https://learn.adafruit.com/adafruit-feather-m0-radio-with-lora-radio-module/downloads). + +## Required Arduino Libraries + +### Important +Make sure you do not have other LMIC arduino libraries installed, otherwise you will experience +build errors. You can find your Arduino libraries for your operating system below, simply delete the directory if you would like to remove a library. + +linux: /home/{user}/Arduino/libraries +windows: Documents/Arduino/libraries +mac os: Documents/Arduino/libraries + +From the Arduino IDE, open the Library Manager (Sketch->Include Library->Manage Libraries). In the search box, type the library name below and install version `1.5.0+arduino-2`. + +[IBM LMIC framework](https://github.com/matthijskooijman/arduino-lmic) + +Next, search for and install both `CayenneLPP` and `DHT sensor library` + +[CayenneLPP](https://github.com/ElectronicCats/CayenneLPP) +[DHT sensor library](https://github.com/adafruit/DHT-sensor-library) + +### Required Configuration +This library requires that a config file be setup properly. After you have installed the `IBM LMIC framework` library, navigate to it's directory on your operating system found below. Next, replace the `config.h` file in this directory with this [config.h](https://github.com/helium/longfi-arduino/blob/master/Sparkfun-Pro-RF/longfi-us915/config.h) file. + +linux: /home/{user}/Arduino/libraries/IBM_LMIC_framework/src/lmic +windows: Documents/Arduino/libraries/IBM_LMIC_framework/src/lmic +mac os: Documents/Arduino/libraries/IBM_LMIC_framework/src/lmic + +## Required Arduino Board Support + +1. Install Arduino SAMD Support, instructions [here](https://learn.adafruit.com/adafruit-feather-m0-radio-with-lora-radio-module/using-with-arduino-ide#install-samd-support-6-5). +2. Install Adafruit SAMD Support, instructions [here](https://learn.adafruit.com/adafruit-feather-m0-radio-with-lora-radio-module/using-with-arduino-ide#install-adafruit-samd-6-7). +3. (Windows 7 & 8 Only) Install drivers, instructions [here](https://learn.adafruit.com/adafruit-feather-m0-radio-with-lora-radio-module/using-with-arduino-ide#install-drivers-windows-7-and-8-only-6-11) diff --git a/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/config.h b/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/config.h new file mode 100644 index 0000000..62da07f --- /dev/null +++ b/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/config.h @@ -0,0 +1,83 @@ +#ifndef _lmic_config_h_ +#define _lmic_config_h_ + +// In the original LMIC code, these config values were defined on the +// gcc commandline. Since Arduino does not allow easily modifying the +// compiler commandline, use this file instead. + +// #define CFG_eu868 1 +#define CFG_us915 1 +// This is the SX1272/SX1273 radio, which is also used on the HopeRF +// RFM92 boards. +//#define CFG_sx1272_radio 1 +// This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on +// the HopeRF RFM95 boards. +#define CFG_sx1276_radio 1 + +// 16 μs per tick +// LMIC requires ticks to be 15.5μs - 100 μs long +#define US_PER_OSTICK_EXPONENT 4 +#define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT) +#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK) + +// Set this to 1 to enable some basic debug output (using printf) about +// RF settings used during transmission and reception. Set to 2 to +// enable more verbose output. Make sure that printf is actually +// configured (e.g. on AVR it is not by default), otherwise using it can +// cause crashing. +#define LMIC_DEBUG_LEVEL 0 + +// Enable this to allow using printf() to print to the given serial port +// (or any other Print object). This can be easy for debugging. The +// current implementation only works on AVR, though. +//#define LMIC_PRINTF_TO Serial + +// Any runtime assertion failures are printed to this serial port (or +// any other Print object). If this is unset, any failures just silently +// halt execution. +#define LMIC_FAILURE_TO Serial + +// Uncomment this to disable all code related to joining +//#define DISABLE_JOIN +// Uncomment this to disable all code related to ping +//#define DISABLE_PING +// Uncomment this to disable all code related to beacon tracking. +// Requires ping to be disabled too +//#define DISABLE_BEACONS + +// Uncomment these to disable the corresponding MAC commands. +// Class A +//#define DISABLE_MCMD_DCAP_REQ // duty cycle cap +//#define DISABLE_MCMD_DN2P_SET // 2nd DN window param +//#define DISABLE_MCMD_SNCH_REQ // set new channel +// Class B +//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING +//#define DISABLE_MCMD_BCNI_ANS // next beacon start, automatical disabled by DISABLE_BEACON + +// In LoRaWAN, a gateway applies I/Q inversion on TX, and nodes do the +// same on RX. This ensures that gateways can talk to nodes and vice +// versa, but gateways will not hear other gateways and nodes will not +// hear other nodes. By uncommenting this macro, this inversion is +// disabled and this node can hear other nodes. If two nodes both have +// this macro set, they can talk to each other (but they can no longer +// hear gateways). This should probably only be used when debugging +// and/or when talking to the radio directly (e.g. like in the "raw" +// example). +//#define DISABLE_INVERT_IQ_ON_RX + +// This allows choosing between multiple included AES implementations. +// Make sure exactly one of these is uncommented. +// +// This selects the original AES implementation included LMIC. This +// implementation is optimized for speed on 32-bit processors using +// fairly big lookup tables, but it takes up big amounts of flash on the +// AVR architecture. +// #define USE_ORIGINAL_AES +// +// This selects the AES implementation written by Ideetroon for their +// own LoRaWAN library. It also uses lookup tables, but smaller +// byte-oriented ones, making it use a lot less flash space (but it is +// also about twice as slow as the original). +#define USE_IDEETRON_AES + +#endif // _lmic_config_h_ diff --git a/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/longfi-us915-cayenne-dht22.ino b/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/longfi-us915-cayenne-dht22.ino new file mode 100644 index 0000000..dd29cdc --- /dev/null +++ b/Adafruit-Feather-M0-RFM95/longfi-us915-cayenne-dht22/longfi-us915-cayenne-dht22.ino @@ -0,0 +1,254 @@ +/******************************************************************************* + * Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman + * + * Permission is hereby granted, free of charge, to anyone + * obtaining a copy of this document and accompanying files, + * to do whatever they want with them without any restriction, + * including, but not limited to, copying, modification and redistribution. + * NO WARRANTY OF ANY KIND IS PROVIDED. + * + * This example sends a valid LoRaWAN packet with payload "Hello, + * world!", using frequency and encryption settings matching those of + * the The Things Network. + * + * This uses OTAA (Over-the-air activation), where where a DevEUI and + * application key is configured, which are used in an over-the-air + * activation procedure where a DevAddr and session keys are + * assigned/generated for use with all further communication. + * + * Note: LoRaWAN per sub-band duty-cycle limitation is enforced (1% in + * g1, 0.1% in g2), but not the TTN fair usage policy (which is probably + * violated by this sketch when left running for longer)! + + * To use this sketch, first register your application and device with + * the things network, to set or generate an AppEUI, DevEUI and AppKey. + * Multiple devices can use the same AppEUI, but each device has its own + * DevEUI and AppKey. + * + * Do not forget to define the radio type correctly in config.h. + * + *******************************************************************************/ +#include +#include +#include + +#include +#include +#include + +#include + +#define DHTPIN 12 +#define DHTTYPE DHT22 // DHT 22 (AM2302) + +DHT_Unified dht(DHTPIN, DHTTYPE); + +// Init CayenneLPP Payload +CayenneLPP lpp(51); + +// This EUI must be in little-endian format, so least-significant-byte +// first. When copying an EUI from ttnctl output, this means to reverse +// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, +// 0x70. +static const u1_t PROGMEM APPEUI[8]={ FILL_ME_IN }; +void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);} + +// This should also be in little endian format, see above. +static const u1_t PROGMEM DEVEUI[8]={ FILL_ME_IN }; +void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);} + +// This key should be in big endian format (or, since it is not really a +// number but a block of memory, endianness does not really apply). In +// practice, a key taken from ttnctl can be copied as-is. +// The key shown here is the semtech default key. +static const u1_t PROGMEM APPKEY[16] = { FILL_ME_IN }; +void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);} + +static osjob_t sendjob; + +// Schedule TX every this many seconds (might become longer due to duty +// cycle limitations). +const unsigned TX_INTERVAL = 20; + +// Pin mapping +const lmic_pinmap lmic_pins = { + .nss = 8, + .rxtx = LMIC_UNUSED_PIN, + .rst = 4, + .dio = {3, 6, 2}, +}; + +void onEvent (ev_t ev) { + Serial.print(os_getTime()); + Serial.print(": "); + switch(ev) { + case EV_SCAN_TIMEOUT: + Serial.println(F("EV_SCAN_TIMEOUT")); + break; + case EV_BEACON_FOUND: + Serial.println(F("EV_BEACON_FOUND")); + break; + case EV_BEACON_MISSED: + Serial.println(F("EV_BEACON_MISSED")); + break; + case EV_BEACON_TRACKED: + Serial.println(F("EV_BEACON_TRACKED")); + break; + case EV_JOINING: + Serial.println(F("EV_JOINING")); + break; + case EV_JOINED: + Serial.println(F("EV_JOINED")); + + // Disable link check validation (automatically enabled + // during join, but not supported by TTN at this time). + LMIC_setLinkCheckMode(0); + break; + case EV_RFU1: + Serial.println(F("EV_RFU1")); + break; + case EV_JOIN_FAILED: + Serial.println(F("EV_JOIN_FAILED")); + break; + case EV_REJOIN_FAILED: + Serial.println(F("EV_REJOIN_FAILED")); + break; + break; + case EV_TXCOMPLETE: + Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); + if (LMIC.txrxFlags & TXRX_ACK) + Serial.println(F("Received ack")); + if (LMIC.dataLen) { + Serial.println(F("Received ")); + Serial.println(LMIC.dataLen); + Serial.println(F(" bytes of payload")); + } + // Schedule next transmission + os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send); + break; + case EV_LOST_TSYNC: + Serial.println(F("EV_LOST_TSYNC")); + break; + case EV_RESET: + Serial.println(F("EV_RESET")); + break; + case EV_RXCOMPLETE: + // data received in ping slot + Serial.println(F("EV_RXCOMPLETE")); + break; + case EV_LINK_DEAD: + Serial.println(F("EV_LINK_DEAD")); + break; + case EV_LINK_ALIVE: + Serial.println(F("EV_LINK_ALIVE")); + break; + default: + Serial.println(F("Unknown event")); + break; + } +} + +void do_send(osjob_t* j){ + // Check if there is not a current TX/RX job running + if (LMIC.opmode & OP_TXRXPEND) { + Serial.println(F("OP_TXRXPEND, not sending")); + } else { + + // Clear Payload + lpp.reset(); + + // Get temperature event and print its value. + sensors_event_t event; + dht.temperature().getEvent(&event); + if (isnan(event.temperature)) { + Serial.println(F("Error reading temperature!")); + } + else { + Serial.print(F("Temperature: ")); + Serial.print(event.temperature); + Serial.println(F("°C")); + + lpp.addTemperature(1, event.temperature); + } + // Get humidity event and print its value. + dht.humidity().getEvent(&event); + if (isnan(event.relative_humidity)) { + Serial.println(F("Error reading humidity!")); + } + else { + Serial.print(F("Humidity: ")); + Serial.print(event.relative_humidity); + Serial.println(F("%")); + + lpp.addRelativeHumidity(2, event.relative_humidity); + } + + // Prepare upstream data transmission at the next possible time. + LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0); + Serial.println(F("Packet queued")); + } + // Next TX is scheduled after TX_COMPLETE event. +} + +void setup() { + Serial.begin(9600); + Serial.println(F("Starting")); + + #ifdef VCC_ENABLE + // For Pinoccio Scout boards + pinMode(VCC_ENABLE, OUTPUT); + digitalWrite(VCC_ENABLE, HIGH); + delay(1000); + #endif + + // Initialize DHT22. + dht.begin(); + Serial.println(F("DHTxx Unified Sensor Example")); + // Print temperature sensor details. + sensor_t sensor; + dht.temperature().getSensor(&sensor); + Serial.println(F("------------------------------------")); + Serial.println(F("Temperature Sensor")); + Serial.print (F("Sensor Type: ")); Serial.println(sensor.name); + Serial.print (F("Driver Ver: ")); Serial.println(sensor.version); + Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id); + Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("°C")); + Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("°C")); + Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("°C")); + Serial.println(F("------------------------------------")); + // Print humidity sensor details. + dht.humidity().getSensor(&sensor); + Serial.println(F("Humidity Sensor")); + Serial.print (F("Sensor Type: ")); Serial.println(sensor.name); + Serial.print (F("Driver Ver: ")); Serial.println(sensor.version); + Serial.print (F("Unique ID: ")); Serial.println(sensor.sensor_id); + Serial.print (F("Max Value: ")); Serial.print(sensor.max_value); Serial.println(F("%")); + Serial.print (F("Min Value: ")); Serial.print(sensor.min_value); Serial.println(F("%")); + Serial.print (F("Resolution: ")); Serial.print(sensor.resolution); Serial.println(F("%")); + Serial.println(F("------------------------------------")); + + // LMIC init + os_init(); + // Reset the MAC state. Session and pending data transfers will be discarded. + LMIC_reset(); + + // allow much more clock error than the X/1000 default. See: + // https://github.com/mcci-catena/arduino-lorawan/issues/74#issuecomment-462171974 + // https://github.com/mcci-catena/arduino-lmic/commit/42da75b56#diff-16d75524a9920f5d043fe731a27cf85aL633 + // the X/1000 means an error rate of 0.1%; the above issue discusses using + // values up to 10%. so, values from 10 (10% error, the most lax) to 1000 + // (0.1% error, the most strict) can be used. + LMIC_setClockError(1 * MAX_CLOCK_ERROR / 40); + + // Sub-band 2 - Helium Network + LMIC_selectSubBand(1); // zero indexed + LMIC_setLinkCheckMode(0); + LMIC_setDrTxpow(DR_SF7, 14); + + // Start job (sending automatically starts OTAA too) + do_send(&sendjob); +} + +void loop() { + os_runloop_once(); +} \ No newline at end of file