First commit
This commit is contained in:
commit
c270086b31
3 changed files with 1511 additions and 0 deletions
449
GasSensor/GasSensor.ino
Normal file
449
GasSensor/GasSensor.ino
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
#include "rn2xx3.h"
|
||||
#include <SoftwareSerial.h>
|
||||
#include <string.h>
|
||||
#include <MsTimer2.h>
|
||||
#include <avr/sleep.h>
|
||||
|
||||
#define LED_OFF HIGH
|
||||
#define LED_ON LOW
|
||||
|
||||
#define MESURE_PERIOD 30
|
||||
|
||||
|
||||
/* DECLARATION DES PINs */
|
||||
const int pinGasSensor = A0;
|
||||
|
||||
|
||||
const int pinInterruptUp = 2;
|
||||
const int pinInterruptDown = 3;
|
||||
|
||||
const int pinRedLED = 4;
|
||||
const int pinBlueLED = 5;
|
||||
const int pinGreenLED = 6;
|
||||
const int pinYellowLED = 7;
|
||||
|
||||
const int pinBuzzer = 9;
|
||||
|
||||
const int pinRX = 10;
|
||||
const int pinTX = 11;
|
||||
const int pinRST = 12;
|
||||
/* FIN DECLARATION DES PINs */
|
||||
|
||||
/* SELECTION DES MODULES UTILISES */
|
||||
const bool useLoRa = true;
|
||||
const bool useLEDs = true;
|
||||
const bool useBuzzer = true;
|
||||
const bool useInterrupts = true;
|
||||
const bool usePeriodic = false;
|
||||
const bool usePowerSaveMode = false;
|
||||
/* FIN SELECTION DES MODULES UTILISES */
|
||||
|
||||
/* VARIABLES GLOBALE D'ETAT */
|
||||
volatile bool gasDetected = false;
|
||||
volatile bool endGasDetected = false;
|
||||
volatile bool lecture = false;
|
||||
/* FIN VARIABLES GLOBALE D'ETAT */
|
||||
|
||||
/* DECLARATION DES VARIABLES GLOBALES */
|
||||
SoftwareSerial mySerial(pinRX, pinTX); // RX, TX
|
||||
rn2xx3 myLora(mySerial);
|
||||
/* FIN DECLARATION DES VARIABLES GLOBALES */
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/************* DEBUT DU SETUP *************/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
|
||||
/* Fonction de setup du module LoRa */
|
||||
void setupLoRa(boolean used) {
|
||||
if (used) {
|
||||
mySerial.begin(9600); //serial port to radio
|
||||
|
||||
//reset rn2483
|
||||
pinMode(pinRST, OUTPUT);
|
||||
digitalWrite(pinRST, LOW);
|
||||
delay(500);
|
||||
digitalWrite(pinRST, HIGH);
|
||||
delay(100); //wait for the RN2xx3's startup message
|
||||
mySerial.flush();
|
||||
|
||||
//Autobaud the rn2483 module to 9600. The default would otherwise be 57600.
|
||||
myLora.autobaud();
|
||||
|
||||
//check communication with radio
|
||||
String hweui = myLora.hweui();
|
||||
while(hweui.length() != 16)
|
||||
{
|
||||
Serial.println("Communication with RN2xx3 unsuccessful. Power cycle the board.");
|
||||
Serial.println(hweui);
|
||||
delay(10000);
|
||||
hweui = myLora.hweui();
|
||||
}
|
||||
|
||||
//print out the HWEUI so that we can register it via ttnctl
|
||||
Serial.println("When using OTAA, register this DevEUI: ");
|
||||
Serial.println(myLora.hweui());
|
||||
Serial.println("RN2xx3 firmware version:");
|
||||
Serial.println(myLora.sysver());
|
||||
|
||||
//configure your keys and join the network
|
||||
Serial.println("Trying to join TTN");
|
||||
bool join_result = false;
|
||||
|
||||
const char *appEui = "0000000000000000";
|
||||
const char *appKey = "27AF4F436A03803BE0E96437B8AD270E";
|
||||
|
||||
join_result = myLora.initOTAA(appEui, appKey);
|
||||
|
||||
while(!join_result)
|
||||
{
|
||||
Serial.println("Unable to join. Are your keys correct, and do you have TTN coverage?");
|
||||
delay(60000); //delay a minute before retry
|
||||
join_result = myLora.init();
|
||||
}
|
||||
Serial.println("Successfully joined TTN");
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonction de setup des LEDs */
|
||||
void setupLEDs(boolean used) {
|
||||
if (used) {
|
||||
pinMode(pinRedLED, OUTPUT);
|
||||
digitalWrite(pinRedLED, LED_OFF);
|
||||
pinMode(pinBlueLED, OUTPUT);
|
||||
digitalWrite(pinBlueLED, LED_OFF);
|
||||
pinMode(pinGreenLED, OUTPUT);
|
||||
digitalWrite(pinGreenLED, LED_OFF);
|
||||
pinMode(pinYellowLED, OUTPUT);
|
||||
digitalWrite(pinYellowLED, LED_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonction de setup du buzzer */
|
||||
void setupBuzzer(boolean used) {
|
||||
if (used) {
|
||||
pinMode(pinBuzzer, OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonction de setup des interruptions */
|
||||
void setupInterrupt(boolean used) {
|
||||
if (used) {
|
||||
attachInterrupt(digitalPinToInterrupt(pinInterruptUp), setAlertState, RISING);
|
||||
attachInterrupt(digitalPinToInterrupt(pinInterruptDown), resetAlertState, FALLING);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonction de setup du Timer */
|
||||
void setupPeriodic(boolean used) {
|
||||
if (used) {
|
||||
MsTimer2::set(MESURE_PERIOD*1000, setPeriodicState);
|
||||
MsTimer2::start();
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonction de setup du power save mode */
|
||||
void setupPowerSaveMode(boolean used) {
|
||||
if (used) {
|
||||
set_sleep_mode(SLEEP_MODE_PWR_SAVE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonction d'initialisation globale */
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
|
||||
setupLoRa(useLoRa);
|
||||
setupLEDs(useLEDs);
|
||||
setupBuzzer(useBuzzer);
|
||||
setupInterrupt(useInterrupts);
|
||||
setupPeriodic(usePeriodic);
|
||||
setupPowerSaveMode(usePowerSaveMode);
|
||||
|
||||
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinYellowLED, LED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/************** FIN DU SETUP **************/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/************* DEBUT HANDLER **************/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
|
||||
void setAlertState() {
|
||||
gasDetected = true;
|
||||
endGasDetected = false;
|
||||
}
|
||||
|
||||
void resetAlertState() {
|
||||
gasDetected = false;
|
||||
endGasDetected = true;
|
||||
}
|
||||
|
||||
void setPeriodicState() {
|
||||
lecture = true;
|
||||
}
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/************** FIN HANDLER ***************/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/********** DEBUT FONCTIONS TEST **********/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
|
||||
void testGasSensor() {
|
||||
Serial.print("Valeur lue sur le capteur : ");
|
||||
Serial.print(readValue());
|
||||
Serial.println(" V");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void testLoRa() {
|
||||
if (useLoRa) {
|
||||
static int i = 0;
|
||||
Serial.print("Envoi du TEST n°");
|
||||
Serial.println(i);
|
||||
String toSend = "TEST" + String(i);
|
||||
myLora.tx(toSend);
|
||||
Serial.println("Envoi terminé");
|
||||
i++;
|
||||
} else {
|
||||
Serial.println("Veuillez activer le module LoRa");
|
||||
}
|
||||
delay(20000);
|
||||
}
|
||||
|
||||
void testLEDs() {
|
||||
int pause = 50;
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinYellowLED, LED_OFF); // RED + BLUE
|
||||
delay(pause);
|
||||
digitalWrite(pinBlueLED, LED_ON);
|
||||
delay(pause);
|
||||
digitalWrite(pinRedLED, LED_OFF); // BLUE + GREEN
|
||||
delay(pause);
|
||||
digitalWrite(pinGreenLED, LED_ON);
|
||||
delay(pause);
|
||||
digitalWrite(pinBlueLED, LED_OFF); // GREEN + YELLOW
|
||||
delay(pause);
|
||||
digitalWrite(pinYellowLED, LED_ON);
|
||||
delay(pause);
|
||||
digitalWrite(pinGreenLED, LED_OFF); // YELLOW + RED
|
||||
delay(pause);
|
||||
digitalWrite(pinRedLED, LED_ON);
|
||||
delay(pause);
|
||||
} else {
|
||||
Serial.println("Veuillez activer les LEDs");
|
||||
delay(20000);
|
||||
}
|
||||
}
|
||||
|
||||
void testBuzzer() {
|
||||
if (useBuzzer) {
|
||||
playAlertPompier();
|
||||
} else {
|
||||
Serial.println("Veuillez activer le Buzzer");
|
||||
}
|
||||
delay(10000);
|
||||
}
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/*********** FIN FONCTIONS TEST ***********/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/************ DEBUT DU PROCESS ************/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
|
||||
|
||||
/* Primitive connection TTN */
|
||||
void connectTTN() {
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinBlueLED, LED_ON);
|
||||
}
|
||||
}
|
||||
|
||||
/* Primitive disconnection TTN */
|
||||
void disconnectTTN() {
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinBlueLED, LED_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Primitive du buzzer */
|
||||
void playTone(int tone, int duration) {
|
||||
for (long i = 0; i < duration * 1000L; i += tone * 2) {
|
||||
digitalWrite(pinBuzzer, HIGH);
|
||||
delayMicroseconds(tone);
|
||||
digitalWrite(pinBuzzer, LOW);
|
||||
delayMicroseconds(tone);
|
||||
}
|
||||
}
|
||||
|
||||
/* Primitive du buzzer */
|
||||
void playNote(char note, int duration) {
|
||||
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
|
||||
int tones[] = { 1915, 1700, 1519, 1432, 1275, 1136, 1014, 956 };
|
||||
|
||||
// play the tone corresponding to the note name
|
||||
for (int i = 0; i < sizeof(names); i++) {
|
||||
//for (int i = 0; i < 8; i++) {
|
||||
if (names[i] == note) {
|
||||
playTone(tones[i], duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Primitive du buzzer */
|
||||
void playAlertPompier() {
|
||||
int length = 15; // the number of notes
|
||||
char notes[] = "bababababababa "; // a space represents a rest
|
||||
int beats[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
|
||||
int tempo = 900;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (notes[i] == ' ') {
|
||||
delay(beats[i] * tempo); // rest
|
||||
} else {
|
||||
playNote(notes[i], beats[i] * tempo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Primitive de lecture de la valeur du capteur */
|
||||
float readValue() {
|
||||
int value = 0;
|
||||
for (int i = 0; i<10; i++) {
|
||||
value += analogRead(pinGasSensor);
|
||||
}
|
||||
return ((float)value/10.0)*5.0/1024.0;
|
||||
}
|
||||
|
||||
/* Gestion de l'alerte */
|
||||
void gasDetectedHandler() {
|
||||
Serial.println("ALERTE présence de gaz !!!");
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinRedLED, LED_ON);
|
||||
}
|
||||
if (useBuzzer) {
|
||||
playAlertPompier();
|
||||
}
|
||||
if (useLoRa) {
|
||||
connectTTN();
|
||||
String toSend = "ALERTE présence de gaz !!!";
|
||||
myLora.tx(toSend);
|
||||
disconnectTTN();
|
||||
}
|
||||
}
|
||||
|
||||
/* Gestion de la fin de l'alerte */
|
||||
void gasDetectionEndHandler() {
|
||||
Serial.println("Fin ALERTE présence de gaz !!!");
|
||||
if (useLoRa) {
|
||||
connectTTN();
|
||||
String toSend = "Fin ALERTE présence de gaz !!!";
|
||||
myLora.tx(toSend);
|
||||
disconnectTTN();
|
||||
}
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinRedLED, LED_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fonction de detection du gaz */
|
||||
void analyseGasAtmosphere() {
|
||||
|
||||
if (lecture) {
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinGreenLED, LED_ON);
|
||||
}
|
||||
float sensorValue = readValue();
|
||||
Serial.println(sensorValue);
|
||||
if (useLoRa) {
|
||||
connectTTN();
|
||||
String sensorValueStr = String(sensorValue, 1);
|
||||
myLora.tx(sensorValueStr);
|
||||
disconnectTTN();
|
||||
}
|
||||
lecture = false;
|
||||
if (useLEDs) {
|
||||
digitalWrite(pinGreenLED, LED_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
if (gasDetected) {
|
||||
gasDetectedHandler();
|
||||
while (!endGasDetected) {
|
||||
gasDetectedHandler();
|
||||
}
|
||||
gasDetectionEndHandler();
|
||||
}
|
||||
|
||||
if (usePowerSaveMode) {
|
||||
sleep_mode();
|
||||
}
|
||||
}
|
||||
|
||||
/* Processus */
|
||||
void loop(){
|
||||
//testGasSensor();
|
||||
//testLoRa();
|
||||
//testLEDs();
|
||||
//testBuzzer();
|
||||
analyseGasAtmosphere();
|
||||
}
|
||||
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
/************* FIN DU PROCESS *************/
|
||||
/******************************************/
|
||||
/******************************************/
|
||||
789
GasSensor/rn2xx3.cpp
Normal file
789
GasSensor/rn2xx3.cpp
Normal file
|
|
@ -0,0 +1,789 @@
|
|||
/*
|
||||
* A library for controlling a Microchip rn2xx3 LoRa radio.
|
||||
*
|
||||
* @Author JP Meijers
|
||||
* @Author Nicolas Schteinschraber
|
||||
* @Date 18/12/2015
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "rn2xx3.h"
|
||||
|
||||
extern "C" {
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
}
|
||||
|
||||
/*
|
||||
@param serial Needs to be an already opened Stream ({Software/Hardware}Serial) to write to and read from.
|
||||
*/
|
||||
rn2xx3::rn2xx3(Stream& serial):
|
||||
_serial(serial)
|
||||
{
|
||||
_serial.setTimeout(2000);
|
||||
}
|
||||
|
||||
//TODO: change to a boolean
|
||||
void rn2xx3::autobaud()
|
||||
{
|
||||
String response = "";
|
||||
|
||||
// Try a maximum of 10 times with a 1 second delay
|
||||
for (uint8_t i=0; i<10 && response==""; i++)
|
||||
{
|
||||
delay(1000);
|
||||
_serial.write((byte)0x00);
|
||||
_serial.write(0x55);
|
||||
_serial.println();
|
||||
// we could use sendRawCommand(F("sys get ver")); here
|
||||
_serial.println("sys get ver");
|
||||
response = _serial.readStringUntil('\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String rn2xx3::sysver()
|
||||
{
|
||||
String ver = sendRawCommand(F("sys get ver"));
|
||||
ver.trim();
|
||||
return ver;
|
||||
}
|
||||
|
||||
RN2xx3_t rn2xx3::configureModuleType()
|
||||
{
|
||||
String version = sysver();
|
||||
String model = version.substring(2,6);
|
||||
switch (model.toInt()) {
|
||||
case 2903:
|
||||
_moduleType = RN2903;
|
||||
break;
|
||||
case 2483:
|
||||
_moduleType = RN2483;
|
||||
break;
|
||||
default:
|
||||
_moduleType = RN_NA;
|
||||
break;
|
||||
}
|
||||
return _moduleType;
|
||||
}
|
||||
|
||||
String rn2xx3::hweui()
|
||||
{
|
||||
return (sendRawCommand(F("sys get hweui")));
|
||||
}
|
||||
|
||||
String rn2xx3::appeui()
|
||||
{
|
||||
return ( sendRawCommand(F("mac get appeui") ));
|
||||
}
|
||||
|
||||
String rn2xx3::appkey()
|
||||
{
|
||||
// We can't read back from module, we send the one
|
||||
// we have memorized if it has been set
|
||||
return _appskey;
|
||||
}
|
||||
|
||||
String rn2xx3::deveui()
|
||||
{
|
||||
return (sendRawCommand(F("mac get deveui")));
|
||||
}
|
||||
|
||||
bool rn2xx3::init()
|
||||
{
|
||||
if(_appskey=="0") //appskey variable is set by both OTAA and ABP
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if(_otaa==true)
|
||||
{
|
||||
return initOTAA(_appeui, _appskey);
|
||||
}
|
||||
else
|
||||
{
|
||||
return initABP(_devAddr, _appskey, _nwkskey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool rn2xx3::initOTAA(String AppEUI, String AppKey, String DevEUI)
|
||||
{
|
||||
_otaa = true;
|
||||
_nwkskey = "0";
|
||||
String receivedData;
|
||||
|
||||
//clear serial buffer
|
||||
while(_serial.available())
|
||||
_serial.read();
|
||||
|
||||
// detect which model radio we are using
|
||||
configureModuleType();
|
||||
|
||||
// reset the module - this will clear all keys set previously
|
||||
switch (_moduleType)
|
||||
{
|
||||
case RN2903:
|
||||
sendRawCommand(F("mac reset"));
|
||||
break;
|
||||
case RN2483:
|
||||
sendRawCommand(F("mac reset 868"));
|
||||
break;
|
||||
default:
|
||||
// we shouldn't go forward with the init
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the Device EUI was given as a parameter, use it
|
||||
// otherwise use the Hardware EUI.
|
||||
if (DevEUI.length() == 16)
|
||||
{
|
||||
_deveui = DevEUI;
|
||||
}
|
||||
else
|
||||
{
|
||||
String addr = sendRawCommand(F("sys get hweui"));
|
||||
if( addr.length() == 16 )
|
||||
{
|
||||
_deveui = addr;
|
||||
}
|
||||
// else fall back to the hard coded value in the header file
|
||||
}
|
||||
|
||||
sendRawCommand("mac set deveui "+_deveui);
|
||||
|
||||
// A valid length App EUI was given. Use it.
|
||||
if ( AppEUI.length() == 16 )
|
||||
{
|
||||
_appeui = AppEUI;
|
||||
sendRawCommand("mac set appeui "+_appeui);
|
||||
}
|
||||
|
||||
// A valid length App Key was give. Use it.
|
||||
if ( AppKey.length() == 32 )
|
||||
{
|
||||
_appskey = AppKey; //reuse the same variable as for ABP
|
||||
sendRawCommand("mac set appkey "+_appskey);
|
||||
}
|
||||
|
||||
if (_moduleType == RN2903)
|
||||
{
|
||||
sendRawCommand(F("mac set pwridx 5"));
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRawCommand(F("mac set pwridx 1"));
|
||||
}
|
||||
|
||||
// TTN does not yet support Adaptive Data Rate.
|
||||
// Using it is also only necessary in limited situations.
|
||||
// Therefore disable it by default.
|
||||
sendRawCommand(F("mac set adr off"));
|
||||
|
||||
// Switch off automatic replies, because this library can not
|
||||
// handle more than one mac_rx per tx. See RN2483 datasheet,
|
||||
// 2.4.8.14, page 27 and the scenario on page 19.
|
||||
sendRawCommand(F("mac set ar off"));
|
||||
|
||||
// Semtech and TTN both use a non default RX2 window freq and SF.
|
||||
// Maybe we should not specify this for other networks.
|
||||
// if (_moduleType == RN2483)
|
||||
// {
|
||||
// sendRawCommand(F("mac set rx2 3 869525000"));
|
||||
// }
|
||||
// Disabled for now because an OTAA join seems to work fine without.
|
||||
|
||||
_serial.setTimeout(30000);
|
||||
sendRawCommand(F("mac save"));
|
||||
|
||||
bool joined = false;
|
||||
|
||||
// Only try twice to join, then return and let the user handle it.
|
||||
for(int i=0; i<2 && !joined; i++)
|
||||
{
|
||||
sendRawCommand(F("mac join otaa"));
|
||||
// Parse 2nd response
|
||||
receivedData = _serial.readStringUntil('\n');
|
||||
|
||||
if(receivedData.startsWith("accepted"))
|
||||
{
|
||||
joined=true;
|
||||
delay(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
_serial.setTimeout(2000);
|
||||
return joined;
|
||||
}
|
||||
|
||||
|
||||
bool rn2xx3::initOTAA(uint8_t * AppEUI, uint8_t * AppKey, uint8_t * DevEUI)
|
||||
{
|
||||
String app_eui;
|
||||
String dev_eui;
|
||||
String app_key;
|
||||
char buff[3];
|
||||
|
||||
app_eui="";
|
||||
for (uint8_t i=0; i<8; i++)
|
||||
{
|
||||
sprintf(buff, "%02X", AppEUI[i]);
|
||||
app_eui += String (buff);
|
||||
}
|
||||
|
||||
dev_eui = "0";
|
||||
if (DevEUI) //==0
|
||||
{
|
||||
dev_eui = "";
|
||||
for (uint8_t i=0; i<8; i++)
|
||||
{
|
||||
sprintf(buff, "%02X", DevEUI[i]);
|
||||
dev_eui += String (buff);
|
||||
}
|
||||
}
|
||||
|
||||
app_key="";
|
||||
for (uint8_t i=0; i<16; i++)
|
||||
{
|
||||
sprintf(buff, "%02X", AppKey[i]);
|
||||
app_key += String (buff);
|
||||
}
|
||||
|
||||
return initOTAA(app_eui, app_key, dev_eui);
|
||||
}
|
||||
|
||||
bool rn2xx3::initABP(String devAddr, String AppSKey, String NwkSKey)
|
||||
{
|
||||
_otaa = false;
|
||||
_devAddr = devAddr;
|
||||
_appskey = AppSKey;
|
||||
_nwkskey = NwkSKey;
|
||||
String receivedData;
|
||||
|
||||
//clear serial buffer
|
||||
while(_serial.available())
|
||||
_serial.read();
|
||||
|
||||
configureModuleType();
|
||||
|
||||
switch (_moduleType) {
|
||||
case RN2903:
|
||||
sendRawCommand(F("mac reset"));
|
||||
break;
|
||||
case RN2483:
|
||||
sendRawCommand(F("mac reset 868"));
|
||||
// sendRawCommand(F("mac set rx2 3 869525000"));
|
||||
// In the past we set the downlink channel here,
|
||||
// but setFrequencyPlan is a better place to do it.
|
||||
break;
|
||||
default:
|
||||
// we shouldn't go forward with the init
|
||||
return false;
|
||||
}
|
||||
|
||||
sendRawCommand("mac set nwkskey "+_nwkskey);
|
||||
sendRawCommand("mac set appskey "+_appskey);
|
||||
sendRawCommand("mac set devaddr "+_devAddr);
|
||||
sendRawCommand(F("mac set adr off"));
|
||||
|
||||
// Switch off automatic replies, because this library can not
|
||||
// handle more than one mac_rx per tx. See RN2483 datasheet,
|
||||
// 2.4.8.14, page 27 and the scenario on page 19.
|
||||
sendRawCommand(F("mac set ar off"));
|
||||
|
||||
if (_moduleType == RN2903)
|
||||
{
|
||||
sendRawCommand("mac set pwridx 5");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRawCommand(F("mac set pwridx 1"));
|
||||
}
|
||||
sendRawCommand(F("mac set dr 5")); //0= min, 7=max
|
||||
|
||||
_serial.setTimeout(60000);
|
||||
sendRawCommand(F("mac save"));
|
||||
sendRawCommand(F("mac join abp"));
|
||||
receivedData = _serial.readStringUntil('\n');
|
||||
|
||||
_serial.setTimeout(2000);
|
||||
delay(1000);
|
||||
|
||||
if(receivedData.startsWith("accepted"))
|
||||
{
|
||||
return true;
|
||||
//with abp we can always join successfully as long as the keys are valid
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::tx(String data)
|
||||
{
|
||||
return txUncnf(data); //we are unsure which mode we're in. Better not to wait for acks.
|
||||
}
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::txBytes(const byte* data, uint8_t size)
|
||||
{
|
||||
char msgBuffer[size*2 + 1];
|
||||
|
||||
char buffer[3];
|
||||
for (unsigned i=0; i<size; i++)
|
||||
{
|
||||
sprintf(buffer, "%02X", data[i]);
|
||||
memcpy(&msgBuffer[i*2], &buffer, sizeof(buffer));
|
||||
}
|
||||
String dataToTx(msgBuffer);
|
||||
return txCommand("mac tx uncnf 1 ", dataToTx, false);
|
||||
}
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::txCnf(String data)
|
||||
{
|
||||
return txCommand("mac tx cnf 1 ", data, true);
|
||||
}
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::txUncnf(String data)
|
||||
{
|
||||
return txCommand("mac tx uncnf 1 ", data, true);
|
||||
}
|
||||
|
||||
TX_RETURN_TYPE rn2xx3::txCommand(String command, String data, bool shouldEncode)
|
||||
{
|
||||
bool send_success = false;
|
||||
uint8_t busy_count = 0;
|
||||
uint8_t retry_count = 0;
|
||||
|
||||
//clear serial buffer
|
||||
while(_serial.available())
|
||||
_serial.read();
|
||||
|
||||
while(!send_success)
|
||||
{
|
||||
//retransmit a maximum of 10 times
|
||||
retry_count++;
|
||||
if(retry_count>10)
|
||||
{
|
||||
return TX_FAIL;
|
||||
}
|
||||
|
||||
_serial.print(command);
|
||||
if(shouldEncode)
|
||||
{
|
||||
sendEncoded(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
_serial.print(data);
|
||||
}
|
||||
_serial.println();
|
||||
|
||||
String receivedData = _serial.readStringUntil('\n');
|
||||
//TODO: Debug print on receivedData
|
||||
|
||||
if(receivedData.startsWith("ok"))
|
||||
{
|
||||
_serial.setTimeout(30000);
|
||||
receivedData = _serial.readStringUntil('\n');
|
||||
_serial.setTimeout(2000);
|
||||
|
||||
//TODO: Debug print on receivedData
|
||||
|
||||
if(receivedData.startsWith("mac_tx_ok"))
|
||||
{
|
||||
//SUCCESS!!
|
||||
send_success = true;
|
||||
return TX_SUCCESS;
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("mac_rx"))
|
||||
{
|
||||
//example: mac_rx 1 54657374696E6720313233
|
||||
_rxMessenge = receivedData.substring(receivedData.indexOf(' ', 7)+1);
|
||||
send_success = true;
|
||||
return TX_WITH_RX;
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("mac_err"))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("invalid_data_len"))
|
||||
{
|
||||
//this should never happen if the prototype worked
|
||||
send_success = true;
|
||||
return TX_FAIL;
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("radio_tx_ok"))
|
||||
{
|
||||
//SUCCESS!!
|
||||
send_success = true;
|
||||
return TX_SUCCESS;
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("radio_err"))
|
||||
{
|
||||
//This should never happen. If it does, something major is wrong.
|
||||
init();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//unknown response
|
||||
//init();
|
||||
}
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("invalid_param"))
|
||||
{
|
||||
//should not happen if we typed the commands correctly
|
||||
send_success = true;
|
||||
return TX_FAIL;
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("not_joined"))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("no_free_ch"))
|
||||
{
|
||||
//retry
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("silent"))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("frame_counter_err_rejoin_needed"))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("busy"))
|
||||
{
|
||||
busy_count++;
|
||||
|
||||
// Not sure if this is wise. At low data rates with large packets
|
||||
// this can perhaps cause transmissions at more than 1% duty cycle.
|
||||
// Need to calculate the correct constant value.
|
||||
// But it is wise to have this check and re-init in case the
|
||||
// lorawan stack in the RN2xx3 hangs.
|
||||
if(busy_count>=10)
|
||||
{
|
||||
init();
|
||||
}
|
||||
else
|
||||
{
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("mac_paused"))
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
else if(receivedData.startsWith("invalid_data_len"))
|
||||
{
|
||||
//should not happen if the prototype worked
|
||||
send_success = true;
|
||||
return TX_FAIL;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//unknown response after mac tx command
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
return TX_FAIL; //should never reach this
|
||||
}
|
||||
|
||||
void rn2xx3::sendEncoded(String input)
|
||||
{
|
||||
char working;
|
||||
char buffer[3];
|
||||
for (unsigned i=0; i<input.length(); i++)
|
||||
{
|
||||
working = input.charAt(i);
|
||||
sprintf(buffer, "%02x", int(working));
|
||||
_serial.print(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
String rn2xx3::base16encode(String input)
|
||||
{
|
||||
char charsOut[input.length()*2+1];
|
||||
char charsIn[input.length()+1];
|
||||
input.trim();
|
||||
input.toCharArray(charsIn, input.length()+1);
|
||||
|
||||
unsigned i = 0;
|
||||
for(i = 0; i<input.length()+1; i++)
|
||||
{
|
||||
if(charsIn[i] == '\0') break;
|
||||
|
||||
int value = int(charsIn[i]);
|
||||
|
||||
char buffer[3];
|
||||
sprintf(buffer, "%02x", value);
|
||||
charsOut[2*i] = buffer[0];
|
||||
charsOut[2*i+1] = buffer[1];
|
||||
}
|
||||
charsOut[2*i] = '\0';
|
||||
String toReturn = String(charsOut);
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
String rn2xx3::getRx() {
|
||||
return _rxMessenge;
|
||||
}
|
||||
|
||||
int rn2xx3::getSNR()
|
||||
{
|
||||
String snr = sendRawCommand(F("radio get snr"));
|
||||
snr.trim();
|
||||
return snr.toInt();
|
||||
}
|
||||
|
||||
String rn2xx3::base16decode(String input)
|
||||
{
|
||||
char charsIn[input.length()+1];
|
||||
char charsOut[input.length()/2+1];
|
||||
input.trim();
|
||||
input.toCharArray(charsIn, input.length()+1);
|
||||
|
||||
unsigned i = 0;
|
||||
for(i = 0; i<input.length()/2+1; i++)
|
||||
{
|
||||
if(charsIn[i*2] == '\0') break;
|
||||
if(charsIn[i*2+1] == '\0') break;
|
||||
|
||||
char toDo[2];
|
||||
toDo[0] = charsIn[i*2];
|
||||
toDo[1] = charsIn[i*2+1];
|
||||
int out = strtoul(toDo, 0, 16);
|
||||
|
||||
if(out<128)
|
||||
{
|
||||
charsOut[i] = char(out);
|
||||
}
|
||||
}
|
||||
charsOut[i] = '\0';
|
||||
return charsOut;
|
||||
}
|
||||
|
||||
void rn2xx3::setDR(int dr)
|
||||
{
|
||||
if(dr>=0 && dr<=5)
|
||||
{
|
||||
delay(100);
|
||||
while(_serial.available())
|
||||
_serial.read();
|
||||
_serial.print("mac set dr ");
|
||||
_serial.println(dr);
|
||||
_serial.readStringUntil('\n');
|
||||
}
|
||||
}
|
||||
|
||||
void rn2xx3::sleep(long msec)
|
||||
{
|
||||
_serial.print("sys sleep ");
|
||||
_serial.println(msec);
|
||||
}
|
||||
|
||||
|
||||
String rn2xx3::sendRawCommand(String command)
|
||||
{
|
||||
delay(100);
|
||||
while(_serial.available())
|
||||
_serial.read();
|
||||
_serial.println(command);
|
||||
String ret = _serial.readStringUntil('\n');
|
||||
ret.trim();
|
||||
|
||||
//TODO: Add debug print
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
RN2xx3_t rn2xx3::moduleType()
|
||||
{
|
||||
return _moduleType;
|
||||
}
|
||||
|
||||
bool rn2xx3::setFrequencyPlan(FREQ_PLAN fp)
|
||||
{
|
||||
bool returnValue;
|
||||
|
||||
switch (fp)
|
||||
{
|
||||
case SINGLE_CHANNEL_EU:
|
||||
{
|
||||
if(_moduleType == RN2483)
|
||||
{
|
||||
//mac set rx2 <dataRate> <frequency>
|
||||
//sendRawCommand(F("mac set rx2 5 868100000")); //use this for "strict" one channel gateways
|
||||
sendRawCommand(F("mac set rx2 3 869525000")); //use for "non-strict" one channel gateways
|
||||
sendRawCommand(F("mac set ch dcycle 0 99")); //1% duty cycle for this channel
|
||||
sendRawCommand(F("mac set ch dcycle 1 65535")); //almost never use this channel
|
||||
sendRawCommand(F("mac set ch dcycle 2 65535")); //almost never use this channel
|
||||
|
||||
returnValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TTN_EU:
|
||||
{
|
||||
if(_moduleType == RN2483)
|
||||
{
|
||||
/*
|
||||
* The <dutyCycle> value that needs to be configured can be
|
||||
* obtained from the actual duty cycle X (in percentage)
|
||||
* using the following formula: <dutyCycle> = (100/X) – 1
|
||||
*
|
||||
* 10% -> 9
|
||||
* 1% -> 99
|
||||
* 0.33% -> 299
|
||||
* 8 channels, total of 1% duty cycle:
|
||||
* 0.125% per channel -> 799
|
||||
*
|
||||
* Most of the TTN_EU frequency plan was copied from:
|
||||
* https://github.com/TheThingsNetwork/arduino-device-lib
|
||||
*/
|
||||
|
||||
//RX window 2
|
||||
sendRawCommand(F("mac set rx2 3 869525000"));
|
||||
|
||||
//channel 0
|
||||
sendRawCommand(F("mac set ch dcycle 0 799"));
|
||||
|
||||
//channel 1
|
||||
sendRawCommand(F("mac set ch drrange 1 0 6"));
|
||||
sendRawCommand(F("mac set ch dcycle 1 799"));
|
||||
|
||||
//channel 2
|
||||
sendRawCommand(F("mac set ch dcycle 2 799"));
|
||||
|
||||
//channel 3
|
||||
sendRawCommand(F("mac set ch freq 3 867100000"));
|
||||
sendRawCommand(F("mac set ch drrange 3 0 5"));
|
||||
sendRawCommand(F("mac set ch dcycle 3 799"));
|
||||
sendRawCommand(F("mac set ch status 3 on"));
|
||||
|
||||
//channel 4
|
||||
sendRawCommand(F("mac set ch freq 4 867300000"));
|
||||
sendRawCommand(F("mac set ch drrange 4 0 5"));
|
||||
sendRawCommand(F("mac set ch dcycle 4 799"));
|
||||
sendRawCommand(F("mac set ch status 4 on"));
|
||||
|
||||
//channel 5
|
||||
sendRawCommand(F("mac set ch freq 5 867500000"));
|
||||
sendRawCommand(F("mac set ch drrange 5 0 5"));
|
||||
sendRawCommand(F("mac set ch dcycle 5 799"));
|
||||
sendRawCommand(F("mac set ch status 5 on"));
|
||||
|
||||
//channel 6
|
||||
sendRawCommand(F("mac set ch freq 6 867700000"));
|
||||
sendRawCommand(F("mac set ch drrange 6 0 5"));
|
||||
sendRawCommand(F("mac set ch dcycle 6 799"));
|
||||
sendRawCommand(F("mac set ch status 6 on"));
|
||||
|
||||
//channel 7
|
||||
sendRawCommand(F("mac set ch freq 7 867900000"));
|
||||
sendRawCommand(F("mac set ch drrange 7 0 5"));
|
||||
sendRawCommand(F("mac set ch dcycle 7 799"));
|
||||
sendRawCommand(F("mac set ch status 7 on"));
|
||||
|
||||
returnValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TTN_US:
|
||||
{
|
||||
/*
|
||||
* Most of the TTN_US frequency plan was copied from:
|
||||
* https://github.com/TheThingsNetwork/arduino-device-lib
|
||||
*/
|
||||
if(_moduleType == RN2903)
|
||||
{
|
||||
for(int channel=0; channel<72; channel++)
|
||||
{
|
||||
// Build command string. First init, then add int.
|
||||
String command = F("mac set ch status ");
|
||||
command += channel;
|
||||
|
||||
if(channel>=8 && channel<16)
|
||||
{
|
||||
sendRawCommand(command+F(" on"));
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRawCommand(command+F(" off"));
|
||||
}
|
||||
}
|
||||
returnValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case DEFAULT_EU:
|
||||
{
|
||||
if(_moduleType == RN2483)
|
||||
{
|
||||
//fix duty cycle - 1% = 0.33% per channel
|
||||
sendRawCommand(F("mac set ch dcycle 0 799"));
|
||||
sendRawCommand(F("mac set ch dcycle 1 799"));
|
||||
sendRawCommand(F("mac set ch dcycle 2 799"));
|
||||
|
||||
//disable non-default channels
|
||||
sendRawCommand(F("mac set ch status 3 on"));
|
||||
sendRawCommand(F("mac set ch status 4 on"));
|
||||
sendRawCommand(F("mac set ch status 5 on"));
|
||||
sendRawCommand(F("mac set ch status 6 on"));
|
||||
sendRawCommand(F("mac set ch status 7 on"));
|
||||
|
||||
returnValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValue = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
//set default channels 868.1, 868.3 and 868.5?
|
||||
returnValue = false; //well we didn't do anything, so yes, false
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
273
GasSensor/rn2xx3.h
Normal file
273
GasSensor/rn2xx3.h
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* A library for controlling a Microchip RN2xx3 LoRa radio.
|
||||
*
|
||||
* @Author JP Meijers
|
||||
* @Author Nicolas Schteinschraber
|
||||
* @Date 18/12/2015
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef rn2xx3_h
|
||||
#define rn2xx3_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
enum RN2xx3_t {
|
||||
RN_NA = 0, // Not set
|
||||
RN2903 = 2903,
|
||||
RN2483 = 2483
|
||||
};
|
||||
|
||||
enum FREQ_PLAN {
|
||||
SINGLE_CHANNEL_EU,
|
||||
TTN_EU,
|
||||
TTN_US,
|
||||
DEFAULT_EU
|
||||
};
|
||||
|
||||
enum TX_RETURN_TYPE {
|
||||
TX_FAIL = 0, // The transmission failed.
|
||||
// If you sent a confirmed message and it is not acked,
|
||||
// this will be the returned value.
|
||||
|
||||
TX_SUCCESS = 1, // The transmission was successful.
|
||||
// Also the case when a confirmed message was acked.
|
||||
|
||||
TX_WITH_RX = 2 // A downlink message was received after the transmission.
|
||||
// This also implies that a confirmed message is acked.
|
||||
};
|
||||
|
||||
class rn2xx3
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
* A simplified constructor taking only a Stream ({Software/Hardware}Serial) object.
|
||||
* The serial port should already be initialised when initialising this library.
|
||||
*/
|
||||
rn2xx3(Stream& serial);
|
||||
|
||||
/*
|
||||
* Transmit the correct sequence to the rn2xx3 to trigger its autobauding feature.
|
||||
* After this operation the rn2xx3 should communicate at the same baud rate than us.
|
||||
*/
|
||||
void autobaud();
|
||||
|
||||
/*
|
||||
* Get the hardware EUI of the radio, so that we can register it on The Things Network
|
||||
* and obtain the correct AppKey.
|
||||
* You have to have a working serial connection to the radio before calling this function.
|
||||
* In other words you have to at least call autobaud() some time before this function.
|
||||
*/
|
||||
String hweui();
|
||||
|
||||
/*
|
||||
* Returns the AppSKey or AppKey used when initializing the radio.
|
||||
* In the case of ABP this function will return the App Session Key.
|
||||
* In the case of OTAA this function will return the App Key.
|
||||
*/
|
||||
String appkey();
|
||||
|
||||
/*
|
||||
* In the case of OTAA this function will return the Application EUI used
|
||||
* to initialize the radio.
|
||||
*/
|
||||
String appeui();
|
||||
|
||||
/*
|
||||
* In the case of OTAA this function will return the Device EUI used to
|
||||
* initialize the radio. This is not necessarily the same as the Hardware EUI.
|
||||
* To obtain the Hardware EUI, use the hweui() function.
|
||||
*/
|
||||
String deveui();
|
||||
|
||||
/*
|
||||
* Get the RN2xx3's hardware and firmware version number. This is also used
|
||||
* to detect if the module is either an RN2483 or an RN2903.
|
||||
*/
|
||||
String sysver();
|
||||
|
||||
/*
|
||||
* Initialise the RN2xx3 and join the LoRa network (if applicable).
|
||||
* This function can only be called after calling initABP() or initOTAA().
|
||||
* The sole purpose of this function is to re-initialise the radio if it
|
||||
* is in an unknown state.
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/*
|
||||
* Initialise the RN2xx3 and join a network using personalization.
|
||||
*
|
||||
* addr: The device address as a HEX string.
|
||||
* Example "0203FFEE"
|
||||
* AppSKey: Application Session Key as a HEX string.
|
||||
* Example "8D7FFEF938589D95AAD928C2E2E7E48F"
|
||||
* NwkSKey: Network Session Key as a HEX string.
|
||||
* Example "AE17E567AECC8787F749A62F5541D522"
|
||||
*/
|
||||
bool initABP(String addr, String AppSKey, String NwkSKey);
|
||||
|
||||
//TODO: initABP(uint8_t * addr, uint8_t * AppSKey, uint8_t * NwkSKey)
|
||||
|
||||
/*
|
||||
* Initialise the RN2xx3 and join a network using over the air activation.
|
||||
*
|
||||
* AppEUI: Application EUI as a HEX string.
|
||||
* Example "70B3D57ED00001A6"
|
||||
* AppKey: Application key as a HEX string.
|
||||
* Example "A23C96EE13804963F8C2BD6285448198"
|
||||
* DevEUI: Device EUI as a HEX string.
|
||||
* Example "0011223344556677"
|
||||
* If the DevEUI parameter is omitted, the Hardware EUI from module will be used
|
||||
* If no keys, or invalid length keys, are provided, no keys
|
||||
* will be configured. If the module is already configured with some keys
|
||||
* they will be used. Otherwise the join will fail and this function
|
||||
* will return false.
|
||||
*/
|
||||
bool initOTAA(String AppEUI="", String AppKey="", String DevEUI="");
|
||||
|
||||
/*
|
||||
* Initialise the RN2xx3 and join a network using over the air activation,
|
||||
* using byte arrays. This is useful when storing the keys in eeprom or flash
|
||||
* and reading them out in runtime.
|
||||
*
|
||||
* AppEUI: Application EUI as a uint8_t buffer
|
||||
* AppKey: Application key as a uint8_t buffer
|
||||
* DevEui: Device EUI as a uint8_t buffer (optional - set to 0 to use Hardware EUI)
|
||||
*/
|
||||
bool initOTAA(uint8_t * AppEUI, uint8_t * AppKey, uint8_t * DevEui);
|
||||
|
||||
/*
|
||||
* Transmit the provided data. The data is hex-encoded by this library,
|
||||
* so plain text can be provided.
|
||||
* This function is an alias for txUncnf().
|
||||
*
|
||||
* Parameter is an ascii text string.
|
||||
*/
|
||||
TX_RETURN_TYPE tx(String);
|
||||
|
||||
/*
|
||||
* Transmit raw byte encoded data via LoRa WAN.
|
||||
* This method expects a raw byte array as first parameter.
|
||||
* The second parameter is the count of the bytes to send.
|
||||
*/
|
||||
TX_RETURN_TYPE txBytes(const byte*, uint8_t);
|
||||
|
||||
/*
|
||||
* Do a confirmed transmission via LoRa WAN.
|
||||
*
|
||||
* Parameter is an ascii text string.
|
||||
*/
|
||||
TX_RETURN_TYPE txCnf(String);
|
||||
|
||||
/*
|
||||
* Do an unconfirmed transmission via LoRa WAN.
|
||||
*
|
||||
* Parameter is an ascii text string.
|
||||
*/
|
||||
TX_RETURN_TYPE txUncnf(String);
|
||||
|
||||
/*
|
||||
* Transmit the provided data using the provided command.
|
||||
*
|
||||
* String - the tx command to send
|
||||
can only be one of "mac tx cnf 1 " or "mac tx uncnf 1 "
|
||||
* String - an ascii text string if bool is true. A HEX string if bool is false.
|
||||
* bool - should the data string be hex encoded or not
|
||||
*/
|
||||
TX_RETURN_TYPE txCommand(String, String, bool);
|
||||
|
||||
/*
|
||||
* Change the datarate at which the RN2xx3 transmits.
|
||||
* A value of between 0 and 5 can be specified,
|
||||
* as is defined in the LoRaWan specs.
|
||||
* This can be overwritten by the network when using OTAA.
|
||||
* So to force a datarate, call this function after initOTAA().
|
||||
*/
|
||||
void setDR(int dr);
|
||||
|
||||
/*
|
||||
* Put the RN2xx3 to sleep for a specified timeframe.
|
||||
* The RN2xx3 accepts values from 100 to 4294967296.
|
||||
* Rumour has it that you need to do a autobaud() after the module wakes up again.
|
||||
*/
|
||||
void sleep(long msec);
|
||||
|
||||
/*
|
||||
* Send a raw command to the RN2xx3 module.
|
||||
* Returns the raw string as received back from the RN2xx3.
|
||||
* If the RN2xx3 replies with multiple line, only the first line will be returned.
|
||||
*/
|
||||
String sendRawCommand(String command);
|
||||
|
||||
/*
|
||||
* Returns the module type either RN2903 or RN2483, or NA.
|
||||
*/
|
||||
RN2xx3_t moduleType();
|
||||
|
||||
/*
|
||||
* Set the active channels to use.
|
||||
* Returns true if setting the channels is possible.
|
||||
* Returns false if you are trying to use the wrong channels on the wrong module type.
|
||||
*/
|
||||
bool setFrequencyPlan(FREQ_PLAN);
|
||||
|
||||
/*
|
||||
* Returns the last downlink message HEX string.
|
||||
*/
|
||||
String getRx();
|
||||
|
||||
/*
|
||||
* Get the RN2xx3's SNR of the last received packet. Helpful to debug link quality.
|
||||
*/
|
||||
int getSNR();
|
||||
|
||||
/*
|
||||
* Encode an ASCII string to a HEX string as needed when passed
|
||||
* to the RN2xx3 module.
|
||||
*/
|
||||
String base16encode(String);
|
||||
|
||||
/*
|
||||
* Decode a HEX string to an ASCII string. Useful to decode a
|
||||
* string received from the RN2xx3.
|
||||
*/
|
||||
String base16decode(String);
|
||||
|
||||
private:
|
||||
Stream& _serial;
|
||||
|
||||
RN2xx3_t _moduleType = RN_NA;
|
||||
|
||||
//Flags to switch code paths. Default is to use OTAA.
|
||||
bool _otaa = true;
|
||||
|
||||
//The default address to use on TTN if no address is defined.
|
||||
//This one falls in the "testing" address space.
|
||||
String _devAddr = "03FFBEEF";
|
||||
|
||||
// if you want to use another DevEUI than the hardware one
|
||||
// use this deveui for LoRa WAN
|
||||
String _deveui = "0011223344556677";
|
||||
|
||||
//the appeui to use for LoRa WAN
|
||||
String _appeui = "0";
|
||||
|
||||
//the nwkskey to use for LoRa WAN
|
||||
String _nwkskey = "0";
|
||||
|
||||
//the appskey/appkey to use for LoRa WAN
|
||||
String _appskey = "0";
|
||||
|
||||
// The downlink messenge
|
||||
String _rxMessenge = "";
|
||||
|
||||
/*
|
||||
* Auto configure for either RN2903 or RN2483 module
|
||||
*/
|
||||
RN2xx3_t configureModuleType();
|
||||
|
||||
void sendEncoded(String);
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue