/******************************************************************************* | |
* Copyright (c) 2015 Thomas Telkamp and Matthijs Kooijman | |
* Copyright (c) 2018 Terry Moore, MCCI | |
* | |
* 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. It's pre-configured for the Adafruit | |
* Feather M0 LoRa. | |
* | |
* 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 | |
* arduino-lmic/project_config/lmic_project_config.h or from your BOARDS.txt. | |
* | |
*******************************************************************************/ | |
#include <lmic.h> | |
#include <hal/hal.h> | |
#include <SPI.h> | |
static const u1_t PROGMEM APPEUI[8]= {0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22}; | |
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]= {0xd6,0xe5,0x86,0x69,0xad,0x1b,0x72,0x96}; | |
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 the TTN console can be copied as-is. | |
static const u1_t PROGMEM APPKEY[16] = { 0x58,0x0c,0x7a,0xc9,0x85,0x95,0x99,0xf2,0xca,0xcb,0x79,0x15,0x0a,0x45,0x6f,0x39 }; | |
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);} | |
static uint8_t mydata[] = "Hello, world!"; | |
static osjob_t sendjob; | |
// Schedule TX every this many seconds (might become longer due to duty | |
// cycle limitations). | |
const unsigned TX_INTERVAL = 60; | |
const lmic_pinmap lmic_pins = { | |
.nss = 8, | |
.rxtx = LMIC_UNUSED_PIN, | |
.rst = 4, | |
.dio = {3, 6, LMIC_UNUSED_PIN}, | |
.rxtx_rx_active = 0, | |
.rssi_cal = 8, // LBT cal for the Adafruit Feather M0 LoRa, in dB | |
.spi_freq = 8000000, | |
}; | |
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")); | |
{ | |
u4_t netid = 0; | |
devaddr_t devaddr = 0; | |
u1_t nwkKey[16]; | |
u1_t artKey[16]; | |
LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey); | |
Serial.print("netid: "); | |
Serial.println(netid, DEC); | |
Serial.print("devaddr: "); | |
Serial.println(devaddr, HEX); | |
Serial.print("artKey: "); | |
for (int i=0; i<sizeof(artKey); ++i) { | |
if (i != 0) | |
Serial.print("-"); | |
Serial.print(artKey[i], HEX); | |
} | |
Serial.println(""); | |
Serial.print("nwkKey: "); | |
for (int i=0; i<sizeof(nwkKey); ++i) { | |
if (i != 0) | |
Serial.print("-"); | |
Serial.print(nwkKey[i], HEX); | |
} | |
Serial.println(""); | |
} | |
// Disable link check validation (automatically enabled | |
// during join, but because slow data rates change max TX | |
// size, we don't use it in this example. | |
LMIC_setLinkCheckMode(0); | |
break; | |
/* | |
|| This event is defined but not used in the code. No | |
|| point in wasting codespace on it. | |
|| | |
|| 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; | |
/* | |
|| This event is defined but not used in the code. No | |
|| point in wasting codespace on it. | |
|| | |
|| case EV_SCAN_FOUND: | |
|| Serial.println(F("EV_SCAN_FOUND")); | |
|| break; | |
*/ | |
case EV_TXSTART: | |
Serial.println(F("EV_TXSTART")); | |
break; | |
default: | |
Serial.print(F("Unknown event: ")); | |
Serial.println((unsigned) ev); | |
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 { | |
// Prepare upstream data transmission at the next possible time. | |
LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0); | |
Serial.println(F("Packet queued")); | |
} | |
// Next TX is scheduled after TX_COMPLETE event. | |
} | |
void setup() { | |
delay(5000); | |
while (! Serial) | |
; | |
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 | |
// LMIC init | |
os_init(); | |
// Reset the MAC state. Session and pending data transfers will be discarded. | |
LMIC_reset(); | |
LMIC_setLinkCheckMode(0); | |
LMIC_setDrTxpow(DR_SF7,14); | |
LMIC_selectSubBand(1); | |
// Start job (sending automatically starts OTAA too) | |
do_send(&sendjob); | |
} | |
void loop() { | |
os_runloop_once(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment