kopia lustrzana https://github.com/helium/longfi-arduino
237 wiersze
7.3 KiB
Arduino
237 wiersze
7.3 KiB
Arduino
|
#include <lmic.h>
|
||
|
#include <hal/hal.h>
|
||
|
#include <SPI.h>
|
||
|
|
||
|
|
||
|
// This should also be in little endian format
|
||
|
static const u1_t PROGMEM DEVEUI[8]= { FILL_ME_IN };
|
||
|
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}
|
||
|
|
||
|
// This should also be in little endian format
|
||
|
static const u1_t PROGMEM APPEUI[8]= { FILL_ME_IN };
|
||
|
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}
|
||
|
|
||
|
// This key should be in big endian format
|
||
|
static const u1_t PROGMEM APPKEY[16] = { FILL_ME_IN };
|
||
|
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}
|
||
|
|
||
|
static uint8_t mydata[] = {0};
|
||
|
static osjob_t sendjob;
|
||
|
|
||
|
// Schedule TX every this many seconds (might become longer due to duty
|
||
|
// cycle limitations).
|
||
|
const unsigned TX_INTERVAL = 15;
|
||
|
|
||
|
// Pin mapping
|
||
|
#include "arduino_lmic_hal_boards.h"
|
||
|
// Pin mapping Discovery
|
||
|
const lmic_pinmap lmic_pins = *Arduino_LMIC::GetPinmap_Disco_L072cz_Lrwan1();
|
||
|
|
||
|
void printHex2(unsigned v) {
|
||
|
v &= 0xff;
|
||
|
if (v < 16)
|
||
|
Serial.print('0');
|
||
|
Serial.print(v, HEX);
|
||
|
}
|
||
|
|
||
|
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("AppSKey: ");
|
||
|
for (size_t i=0; i<sizeof(artKey); ++i) {
|
||
|
if (i != 0)
|
||
|
Serial.print("-");
|
||
|
printHex2(artKey[i]);
|
||
|
}
|
||
|
Serial.println("");
|
||
|
Serial.print("NwkSKey: ");
|
||
|
for (size_t i=0; i<sizeof(nwkKey); ++i) {
|
||
|
if (i != 0)
|
||
|
Serial.print("-");
|
||
|
printHex2(nwkKey[i]);
|
||
|
}
|
||
|
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;
|
||
|
case EV_TXCANCELED:
|
||
|
Serial.println(F("EV_TXCANCELED"));
|
||
|
break;
|
||
|
case EV_RXSTART:
|
||
|
/* do not print anything -- it wrecks timing */
|
||
|
break;
|
||
|
case EV_JOIN_TXCOMPLETE:
|
||
|
Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));
|
||
|
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 update packet"));
|
||
|
} else {
|
||
|
mydata[0] = 0;
|
||
|
// Prepare upstream data transmission at the next possible time.
|
||
|
LMIC_setTxData2(1, mydata, sizeof(mydata), 0);
|
||
|
Serial.println(F("Packet queued: Update Send"));
|
||
|
}
|
||
|
// Next TX is scheduled after TX_COMPLETE event.
|
||
|
}
|
||
|
|
||
|
bool async_send(){
|
||
|
// Check if there is not a current TX/RX job running
|
||
|
if (LMIC.opmode & OP_TXRXPEND) {
|
||
|
Serial.println(F("OP_TXRXPEND, not sending async send yet"));
|
||
|
return true;
|
||
|
} else {
|
||
|
mydata[0] = 1;
|
||
|
// Prepare upstream data transmission at the next possible time.
|
||
|
LMIC_setTxData2(1, mydata, sizeof(mydata), 0);
|
||
|
Serial.println(F("Packet queued: Async Send"));
|
||
|
return false;
|
||
|
}
|
||
|
// Next TX is scheduled after TX_COMPLETE event.
|
||
|
}
|
||
|
|
||
|
static volatile bool button_pushed;
|
||
|
|
||
|
void push_button_ISR(){
|
||
|
button_pushed = true;
|
||
|
}
|
||
|
|
||
|
void setup() {
|
||
|
Serial.begin(9600);
|
||
|
Serial.println("Starting");
|
||
|
|
||
|
SPI.setMOSI(RADIO_MOSI_PORT);
|
||
|
SPI.setMISO(RADIO_MISO_PORT);
|
||
|
SPI.setSCLK(RADIO_SCLK_PORT);
|
||
|
SPI.setSSEL(RADIO_NSS_PORT);
|
||
|
|
||
|
// Configure User Button
|
||
|
pinMode(USER_BTN, INPUT_PULLUP);
|
||
|
attachInterrupt(digitalPinToInterrupt(USER_BTN), push_button_ISR, HIGH);
|
||
|
|
||
|
Serial.println("Setup Complete");
|
||
|
|
||
|
// 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);
|
||
|
|
||
|
LMIC_setLinkCheckMode(0);
|
||
|
LMIC_setDrTxpow(DR_SF7,14);
|
||
|
LMIC_selectSubBand(6);
|
||
|
|
||
|
// Start job (sending automatically starts OTAA too)
|
||
|
do_send(&sendjob);
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
void loop() {
|
||
|
if(button_pushed) {
|
||
|
button_pushed = async_send();
|
||
|
}
|
||
|
os_runloop_once();
|
||
|
}
|