/*
* temperature sensor on analog 8 to test the LoRa gateway
* extended version with AES and custom Carrier Sense features
*
* Copyright (C) 2016 Congduc Pham, University of Pau, France
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the program. If not, see .
*
*****************************************************************************
* last update: Nov. 26th by C. Pham
*/
#include
// Include the SX1272
#include "SX1272.h"
// IMPORTANT
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// please uncomment only 1 choice
//
#define ETSI_EUROPE_REGULATION
//#define FCC_US_REGULATION
//#define SENEGAL_REGULATION
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORTANT
///////////////////////////////////////////////////////////////////////////////////////////////////////////
// please uncomment only 1 choice
//#define BAND868
//#define BAND900
#define BAND433
///////////////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef ETSI_EUROPE_REGULATION
#define MAX_DBM 14
// previous way for setting output power
// char powerLevel='M';
#elif defined SENEGAL_REGULATION
#define MAX_DBM 10
// previous way for setting output power
// 'H' is actually 6dBm, so better to use the new way to set output power
// char powerLevel='H';
#elif defined FCC_US_REGULATION
#define MAX_DBM 14
#endif
#ifdef BAND868
#ifdef SENEGAL_REGULATION
const uint32_t DEFAULT_CHANNEL=CH_04_868;
#else
const uint32_t DEFAULT_CHANNEL=CH_10_868;
#endif
#elif defined BAND900
const uint32_t DEFAULT_CHANNEL=CH_05_900;
#elif defined BAND433
const uint32_t DEFAULT_CHANNEL=CH_00_433;
#endif
// IMPORTANT
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// uncomment if your radio is an HopeRF RFM92W, HopeRF RFM95W, Modtronix inAir9B, NiceRF1276
// or you known from the circuit diagram that output use the PABOOST line instead of the RFO line
//#define PABOOST
///////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// COMMENT OR UNCOMMENT TO CHANGE FEATURES.
// ONLY IF YOU KNOW WHAT YOU ARE DOING!!! OTHERWISE LEAVE AS IT IS
#if not defined _VARIANT_ARDUINO_DUE_X_ && not defined __SAMD21G18A__
#define WITH_EEPROM
#endif
//#define WITH_APPKEY
#define FLOAT_TEMP
#define NEW_DATA_FIELD
#define LOW_POWER
#define LOW_POWER_HIBERNATE
#define CUSTOM_CS
//#define LORA_LAS
//#define WITH_AES
//#define LORAWAN
//#define TO_LORAWAN_GW
#define WITH_ACK
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// CHANGE HERE THE LORA MODE, NODE ADDRESS
#define LORAMODE 1
#define node_addr 6
//////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// CHANGE HERE THE THINGSPEAK FIELD BETWEEN 1 AND 4
#define field_index 3
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// CHANGE HERE THE READ PIN AND THE POWER PIN FOR THE TEMP. SENSOR
#define TEMP_PIN_READ A0
// use digital 8 to power the temperature sensor if needed
#define TEMP_PIN_POWER 8
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// CHANGE HERE THE TIME IN MINUTES BETWEEN 2 READING & TRANSMISSION
unsigned int idlePeriodInMin = 10;
///////////////////////////////////////////////////////////////////
#ifdef WITH_APPKEY
///////////////////////////////////////////////////////////////////
// CHANGE HERE THE APPKEY, BUT IF GW CHECKS FOR APPKEY, MUST BE
// IN THE APPKEY LIST MAINTAINED BY GW.
uint8_t my_appKey[4]={5, 6, 7, 8};
///////////////////////////////////////////////////////////////////
#endif
// we wrapped Serial.println to support the Arduino Zero or M0
#if defined __SAMD21G18A__ && not defined ARDUINO_SAMD_FEATHER_M0
#define PRINTLN SerialUSB.println("")
#define PRINT_CSTSTR(fmt,param) SerialUSB.print(F(param))
#define PRINT_STR(fmt,param) SerialUSB.print(param)
#define PRINT_VALUE(fmt,param) SerialUSB.print(param)
#define PRINT_HEX(fmt,param) SerialUSB.print(param,HEX)
#define FLUSHOUTPUT SerialUSB.flush();
#else
#define PRINTLN Serial.println("")
#define PRINT_CSTSTR(fmt,param) Serial.print(F(param))
#define PRINT_STR(fmt,param) Serial.print(param)
#define PRINT_VALUE(fmt,param) Serial.print(param)
#define PRINT_HEX(fmt,param) Serial.print(param,HEX)
#define FLUSHOUTPUT Serial.flush();
#endif
#ifdef WITH_EEPROM
#include
#endif
#define DEFAULT_DEST_ADDR 1
#ifdef WITH_ACK
#define NB_RETRIES 15
#endif
#if defined ARDUINO_AVR_PRO || defined ARDUINO_AVR_MINI || defined __MK20DX256__ || defined __MKL26Z64__ || defined __MK64FX512__ || defined __MK66FX1M0__ || defined __SAMD21G18A__
// if you have a Pro Mini running at 5V, then change here
// these boards work in 3.3V
// Nexus board from Ideetron is a Mini
// __MK66FX1M0__ is for Teensy36
// __MK64FX512__ is for Teensy35
// __MK20DX256__ is for Teensy31/32
// __MKL26Z64__ is for TeensyLC
// __SAMD21G18A__ is for Zero/M0 and FeatherM0 (Cortex-M0)
#define TEMP_SCALE 3300.0
#else // ARDUINO_AVR_NANO || defined ARDUINO_AVR_UNO || defined ARDUINO_AVR_MEGA2560
// also for all other boards, so change here if required.
#define TEMP_SCALE 5000.0
#endif
#ifdef LOW_POWER
// this is for the Teensy36, Teensy35, Teensy31/32 & TeensyLC
// need v6 of Snooze library
#if defined __MK20DX256__ || defined __MKL26Z64__ || defined __MK64FX512__ || defined __MK66FX1M0__
#define LOW_POWER_PERIOD 60
#include
SnoozeTimer timer;
SnoozeBlock sleep_config(timer);
#else
#define LOW_POWER_PERIOD 8
// you need the LowPower library from RocketScream
// https://github.com/rocketscream/Low-Power
#include "LowPower.h"
#ifdef __SAMD21G18A__
// use the RTC library
#include "RTCZero.h"
/* Create an rtc object */
RTCZero rtc;
#endif
#endif
unsigned int nCycle = idlePeriodInMin*60/LOW_POWER_PERIOD;
#endif
#ifdef WITH_AES
#include "AES-128_V10.h"
#include "Encrypt_V31.h"
unsigned char AppSkey[16] = {
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};
unsigned char NwkSkey[16] = {
0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};
unsigned char DevAddr[4] = {
0x00, 0x00, 0x00, node_addr
};
uint16_t Frame_Counter_Up = 0x0000;
// we use the same convention than for LoRaWAN as we will use the same AES convention
// See LoRaWAN specifications
unsigned char Direction = 0x00;
#endif
#ifdef LORA_LAS
#include "LoRaActivitySharing.h"
// acting as an end-device
LASDevice loraLAS(node_addr,LAS_DEFAULT_ALPHA,DEFAULT_DEST_ADDR);
#endif
double temp;
unsigned long nextTransmissionTime=0L;
char float_str[20];
uint8_t message[100];
#ifdef TO_LORAWAN_GW
int loraMode=1;
#else
int loraMode=LORAMODE;
#endif
#ifdef WITH_EEPROM
struct sx1272config {
uint8_t flag1;
uint8_t flag2;
uint8_t seq;
// can add other fields such as LoRa mode,...
};
sx1272config my_sx1272config;
#endif
// receive window
uint16_t w_timer=1000;
#ifdef CUSTOM_CS
unsigned long startDoCad, endDoCad;
bool extendedIFS=true;
bool RSSIonSend=true;
uint8_t SIFS_cad_number;
uint8_t send_cad_number;
uint8_t SIFS_value[11]={0, 183, 94, 44, 47, 23, 24, 12, 12, 7, 4};
uint8_t CAD_value[11]={0, 62, 31, 16, 16, 8, 9, 5, 3, 1, 1};
// we could use the CarrierSense function added in the SX1272 library, but it is more convenient to duplicate it here
// so that we could easily modify it for testing
void CarrierSense() {
bool carrierSenseRetry=false;
int e;
if (send_cad_number) {
do {
do {
// check for free channel (SIFS/DIFS)
startDoCad=millis();
e = sx1272.doCAD(send_cad_number);
endDoCad=millis();
PRINT_CSTSTR("%s","--> CAD duration ");
PRINT_VALUE("%ld",endDoCad-startDoCad);
PRINTLN;
if (!e) {
PRINT_CSTSTR("%s","OK1\n");
if (extendedIFS) {
// wait for random number of CAD
#ifdef ARDUINO
uint8_t w = random(1,8);
#else
uint8_t w = rand() % 8 + 1;
#endif
PRINT_CSTSTR("%s","--> waiting for ");
PRINT_VALUE("%d",w);
PRINT_CSTSTR("%s"," CAD = ");
PRINT_VALUE("%d",CAD_value[loraMode]*w);
PRINTLN;
delay(CAD_value[loraMode]*w);
// check for free channel (SIFS/DIFS) once again
startDoCad=millis();
e = sx1272.doCAD(send_cad_number);
endDoCad=millis();
PRINT_CSTSTR("%s","--> CAD duration ");
PRINT_VALUE("%ld",endDoCad-startDoCad);
PRINTLN;
if (!e)
PRINT_CSTSTR("%s","OK2");
else
PRINT_CSTSTR("%s","###2");
PRINTLN;
}
}
else {
PRINT_CSTSTR("%s","###1\n");
// wait for random number of DIFS
#ifdef ARDUINO
uint8_t w = random(1,8);
#else
uint8_t w = rand() % 8 + 1;
#endif
PRINT_CSTSTR("%s","--> waiting for ");
PRINT_VALUE("%d",w);
PRINT_CSTSTR("%s"," DIFS (DIFS=3SIFS) = ");
PRINT_VALUE("%d",SIFS_value[loraMode]*3*w);
PRINTLN;
delay(SIFS_value[loraMode]*3*w);
PRINT_CSTSTR("%s","--> retry\n");
}
} while (e);
// CAD is OK, but need to check RSSI
if (RSSIonSend) {
e=sx1272.getRSSI();
uint8_t rssi_retry_count=10;
if (!e) {
PRINT_CSTSTR("%s","--> RSSI ");
PRINT_VALUE("%d", sx1272._RSSI);
PRINTLN;
while (sx1272._RSSI > -90 && rssi_retry_count) {
delay(1);
sx1272.getRSSI();
PRINT_CSTSTR("%s","--> RSSI ");
PRINT_VALUE("%d", sx1272._RSSI);
PRINTLN;
rssi_retry_count--;
}
}
else
PRINT_CSTSTR("%s","--> RSSI error\n");
if (!rssi_retry_count)
carrierSenseRetry=true;
else
carrierSenseRetry=false;
}
} while (carrierSenseRetry);
}
}
#endif
#define DEF_BAUDRATE 19200
#define ADC_MAX 1023 // bei 10 Bit
#define PT_IN_0 0 // analog Eingang A0
#define UEBERLAUF 9999 // Fehler bei offenem Eingang
#define R_PT0 1000.0 // bei 0 Grad C
#define R_REF 1000.0 // ext. Widerstand mit 0,1%
#define R_ZULEITUNG 0 // bei laengeren Leitungen unbedingt anpassen
#define PT_FAKTOR 3.85 // schon mit 1000.0 skaliert
int lese_PT1000(int ad_eingang) // liest den ADC-Eingang und rechnet auf Grad Celsius um
{
int temperatur, ADC_wert;
float PT_x;
analogReference(DEFAULT); // AREF einschalten
analogRead(PT_IN_0); // ADC in Betrieb nehmen
ADC_wert = analogRead(ad_eingang); // und Kanal messen
analogReference(EXTERNAL);
analogRead(7); // AREF wieder abschalten: geht nur so
if(ADC_wert < ADC_MAX) { // nur gueltige Werte auswerten
PT_x = R_REF * ADC_wert / (ADC_MAX-ADC_wert); // Widerstand ausrechnen
PT_x = PT_x - R_PT0 - R_ZULEITUNG; // Offset fuer 0 Grad abziehen
temperatur = PT_x / PT_FAKTOR; // und auf Grad C skalieren
} else temperatur = UEBERLAUF; // falls PT1000-Zuleitung offen
return temperatur;
}
void setup()
{
int e;
// for the temperature sensor
pinMode(TEMP_PIN_READ, INPUT);
// and to power the temperature sensor
pinMode(TEMP_PIN_POWER,OUTPUT);
#ifdef LOW_POWER
#ifdef __SAMD21G18A__
rtc.begin();
#endif
#else
digitalWrite(TEMP_PIN_POWER,HIGH);
#endif
delay(3000);
// Open serial communications and wait for port to open:
#if defined __SAMD21G18A__ && not defined ARDUINO_SAMD_FEATHER_M0
SerialUSB.begin(38400);
#else
Serial.begin(38400);
#endif
// Print a start message
PRINT_CSTSTR("%s","LoRa temperature sensor, extended version\n");
#ifdef ARDUINO_AVR_PRO
PRINT_CSTSTR("%s","Arduino Pro Mini detected\n");
#endif
#ifdef ARDUINO_AVR_NANO
PRINT_CSTSTR("%s","Arduino Nano detected\n");
#endif
#ifdef ARDUINO_AVR_MINI
PRINT_CSTSTR("%s","Arduino MINI/Nexus detected\n");
#endif
#ifdef __MK20DX256__
PRINT_CSTSTR("%s","Teensy31/32 detected\n");
#endif
#ifdef __MKL26Z64__
PRINT_CSTSTR("%s","TeensyLC detected\n");
#endif
#ifdef __SAMD21G18A__
PRINT_CSTSTR("%s","Arduino M0/Zero detected\n");
#endif
// Power ON the module
sx1272.ON();
#ifdef WITH_EEPROM
// get config from EEPROM
EEPROM.get(0, my_sx1272config);
// found a valid config?
if (my_sx1272config.flag1==0x12 && my_sx1272config.flag2==0x34) {
PRINT_CSTSTR("%s","Get back previous sx1272 config\n");
// set sequence number for SX1272 library
sx1272._packetNumber=my_sx1272config.seq;
PRINT_CSTSTR("%s","Using packet sequence number of ");
PRINT_VALUE("%d", sx1272._packetNumber);
PRINTLN;
}
else {
// otherwise, write config and start over
my_sx1272config.flag1=0x12;
my_sx1272config.flag2=0x34;
my_sx1272config.seq=sx1272._packetNumber;
}
#endif
// Set transmission mode and print the result
e = sx1272.setMode(loraMode);
PRINT_CSTSTR("%s","Setting Mode: state ");
PRINT_VALUE("%d", e);
PRINTLN;
if (loraMode==1)
w_timer=2500;
#ifdef LORA_LAS
loraLAS.setSIFS(loraMode);
#endif
#ifdef CUSTOM_CS
if (loraMode>7)
SIFS_cad_number=6;
else
SIFS_cad_number=3;
// SIFS=3CAD and DIFS=3SIFS
// here we use a DIFS prior to data transmission
send_cad_number=3*SIFS_cad_number;
#ifdef LOW_POWER
// TODO: with low power, when setting the radio module in sleep mode
// there seem to be some issue with RSSI reading
RSSIonSend=false;
#endif
#else
// enable carrier sense
sx1272._enableCarrierSense=true;
#ifdef LOW_POWER
// TODO: with low power, when setting the radio module in sleep mode
// there seem to be some issue with RSSI reading
sx1272._RSSIonSend=false;
#endif
#endif
// Select frequency channel
e = sx1272.setChannel(DEFAULT_CHANNEL);
PRINT_CSTSTR("%s","Setting Channel: state ");
PRINT_VALUE("%d", e);
PRINTLN;
// Select amplifier line; PABOOST or RFO
#ifdef PABOOST
sx1272._needPABOOST=true;
// previous way for setting output power
// powerLevel='x';
#else
// previous way for setting output power
// powerLevel='M';
#endif
// previous way for setting output power
// e = sx1272.setPower(powerLevel);
e = sx1272.setPowerDBM((uint8_t)MAX_DBM);
PRINT_CSTSTR("%s","Setting Power: state ");
PRINT_VALUE("%d", e);
PRINTLN;
// Set the node address and print the result
e = sx1272.setNodeAddress(node_addr);
PRINT_CSTSTR("%s","Setting node addr: state ");
PRINT_VALUE("%d", e);
PRINTLN;
#ifdef TO_LORAWAN_GW
e = sx1272.setSyncWord(0x34);
PRINT_CSTSTR("%s","Set sync word to 0x34 state ");
PRINT_VALUE("%d", e);
PRINTLN;
#endif
// Print a success message
PRINT_CSTSTR("%s","SX1272 successfully configured\n");
#ifdef LORA_LAS
loraLAS.ON(LAS_ON_WRESET);
#endif
//printf_begin();
delay(500);
}
#if not defined _VARIANT_ARDUINO_DUE_X_ && defined FLOAT_TEMP
char *ftoa(char *a, double f, int precision)
{
long p[] = {0,10,100,1000,10000,100000,1000000,10000000,100000000};
char *ret = a;
long heiltal = (long)f;
itoa(heiltal, a, 10);
while (*a != '\0') a++;
*a++ = '.';
long desimal = abs((long)((f - heiltal) * p[precision]));
itoa(desimal, a, 10);
return ret;
}
#endif
void loop(void)
{
long startSend;
long endSend;
uint8_t app_key_offset=0;
int e;
#ifdef LORA_LAS
// call periodically to be able to detect the start of a new cycle
loraLAS.checkCycle();
#else
//if (loraLAS._has_init && (millis()-lastTransmissionTime > 120000)) {
#endif
#ifndef LOW_POWER
// 600000+random(15,60)*1000
if (millis() > nextTransmissionTime) {
#endif
#ifdef LOW_POWER
digitalWrite(TEMP_PIN_POWER,HIGH);
// security?
delay(200);
int value = analogRead(TEMP_PIN_READ);
#else
int value = analogRead(TEMP_PIN_READ);
#endif
// change here how the temperature should be computed depending on your sensor type
//
temp = lese_PT1000(PT_IN_0);
digitalWrite(TEMP_PIN_POWER,LOW);
PRINT_CSTSTR("%s","Reading ");
PRINT_VALUE("%d", value);
PRINTLN;
//temp = temp - 0.5;
//temp = temp / 10.0;
PRINT_CSTSTR("%s","Temp is ");
PRINT_VALUE("%f", temp);
PRINTLN;
#if defined WITH_APPKEY && not defined WITH_AES
app_key_offset = sizeof(my_appKey);
// set the app key in the payload
memcpy(message,my_appKey,app_key_offset);
#endif
uint8_t r_size;
// then use app_key_offset to skip the app key
#ifdef _VARIANT_ARDUINO_DUE_X_
#ifdef NEW_DATA_FIELD
r_size=sprintf((char*)message+app_key_offset, "\\!#%d#TC/%.2f", field_index, temp);
#else
r_size=sprintf((char*)message+app_key_offset, "\\!#%d#%.2f", field_index, temp);
#endif
#else
#ifdef FLOAT_TEMP
ftoa(float_str,temp,2);
#ifdef NEW_DATA_FIELD
r_size=sprintf((char*)message+app_key_offset, "\\!#%d#TC/%s", field_index, float_str);
#else
// this is for testing, uncomment if you just want to test, without a real temp sensor plugged
//strcpy(float_str, "21.55567");
r_size=sprintf((char*)message+app_key_offset, "\\!#%d#%s", field_index, float_str);
#endif
#else
#ifdef NEW_DATA_FIELD
r_size=sprintf((char*)message+app_key_offset, "\\!#%d#TC/%d", field_index, (int)temp);
#else
r_size=sprintf((char*)message+app_key_offset, "\\!#%d#%d", field_index, (int)temp);
#endif
#endif
#endif
PRINT_CSTSTR("%s","Sending ");
PRINT_STR("%s",(char*)(message+app_key_offset));
PRINTLN;
PRINT_CSTSTR("%s","Real payload size is ");
PRINT_VALUE("%d", r_size);
PRINTLN;
int pl=r_size+app_key_offset;
#ifdef WITH_AES
// if encryption then we DO NOT use appkey
//
PRINT_STR("%s",(char*)message);
PRINTLN;
PRINT_CSTSTR("%s","plain payload hex\n");
for (int i=0; i> 8) & 0x00FF);
LORAWAN_Data[8] = Frame_Port;
//Set Current package length
LORAWAN_Package_Length = 9;
//Load Data
for(int i = 0; i < r_size; i++)
{
// see that we don't take the appkey, just the encrypted data that starts that message[app_key_offset]
LORAWAN_Data[LORAWAN_Package_Length + i] = message[i];
}
//Add data Lenth to package length
LORAWAN_Package_Length = LORAWAN_Package_Length + r_size;
PRINT_CSTSTR("%s","calculate MIC with NwkSKey\n");
//Calculate MIC
Calculate_MIC(LORAWAN_Data, MIC, LORAWAN_Package_Length, Frame_Counter_Up, Direction);
//Load MIC in package
for(int i=0; i < 4; i++)
{
LORAWAN_Data[i + LORAWAN_Package_Length] = MIC[i];
}
//Add MIC length to package length
LORAWAN_Package_Length = LORAWAN_Package_Length + 4;
PRINT_CSTSTR("%s","transmitted LoRaWAN-like packet:\n");
PRINT_CSTSTR("%s","MHDR[1] | DevAddr[4] | FCtrl[1] | FCnt[2] | FPort[1] | EncryptedPayload | MIC[4]\n");
//Print transmitted data
for(int i = 0; i < LORAWAN_Package_Length; i++)
{
if (LORAWAN_Data[i]<16)
PRINT_CSTSTR("%s","0");
PRINT_HEX("%X", LORAWAN_Data[i]);
PRINT_CSTSTR("%s"," ");
}
PRINTLN;
// copy back to message
memcpy(message,LORAWAN_Data,LORAWAN_Package_Length);
pl = LORAWAN_Package_Length;
#ifdef LORAWAN
PRINT_CSTSTR("%s","end-device uses native LoRaWAN packet format\n");
// indicate to SX1272 lib that raw mode at transmission is required to avoid our own packet header
sx1272._rawFormat=true;
#else
PRINT_CSTSTR("%s","end-device uses encapsulated LoRaWAN packet format only for encryption\n");
#endif
// in any case, we increment Frame_Counter_Up
// even if the transmission will not succeed
Frame_Counter_Up++;
#endif
#ifdef CUSTOM_CS
CarrierSense();
#else
sx1272.CarrierSense();
#endif
startSend=millis();
#ifdef WITH_AES
// indicate that payload is encrypted
// DO NOT take into account appkey
sx1272.setPacketType(PKT_TYPE_DATA | PKT_FLAG_DATA_ENCRYPTED);
#else
#ifdef WITH_APPKEY
// indicate that we have an appkey
sx1272.setPacketType(PKT_TYPE_DATA | PKT_FLAG_DATA_WAPPKEY);
#else
// just a simple data packet
sx1272.setPacketType(PKT_TYPE_DATA);
#endif
#endif
#ifdef LORA_LAS
e = loraLAS.sendData(DEFAULT_DEST_ADDR, (uint8_t*)message, pl, 0,
LAS_FIRST_DATAPKT+LAS_LAST_DATAPKT, LAS_NOACK);
if (e==TOA_OVERUSE) {
PRINT_CSTSTR("%s","Not sent, TOA_OVERUSE\n");
}
if (e==LAS_LBT_ERROR) {
PRINT_CSTSTR("%s","LBT error\n");
}
if (e==LAS_SEND_ERROR || e==LAS_ERROR) {
PRINT_CSTSTR("%s","Send error\n");
}
#else
// Send message to the gateway and print the result
// with the app key if this feature is enabled
#ifdef WITH_ACK
int n_retry=NB_RETRIES;
do {
e = sx1272.sendPacketTimeoutACK(DEFAULT_DEST_ADDR, message, pl);
if (e==3)
PRINT_CSTSTR("%s","No ACK");
n_retry--;
if (n_retry)
PRINT_CSTSTR("%s","Retry");
else
PRINT_CSTSTR("%s","Abort");
} while (e && n_retry);
#else
e = sx1272.sendPacketTimeout(DEFAULT_DEST_ADDR, message, pl);
#endif
#endif
endSend=millis();
#ifdef LORAWAN
// switch back to normal behavior
sx1272._rawFormat=false;
#endif
#ifdef WITH_EEPROM
// save packet number for next packet in case of reboot
my_sx1272config.seq=sx1272._packetNumber;
EEPROM.put(0, my_sx1272config);
#endif
PRINT_CSTSTR("%s","LoRa pkt size ");
PRINT_VALUE("%d", pl);
PRINTLN;
PRINT_CSTSTR("%s","LoRa pkt seq ");
PRINT_VALUE("%d", sx1272.packet_sent.packnum);
PRINTLN;
PRINT_CSTSTR("%s","LoRa Sent in ");
PRINT_VALUE("%ld", endSend-startSend);
PRINTLN;
PRINT_CSTSTR("%s","LoRa Sent w/CAD in ");
PRINT_VALUE("%ld", endSend-sx1272._startDoCad);
PRINTLN;
PRINT_CSTSTR("%s","Packet sent, state ");
PRINT_VALUE("%d", e);
PRINTLN;
#ifdef LOW_POWER
PRINT_CSTSTR("%s","Switch to power saving mode\n");
e = sx1272.setSleepMode();
if (!e)
PRINT_CSTSTR("%s","Successfully switch LoRa module in sleep mode\n");
else
PRINT_CSTSTR("%s","Could not switch LoRa module in sleep mode\n");
FLUSHOUTPUT
delay(50);
#ifdef __SAMD21G18A__
// For Arduino M0 or Zero we use the built-in RTC
//LowPower.standby();
rtc.setTime(17, 0, 0);
rtc.setDate(1, 1, 2000);
rtc.setAlarmTime(17, idlePeriodInMin, 0);
// for testing with 20s
//rtc.setAlarmTime(17, 0, 20);
rtc.enableAlarm(rtc.MATCH_HHMMSS);
//rtc.attachInterrupt(alarmMatch);
rtc.standbyMode();
PRINT_CSTSTR("%s","SAMD21G18A wakes up from standby\n");
FLUSHOUTPUT
#else
nCycle = idlePeriodInMin*60/LOW_POWER_PERIOD + random(2,4);
#if defined __MK20DX256__ || defined __MKL26Z64__ || defined __MK64FX512__ || defined __MK66FX1M0__
// warning, setTimer accepts value from 1ms to 65535ms max
timer.setTimer(LOW_POWER_PERIOD*1000 + random(1,5)*1000);// milliseconds
nCycle = idlePeriodInMin*60/LOW_POWER_PERIOD;
#endif
for (int i=0; i