LightTracker-1.0/lorawan-otaa-asset-tracker/lorawan-otaa-asset-tracker.ino

861 wiersze
28 KiB
C++

#include <basicmac.h>
#include <hal/hal.h>
#include <Adafruit_BMP085.h>
#include "SparkFun_Ublox_Arduino_Library.h"
#include <MemoryFree.h>;
#include <CayenneLPP.h>
#include "SparkFunLIS3DH.h"
#include <Adafruit_SSD1306.h>
// SX1262 has the following connections:
#define nssPin 8
#define rstPin 9
#define dio1Pin 3
#define busyPin 2
#define BattPin A5
#define GpsPwr 12
#define GpsON digitalWrite(GpsPwr, LOW);
#define GpsOFF digitalWrite(GpsPwr, HIGH);
SFE_UBLOX_GPS myGPS;
Adafruit_BMP085 bmp; //temp and pressure sensor
LIS3DH myIMU; //accelerometer
#define SSD1306_WHITE 1 ///< Draw 'on' pixels
//#define DEVMODE // Development mode. Uncomment to enable for debugging.
boolean airborne = false; //if you want to put the tracker on an airborne (balloon, drone, plane, etc.) device, set this variable true;
uint8_t measurementSystem = 0; //0 for metric (meters, km, Celcius, etc.), 1 for imperial (feet, mile, Fahrenheit,etc.)
//***************************** UPDATE HERE WITH YOUR DEVICE KEYS **************************************/
//You should copy device keys from Helium or TTN Console and update following keys. Please check out: https://github.com/lightaprs/LightTracker-1.0/wiki/Adding-Device-on-Helium-Console
// This EUI must be in little-endian format, so least-significant-byte (lsb)
// first. When copying an EUI from Helium Console or ttnctl output, this means to reverse the bytes.
static const u1_t PROGMEM DEVEUI[8]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //helium or ttn
// This EUI must be in little-endian format, so least-significant-byte (lsb)
// first. When copying an EUI from Helium Console or ttnctl output, this means to reverse the bytes.
static const u1_t PROGMEM APPEUI[8]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //helium or ttn
// 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 Helium Console or ttnctl can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //helium or ttn
//*****************************************************************************************************/
//************************** LoRaWAN Settings ********************
//DO NOT FORGET TO CHANGE YOUR REGION, DEFAULT REGION IS EU. Uncomment your region, but comment other regions
uint8_t Lorawan_region_code = REGCODE_EU868;//For EU
//uint8_t Lorawan_region_code = REGCODE_US915;//For North America
//uint8_t Lorawan_region_code = REGCODE_AS923;//For Asia
//uint8_t Lorawan_region_code = REGCODE_AU915;//For South America and Australia
//uint8_t Lorawan_region_code = REGCODE_IN865;//For India and Pakistan
const unsigned TX_INTERVAL = 60000; // Schedule TX every this many miliseconds (might become longer due to duty cycle limitations).
boolean gpsFixRequiredforTX = true; //By default GPS fix required for telemetry TX (but not required for OTAA join)
//Spreading Factor automatically selected by BasicMAC LoRaWAN Library. Keep this "true" if you want to use your tracker in urban areas.
//But if you are too far from the the gateways/hotspots then change it to "false"
boolean autoSF = true;
//try to keep telemetry size smaller than 51 bytes if possible. Default telemetry size is 45 bytes.
CayenneLPP telemetry(51);
u1_t os_getRegion (void) { return Lorawan_region_code; } //do not change this.
uint8_t channelNoFor2ndSubBand = 8; //do not change this. Used for US915 and AU915 / TTN and Helium
uint32_t last_packet = 0; //do not change this. Timestamp of last packet sent.
boolean ev_joined = false;
//pinmap for SX1262 LoRa module
#if !defined(USE_STANDARD_PINMAP)
const lmic_pinmap lmic_pins = {
.nss = nssPin,
.tx = LMIC_UNUSED_PIN,
.rx = LMIC_UNUSED_PIN,
.rst = rstPin,
.dio = {/* DIO0 */ LMIC_UNUSED_PIN, /* DIO1 */ dio1Pin, /* DIO2 */ LMIC_UNUSED_PIN},
.busy = busyPin,
.tcxo = LMIC_CONTROLLED_BY_DIO3,
};
#endif // !defined(USE_STANDARD_PINMAP)
//************************** uBlox GPS Settings ********************
long lastTime = 0; //Simple local timer. Limits amount if I2C traffic to Ublox module.
//********************************* Power Settings ******************************
int battWait=60; //seconds sleep if super capacitors/batteries are below battMin (important if power source is solar panel)
float battMin=2.7; // min Volts to TX.
//********************************* Misc Settings ******************************
int txCount = 1;
float voltage = 0;
float tempAltitudeLong = 0;
float tempAltitudeShort = 0;
float tempSpeed = 0;
float tempTemperature = 0;
float tempLatitude = 0;
float tempLongitude = 0;
float tempSats = 0;
float tempHeading = 0;
float tempPressure = 0;
static char tempUnit[2] = ""; //C or F
static char speedUnit[7] = ""; //km/h or mph (mile per hour)
static char altUnit[5] = ""; //meters or feet
static char distUnit[5] = ""; //km or mile
static char measureSystem[10] = ""; //km or mile
static char regionName[6] ="";
//********** OLED Display Settings ****************//
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
int displayPageID = 1;
int displayInterval = 7;
uint32_t last_display_refreshed = -10000;
void setup() {
pinMode(A1,INPUT_PULLUP);
if(digitalRead(A1)==LOW) while(1);
delay(5000); //do not change this
pinMode(GpsPwr, OUTPUT);
SerialUSB.begin(115200);
// Wait up to 5 seconds for serial to be opened, to allow catching
// startup messages on native USB boards (that do not reset when
// serial is opened).
unsigned long start = millis();
while (millis() - start < 5000 && !SerialUSB);
SerialUSB.println();
SerialUSB.println(F("Starting"));
SerialUSB.println();
GpsON;
delay(1000);
SerialUSB.println(F("GPS setup"));
setupGPS_BMP();
delay(2000);
if(airborne){
SerialUSB.println(F("Airborne mode initiated..."));
setupUBloxDynamicModel(); // Set the dynamic model to DYN_MODEL_AIRBORNE4g
autoSF = false; //override LoRaWAN auto Spreading Factor selection setting
}
SerialUSB.println(F("Searching for GPS fix..."));
setupAccel();
//OLED Display
setupDisplay();
SerialUSB.println(F("LoRaWAN OTAA Login initiated..."));
startJoining();
SerialUSB.println(F("LoRaWAN OTAA Login successful..."));
printLoRaWANSettings();
//OLED Display
printDisplay(5);
delay(1000);
freeMem();
}
void loop() {
voltage = readBatt();
if (voltage > battMin) {
// Let LMIC handle LoRaWAN background tasks
os_runstep();
#if defined(DEVMODE)
printGPSandSensorData();
#endif
// If TX_INTERVAL passed, *and* our previous packet is not still
// pending (which can happen due to duty cycle limitations), send
// the next packet.
if ((millis() - last_packet > TX_INTERVAL && !(LMIC.opmode & (OP_JOINING|OP_TXRXPEND)))){
// Calling myGPS.getPVT() returns true if there actually is a fresh navigation solution available.
if ((myGPS.getPVT() && (myGPS.getFixType() !=0) && (myGPS.getSIV() > 0)) || !gpsFixRequiredforTX) {
updateTelemetry();
printDisplay(3);
sendLoRaWANPacket();
SerialUSB.println(F("LoRaWAN packet sent.."));
printLoRaWANSettings();
freeMem();
delay(1000);
displayPageID=2;
}
}
//update display
if (millis() - last_display_refreshed > (displayInterval * 1000)) {
printDisplay(displayPageID);
last_display_refreshed = millis();
++displayPageID;
if(displayPageID == 3) {
displayPageID = 1;
}
}
} else {
SerialUSB.println(F("Voltage is too low, please check your battery..."));
}
delay(1000);
}
void printDisplay(int pageID){
display.clearDisplay();
display.setCursor(0, 0);
switch(pageID) {
case 1:
static char fixMessage[10] = "";
if(myGPS.getFixType() !=0){
sprintf(fixMessage, "%s", "Fixed");
} else {
sprintf(fixMessage, "%s", "Not Fixed");
}
display.print("GPS Fix : ");display.println(fixMessage);
display.print("GPS Sats: ");display.println((int)myGPS.getSIV());
display.print("Lat : ");display.println(tempLatitude);
display.print("Long : ");display.println(tempLongitude);
display.print("Altitude: ");display.print((int)tempAltitudeLong);display.println(altUnit);
display.print("Speed : ");display.print((int)tempSpeed);display.println(speedUnit);
display.print("Battery : ");display.print(voltage); display.println("V");
break;
case 2:
display.print("Temp :");display.print(tempTemperature);display.println(tempUnit);
display.print("Pressure:");display.print(tempPressure); display.println("hPa");
display.print("TX Count:");display.println(txCount-1);
display.print("Freq. :");display.print(LMIC.freq/1000000.f);display.println("MHz");
display.print("SF&BW :");display.print(F("SF"));display.print(getSf(LMIC.rps) - SF7 + 7);display.print(F("BW"));display.println(125 << (getBw(LMIC.rps) - BW125));
display.print("TXPower :");display.println(LMIC.txpow + LMIC.brdTxPowOff);
if(txCount >1) {
display.print("Last TX :");display.print((millis() - last_packet)/1000); display.println(" secs ago");
}
break;
case 3:
display.println("");
display.println("");
display.println("Packet Sending...");
display.print("PcktSize: ");display.print(telemetry.getSize());display.println(" bytes");
display.println("");
break;
case 4:
display.println("");
display.println("LoRaWAN OTAA login");
display.println("initiated...");
display.println("");
display.print("Region ");display.println(regionName);
break;
case 5:
display.println("");
display.println("LoRaWAN OTAA login");
display.println("successful...");
display.println("");
display.print("Region ");display.println(regionName);
break;
default:
SerialUSB.println("default");
break;
}
display.display();
}
void setupDisplay(){
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
SerialUSB.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextSize(1); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
if(measurementSystem == 0){ //Metric
//meters
sprintf(altUnit, "%s", " m");
//km/hour
sprintf(speedUnit, "%s", " km/h");
//Celsius
sprintf(tempUnit, "%s", "C");
//km
sprintf(distUnit, "%s", " km");
//Metric
sprintf(measureSystem, "%s", "Metric");
} else { //Imperial
//feet
sprintf(altUnit, "%s", " ft");
//mile/hour
sprintf(speedUnit, "%s", " mph");
//Fahrenheit
sprintf(tempUnit, "%s", "F");
//mile
sprintf(distUnit, "%s", " m");
//Imperial
sprintf(measureSystem, "%s", "Imperial");
}
}
//to join LoRaWAN network, every region requires different parameters. Please refer to : https://lora-alliance.org/resource_hub/rp2-1-0-3-lorawan-regional-parameters/
void startJoining() {
// LMIC init
os_init(nullptr);
LMIC_reset();
// Start join
LMIC_startJoining();
//DO NOT CHANGE following code blocks unless you know what you are doing :)
//Europe
if(Lorawan_region_code == REGCODE_EU868) {
sprintf(regionName, "%s", "EU868");
if(!autoSF){
//DR2 (SF10 BW125kHz)
LMIC_setDrTxpow(2,KEEP_TXPOWADJ);
}
//Japan, Malaysia, Singapore, Brunei, Cambodia, Hong Kong, Indonesia, Laos, Taiwan, Thailand, Vietnam
} else if (Lorawan_region_code == REGCODE_AS923) {
sprintf(regionName, "%s", "AS923");
if(!autoSF){
//DR2 (SF10 BW125kHz)
//For AS923, DR2 join only since max payload limit is 11 bytes.
LMIC_setDrTxpow(2,KEEP_TXPOWADJ);
}
//North and South America (Except Brazil)
} else if (Lorawan_region_code == REGCODE_US915) {
sprintf(regionName, "%s", "US915");
if(!autoSF){
//DR0 (SF10 BW125kHz)
//For US915, DR0 join only since max payload limit is 11 bytes.
LMIC_setDrTxpow(0,KEEP_TXPOWADJ);
}
//TTN and Helium only supports second sub band (channels 8 to 15)
//so we should force BasicMAC to initiate a join with second sub band channels.
LMIC_selectChannel(8);
//Australia and New Zeleand
} else if (Lorawan_region_code == REGCODE_AU915) {
sprintf(regionName, "%s", "AU915");
if(!autoSF){
//DR2 (SF10 BW125kHz)
//For AU915, DR2 join only since max payload limit is 11 bytes.
LMIC_setDrTxpow(2,KEEP_TXPOWADJ);
}
//TTN and Helium only supports second sub band (channels 8 to 15)
//so we should force BasicMAC to initiate a join with second sub band channels.
LMIC_selectChannel(8);
}
LMIC_setAdrMode(false); //do not enable ADR (Adaptive Data Rate), does not work for every region or gateway
LMIC_setLinkCheckMode(0);
// Make sure the first packet is scheduled ASAP after join completes
last_packet = millis() - TX_INTERVAL;
//OLED Display
printDisplay(4);
// Optionally wait for join to complete (uncomment this is you want
// to run the loop while joining).
while ((LMIC.opmode & (OP_JOINING))) {
os_runstep();
}
}
// Telemetry size is very important, try to keep it lower than 51 bytes. Always lower is better.
void sendLoRaWANPacket(){
//Europa
if(Lorawan_region_code == REGCODE_EU868) {
if(!autoSF){
if(telemetry.getSize() < 52) {
//DR2 (SF10 BW125kHz) max payload size is 51 bytes.
LMIC_setDrTxpow(2,KEEP_TXPOWADJ);
} else if (telemetry.getSize() < 116){
//DR3 (SF9 BW125kHz) max payload size is 115 bytes.
LMIC_setDrTxpow(3,KEEP_TXPOWADJ);
} else {
//DR4 (SF8 BW125kHz) max payload size is 222 bytes.
LMIC_setDrTxpow(4,KEEP_TXPOWADJ);
}
}
//Japan, Malaysia, Singapore, Brunei, Cambodia, Hong Kong, Indonesia, Laos, Taiwan, Thailand, Vietnam
} else if (Lorawan_region_code == REGCODE_AS923) {
if(!autoSF){
if(telemetry.getSize() < 54) {
//DR3 (SF9 BW125kHz) max payload size is 53 bytes.
LMIC_setDrTxpow(3,KEEP_TXPOWADJ);
} else if (telemetry.getSize() < 126){
//DR4 (SF8 BW125kHz) max payload size is 125 bytes.
LMIC_setDrTxpow(4,KEEP_TXPOWADJ);
} else {
//DR5 (SF7 BW125kHz) max payload size is 222 bytes.
LMIC_setDrTxpow(5,KEEP_TXPOWADJ);
}
}
//North and South America (Except Brazil) or Australia and New Zeleand
} else if (Lorawan_region_code == REGCODE_US915 || Lorawan_region_code == REGCODE_AU915) {
if(!autoSF){
//North and South America (Except Brazil)
if (Lorawan_region_code == REGCODE_US915){
if(telemetry.getSize() < 54) {
//DR1 (SF9 BW125kHz) max payload size is 53 bytes.
LMIC_setDrTxpow(1,KEEP_TXPOWADJ);
} else if (telemetry.getSize() < 126){
//DR2 (SF8 BW125kHz) max payload size is 125 bytes.
LMIC_setDrTxpow(2,KEEP_TXPOWADJ);
} else {
//DR3 (SF7 BW125kHz) max payload size is 222 bytes.
LMIC_setDrTxpow(3,KEEP_TXPOWADJ);
}
//Australia and New Zeleand
} else if (Lorawan_region_code == REGCODE_AU915){
if(telemetry.getSize() < 54) {
//DR3 (SF9 BW125kHz) max payload size is 53 bytes.
LMIC_setDrTxpow(3,KEEP_TXPOWADJ);
} else if (telemetry.getSize() < 126){
//DR4 (SF8 BW125kHz) max payload size is 125 bytes.
LMIC_setDrTxpow(4,KEEP_TXPOWADJ);
} else {
//DR5 (SF7 BW125kHz) max payload size is 222 bytes.
LMIC_setDrTxpow(5,KEEP_TXPOWADJ);
}
}
}
//TTN and Helium only supports second sub band (channels 8 to 15)
//so we should force BasicMAC use second sub band channels.
LMIC_selectChannel(channelNoFor2ndSubBand);
++channelNoFor2ndSubBand;
if(channelNoFor2ndSubBand > 15) {
channelNoFor2ndSubBand = 8;
}
//India
} else if (Lorawan_region_code == REGCODE_IN865) {
if(!autoSF){
if(telemetry.getSize() < 52) {
//DR2 (SF10 BW125kHz) max payload size is 51 bytes.
LMIC_setDrTxpow(2,KEEP_TXPOWADJ);
} else if (telemetry.getSize() < 116){
//DR3 (SF9 BW125kHz) max payload size is 115 bytes.
LMIC_setDrTxpow(3,KEEP_TXPOWADJ);
} else {
//DR4 (SF8 BW125kHz) max payload size is 222 bytes.
LMIC_setDrTxpow(4,KEEP_TXPOWADJ);
}
}
}
LMIC_setAdrMode(false);
LMIC_setLinkCheckMode(0);
LMIC_setTxData2(1, telemetry.getBuffer(), telemetry.getSize(), 0);
last_packet = millis();
txCount++;
SerialUSB.println(F("Packet queued..."));
}
void setupAccel() {
myIMU.settings.adcEnabled = 1;
myIMU.settings.accelSampleRate = 400; //Hz. Can be: 0,1,10,25,50,100,200,400,1600,5000 Hz
myIMU.settings.accelRange = 16; //Max G force readable. Can be: 2, 4, 8, 16
myIMU.settings.xAccelEnabled = 1;
myIMU.settings.yAccelEnabled = 1;
myIMU.settings.zAccelEnabled = 1;
//Call .begin() to configure the IMU
myIMU.begin();
delay(100);
}
void setupGPS_BMP() {
GpsON;
delay(100);
Wire.begin();
bmp.begin();
Wire.setClock(400000);
if (myGPS.begin() == false) //Connect to the Ublox module using Wire port
{
SerialUSB.println(F("Ublox GPS not detected at default I2C address. Please check wiring. Freezing."));
while (1)
;
}
// do not overload the buffer system from the GPS, disable UART output
myGPS.setUART1Output(0); //Disable the UART1 port output
myGPS.setUART2Output(0); //Disable Set the UART2 port output
myGPS.setI2COutput(COM_TYPE_UBX); //Set the I2C port to output UBX only (turn off NMEA noise)
//myGPS.enableDebugging(); //Enable debug messages over Serial (default)
myGPS.setNavigationFrequency(2);//Set output to 2 times a second. Max is 10
byte rate = myGPS.getNavigationFrequency(); //Get the update rate of this module
SerialUSB.print("Current update rate for GPS: ");
SerialUSB.println(rate);
myGPS.saveConfiguration(); //Save the current settings to flash and BBR
}
void printGPSandSensorData()
{
lastTime = millis(); //Update the timer
byte fixType = myGPS.getFixType();
SerialUSB.print(F("FixType: "));
SerialUSB.print(fixType);
int SIV = myGPS.getSIV();
SerialUSB.print(F(" Sats: "));
SerialUSB.print(SIV);
float flat = myGPS.getLatitude() / 10000000.f;
SerialUSB.print(F(" Lat: "));
SerialUSB.print(flat);
float flong = myGPS.getLongitude() / 10000000.f;
SerialUSB.print(F(" Long: "));
SerialUSB.print(flong);
float altitude = myGPS.getAltitude() / 1000;
SerialUSB.print(F(" Alt: "));
SerialUSB.print(altitude);
SerialUSB.print(F(" (m)"));
//float speed = myGPS.getGroundSpeed() * 0.0036f;
//SerialUSB.print(F(" Speed: "));
//SerialUSB.print(speed);
//SerialUSB.print(F(" (km/h)"));
//long heading = myGPS.getHeading() / 100000;
//SerialUSB.print(F(" Heading: "));
//SerialUSB.print(heading);
//SerialUSB.print(F(" (degrees)"));
SerialUSB.print(" Time: ");
SerialUSB.print(myGPS.getYear());
SerialUSB.print("-");
SerialUSB.print(myGPS.getMonth());
SerialUSB.print("-");
SerialUSB.print(myGPS.getDay());
SerialUSB.print(" ");
SerialUSB.print(myGPS.getHour());
SerialUSB.print(":");
SerialUSB.print(myGPS.getMinute());
SerialUSB.print(":");
SerialUSB.print(myGPS.getSecond());
SerialUSB.print(" Temp: ");
SerialUSB.print(bmp.readTemperature());
SerialUSB.print(" C");
SerialUSB.print(" Press: ");
SerialUSB.print(bmp.readPressure() / 100.0);
SerialUSB.print(" hPa");
//SerialUSB.print(" Accel: ");
//SerialUSB.print(myIMU.readFloatAccelX());
//SerialUSB.print(",");
//SerialUSB.print(myIMU.readFloatAccelY()- 0.98f);
//SerialUSB.print(",");
//SerialUSB.print(myIMU.readFloatAccelZ());
//SerialUSB.print(" ");
SerialUSB.println();
}
void updateTelemetry() {
tempAltitudeLong = 0; //meters or feet
tempAltitudeShort = 0; //km or miles
tempSpeed = 0; //km or miles
tempTemperature = 0; //Celcius or Fahrenheit
if(measurementSystem == 0){ //Metric
tempAltitudeLong = myGPS.getAltitude() / 1000.f; //meters
tempAltitudeShort = tempAltitudeLong / 1000.f; //kilometers
tempSpeed = myGPS.getGroundSpeed() * 0.0036f; //km/hour
tempTemperature = bmp.readTemperature(); //Celsius
} else { //Imperial
tempAltitudeLong = (myGPS.getAltitude() * 3.2808399) / 1000.f;//feet
tempAltitudeShort = tempAltitudeLong / 5280.f;//miles
tempSpeed = myGPS.getGroundSpeed() * 0.00223694f; //mile/hour
tempTemperature = (bmp.readTemperature() * 1.8f) + 32; //Fahrenheit
}
tempLatitude = myGPS.getLatitude() / 10000000.f;
tempLongitude = myGPS.getLongitude() / 10000000.f;
tempSats = myGPS.getSIV();
tempHeading = myGPS.getHeading() / 100000;
tempPressure = bmp.readPressure() / 100.0f;
//latitude,longtitude,altitude,speed,course,sattelite,battery,temp,pressure
telemetry.reset();// clear the buffer
telemetry.addGPS(1, tempLatitude, tempLongitude, tempAltitudeLong); // channel 3, coordinates and altitude (meters or feet)
telemetry.addTemperature(2, tempTemperature); // Celcius or Fahrenheit
telemetry.addAnalogInput(3, voltage); //Battery/Supercaps voltage
telemetry.addDigitalInput(4, tempSats); //GPS sattelites in view
telemetry.addAnalogInput(5, tempSpeed); //km/h or mile/h
telemetry.addDigitalInput(6, tempHeading); //course in degrees
telemetry.addBarometricPressure(7, tempPressure); //pressure
telemetry.addAccelerometer(8,myIMU.readFloatAccelX(),myIMU.readFloatAccelY(),myIMU.readFloatAccelZ());
telemetry.addAnalogInput(9, tempAltitudeShort); //kilometers or miles
}
float readBatt() {
float R1 = 560000.0; // 560K
float R2 = 100000.0; // 100K
float value = 0.0f;
do {
value =analogRead(BattPin);
value +=analogRead(BattPin);
value +=analogRead(BattPin);
value = value / 3.0f;
value = (value * 3.3) / 1024.0f;
value = value / (R2/(R1+R2));
} while (value > 20.0);
return value ;
}
void freeMem() {
#if defined(DEVMODE)
SerialUSB.print(F("Free RAM: ")); SerialUSB.print(freeMemory(), DEC); SerialUSB.println(F(" byte"));
#endif
}
void os_getJoinEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}
void os_getNwkKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}
void onLmicEvent (ev_t ev) {
SerialUSB.print(os_getTime());
SerialUSB.print(": ");
switch(ev) {
case EV_SCAN_TIMEOUT:
SerialUSB.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
SerialUSB.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
SerialUSB.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
SerialUSB.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
SerialUSB.println(F("EV_JOINING"));
break;
case EV_JOINED:
SerialUSB.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:
SerialUSB.println(F("EV_RFU1"));
break;
case EV_JOIN_FAILED:
SerialUSB.println(F("EV_JOIN_FAILED"));
break;
case EV_REJOIN_FAILED:
SerialUSB.println(F("EV_REJOIN_FAILED"));
break;
break;
case EV_TXCOMPLETE:
SerialUSB.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
SerialUSB.println(F("Received ack"));
if (LMIC.dataLen) {
SerialUSB.print(F("Received "));
SerialUSB.print(LMIC.dataLen);
SerialUSB.println(F(" bytes of payload"));
}
break;
case EV_LOST_TSYNC:
SerialUSB.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
SerialUSB.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
SerialUSB.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
SerialUSB.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
SerialUSB.println(F("EV_LINK_ALIVE"));
break;
case EV_SCAN_FOUND:
SerialUSB.println(F("EV_SCAN_FOUND"));
break;
case EV_TXSTART:
SerialUSB.println(F("EV_TXSTART"));
break;
case EV_TXDONE:
SerialUSB.println(F("EV_TXDONE"));
break;
case EV_DATARATE:
SerialUSB.println(F("EV_DATARATE"));
break;
case EV_START_SCAN:
SerialUSB.println(F("EV_START_SCAN"));
break;
case EV_ADR_BACKOFF:
SerialUSB.println(F("EV_ADR_BACKOFF"));
break;
default:
SerialUSB.print(F("Unknown event: "));
SerialUSB.println(ev);
break;
}
}
void printLoRaWANSettings(){
SerialUSB.println(F("------------------------------------------------------------------------------------"));
SerialUSB.print(F("Region: "));
SerialUSB.print(regionName);
SerialUSB.print(F(", Freq: "));
SerialUSB.print(LMIC.freq/1000000.f);
SerialUSB.print(F("MHz, SF"));
SerialUSB.print(getSf(LMIC.rps) - SF7 + 7);
SerialUSB.print(F("BW"));
SerialUSB.print(125 << (getBw(LMIC.rps) - BW125));
SerialUSB.print(F(", Power: "));
SerialUSB.print(LMIC.txpow + LMIC.brdTxPowOff);
SerialUSB.print(F("dBm, Payload Size: "));
SerialUSB.print(telemetry.getSize());
SerialUSB.println(F(" bytes"));
SerialUSB.println(F("------------------------------------------------------------------------------------"));
}
void setupUBloxDynamicModel() {
// If we are going to change the dynamic platform model, let's do it here.
// Possible values are:
// PORTABLE, STATIONARY, PEDESTRIAN, AUTOMOTIVE, SEA, AIRBORNE1g, AIRBORNE2g, AIRBORNE4g, WRIST, BIKE
//DYN_MODEL_AIRBORNE4g model increases ublox max. altitude limit from 12.000 meters to 50.000 meters.
if (myGPS.setDynamicModel(DYN_MODEL_AIRBORNE4g) == false) // Set the dynamic model to DYN_MODEL_AIRBORNE4g
{
SerialUSB.println(F("***!!! Warning: setDynamicModel failed !!!***"));
}
else
{
SerialUSB.print(F("Ublox Dynamic platform model changed successfully! : "));
SerialUSB.println(myGPS.getDynamicModel());
}
}