/*
**************************************************************************************************
ProMiniLoRaTracker_V1 Programs
Copyright of the author Stuart Robinson - 02/07/2015 15:00
These programs may be used free of charge for personal, recreational and educational purposes only.
This program, or parts of it, may not be used for or in connection with any commercial purpose without
the explicit permission of the author Stuart Robinson.
The programs are supplied as is, it is up to individual to decide if the programs are suitable for the
intended purpose and free from errors.
**************************************************************************************************
*/
//Hardware definitions
const byte lora_PNSS = 10; //pin number where the NSS line for the LoRa device is connected.
const byte PLED1 = 8; //pin number for LED on Tracker
const byte lora_PReset = 9; //pin where LoRa device reset line is connected
const byte lora_PPWMCH = 3; //pin number for tone generation, connects to LoRa device DIO2.
static const int RXPin = A5, TXPin = A6; //pins for soft serial
static const uint32_t GPSBaud = 9600; //GPS
String InputString = ""; //data on buff is copied to this string
String Outputstring = "";
float BattVolts;
//char charVal[20];
#include <SPI.h>
#include "LoRaTX.h"
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
TinyGPSPlus gps; // The TinyGPS++ object
SoftwareSerial ss(RXPin, TXPin); // The serial connection to the GPS device
///////////////////////////////////////////////////////////////////////////////////////
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
{
displayInfo();
}
if (millis() > 5000 && gps.charsProcessed() < 10)
{
digitalWrite(PLED1, HIGH);
//Serial.println("No GPS detected!");
while (true);
}
}
/////////////////////////////////////////////////////////////////////////////////////////
void displayInfo()
{
//Serial.print("Location: ");
byte i;
byte ltemp;
batt_read();
Outputstring = "";
if (gps.location.isValid())
{
addtostring(gps.location.lat(), 5, 5, ",");
addtostring(gps.location.lng(), 5, 5, ",");
addtostring(gps.altitude.meters(), 3, 0, ",");
addtostring(BattVolts, 4, 2, ",*");
// at this point Outputstring has the LoRa Telemetry data to send
//Serial.print("OutputString is ");
//Serial.println(Outputstring);
ltemp = Outputstring.length();
lora_SetModem(lora_BW125, lora_SF12, lora_CR4_5, lora_Explicit, lora_LowDoptON); //Setup the LoRa modem parameters, default: (lora_BW41_7, lora_SF12, lora_CR4_5, lora_Explicit, lora_LowDoptON)
//lora_PrintModem(); //Print the modem parameters
lora_TXStart = 0;
lora_TXEnd = 0;
for (i = 0; i <= ltemp; i++)
{
lora_TXBUFF[i] = Outputstring.charAt(i);
}
i--;
lora_TXEnd = i;
digitalWrite(PLED1, HIGH); //LED on during packet
lora_Send(lora_TXStart, lora_TXEnd, 60, 255, 1, 10, 10); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd
digitalWrite(PLED1, LOW);
lora_TXPKTInfo(); //print packet information
lora_TXBuffPrint(0);
//Serial.println();
delay(1000); //default: (7000)
}
else
{
// at this point Outputstring has the LoRa Telemetry data to send
digitalWrite(PLED1, HIGH);
Outputstring = "No GPS-Fix";
//Serial.println(Outputstring);
ltemp = Outputstring.length();
lora_SetModem(lora_BW125, lora_SF12, lora_CR4_5, lora_Explicit, lora_LowDoptON); //Setup the LoRa modem parameters, default: (lora_BW41_7, lora_SF12, lora_CR4_5, lora_Explicit, lora_LowDoptON)
//lora_PrintModem(); //Print the modem parameters
lora_TXStart = 0;
lora_TXEnd = 0;
for (i = 0; i <= ltemp; i++)
{
lora_TXBUFF[i] = Outputstring.charAt(i);
}
i--;
lora_TXEnd = i;
digitalWrite(PLED1, HIGH); //LED on during packet
lora_Send(lora_TXStart, lora_TXEnd, 60, 255, 1, 10, 10); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd
digitalWrite(PLED1, LOW);
lora_TXPKTInfo(); //print packet information
lora_TXBuffPrint(0);
//Serial.println();
delay(1000); //default: (7000)
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void addtostring(double lFloat, byte lmin, byte lprecision, String Stuff) // from dtostrf3
{
char charVal[10]; //temporarily holds data from vals
memset(charVal, 0, sizeof(charVal)); //clear array
InputString = "";
dtostrf(lFloat, lmin, lprecision, charVal); //lmin is mininum width, lprecision is precision
for (int i = 0; i < sizeof(charVal); i++)
{
if (charVal[i] == 0)
{
break;
}
InputString += charVal[i];
}
//return InputString;
Outputstring = Outputstring + InputString + Stuff;
}
/////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
Serial.begin(9600); //Serial console ouput
//Serial.println("ProMiniLoRaTracker_V1");
//Serial.println("Stuart Robinson - July 2015");
//Serial.println();
pinMode(lora_PReset, OUTPUT); // RFM98 reset line
digitalWrite(lora_PReset, LOW); // Reset RFM98
pinMode (lora_PNSS, OUTPUT); // set the slaveSelectPin as an output:
digitalWrite(lora_PNSS, HIGH);
pinMode(PLED1, OUTPUT); // for shield LED
SPI.begin(); // initialize SPI:
SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
lora_ResetDev(); //Reset the device
lora_Setup(); //Do the initial LoRa Setup
lora_SetFreq(108, 153, 153); //Set the LoRa frequency, 434.400 Mhz
lora_Tone(1000, 1000, 10); //Transmit an FM tone, 1000hz, 100ms
ss.begin(GPSBaud); //Startup soft serial for GPS
}
///////////////////////////////////////////////////////////////////////////////////////
void batt_read()
{
int BattRead = analogRead(A1);
lora_TXBUFF[1] = (BattRead / 256); //MSB of battery volts
lora_TXBUFF[0] = (BattRead - (lora_TXBUFF[1] * 256)); //LSB of battery volts
BattVolts = (BattRead * (10.4 / 1023.0));
Serial.print("lora_TXBUFF[0] ");
Serial.println(lora_TXBUFF[0]);
Serial.print("lora_TXBUFF[1] ");
Serial.println(lora_TXBUFF[1]);
Serial.println("Battery ");
Serial.print(BattVolts, 2);
Serial.println("V");
}
/*****************************************************************************************************
ProMiniLoRaTracker_RX_V2 Programs
Copyright of the author Stuart Robinson - 18/07/2015 15:00
These programs may be used free of charge for personal, recreational and educational purposes only.
This program, or parts of it, may not be used for or in connection with any commercial purpose without
the explicit permission of the author Stuart Robinson.
The programs are supplied as is, it is up to individual to decide if the programs are suitable for the
intended purpose and free from errors.
Modified by DJ7OO for transmitting the battery voltage and providing GGA output sentences serially.
******************************************************************************************************/
//Hardware definitions
const byte lora_PNSS = 10; //pin number where the NSS line for the LoRa device is connected.
const byte PLED1 = 8; //pin number for LED on Tracker
const byte PBUZZ = 4; //pin number for Buzzer on Tracker
const byte lora_PReset = 9; //pin where LoRa device reset line is connected
const byte lora_PPWMCH = 3; //pin number for tone generation, connects to LoRa device DIO2.
const int RXPin = A5, TXPin = A2; //pins for soft serial
const uint32_t GPSBaud = 9600; //GPS and Digole Serial LCD
float Hlat, Hlon, Tlat, Tlon, Tvolt; //define the GPS lat and long variables
int Talt; //define GPS altitude variable
const int PayloadArraySize = 4;
String results[PayloadArraySize];
String InputString = ""; //data on buff is copied to this string
String outString = "";
String Ns, Ew;
float Lat, Lon;
byte index = 0;
byte start_with = 0;
byte end_with = 78;
byte CRC = 0;
int cnt = 1;
#include <SPI.h>
#include "LoRaCommon.h"
#include "LoRaRXonly.h"
#include "LoRaTXonly.h"
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);
///////////////////////////////////////////////////////////////////////////////////
void loop()
{
checkforpacket();
delay(1000);
}
///////////////////////////////////////////////////////////////////////////////////
float convertstring(String inString)
{
char buf[20];
inString.toCharArray(buf,(inString.length()+1));
float val = atof(buf);
return val;
}
//////////////////////////////////////////////////////////////////////////////////
void setup()
{
Serial.begin(9600); //Serial console ouput
// OLED startmessage
u8g.firstPage();
do {
u8g.setFont(u8g_font_unifont);
u8g.setPrintPos(16,10);
u8g.print("LoRa-DECODER");
u8g.setPrintPos(1,40);
u8g.print("WAITING FOR DATA");
} while ( u8g.nextPage() );
delay(100);
//ss.begin(GPSBaud); //Startup soft serial for GPS
pinMode(lora_PReset, OUTPUT); // RFM98 reset line
digitalWrite(lora_PReset, LOW); // Reset RFM98
pinMode (lora_PNSS, OUTPUT); // set the slaveSelectPin as an output:
digitalWrite(lora_PNSS, HIGH);
pinMode(PLED1, OUTPUT); // for shield LED
pinMode(PBUZZ, OUTPUT); // for shield Buzzer
SPI.begin(); // initialize SPI:
SPI.setClockDivider(SPI_CLOCK_DIV2);
SPI.setDataMode(SPI_MODE0);
SPI.setBitOrder(MSBFIRST);
lora_Setup(); //Do the initial LoRa Setup
lora_SetFreq(108, 153, 153); //Set the LoRa frequency, 434.400 Mhz
lora_Tone(1000, 1000, 10); //Transmit an FM tone
lora_SetModem(lora_BW125, lora_SF12, lora_CR4_5, lora_Explicit, lora_LowDoptON); //Setup the LoRa modem parameters, default: (lora_BW41_7, lora_SF12, lora_CR4_5, lora_Explicit, lora_LowDoptON)
//lora_PrintModem(); //Print the modem parameters
lora_RXtoReady();
}
//////////////////////////////////////////////////////////////////////////////////
void FillPayloadArray(byte llora_RXStart, byte llora_RXEnd)
//fills payload array from RC buffer
{
byte i = 0;
byte j = 0;
byte lvar1 = 0;
String tempstring;
for (i = llora_RXStart; i < llora_RXEnd; i++)
{
lvar1 = lora_RXBUFF[i];
if (lvar1 == 44)
{
results[j] = tempstring;
j++;
tempstring = "";
if (j > PayloadArraySize)
{
//Serial.print("ERROR To many Payload Fields ");
//Serial.println(j);
break;
}
}
else
{
tempstring = tempstring + char(lvar1);
}
}
}
//////////////////////////////////////////////////////////////////////////////////
void checkforpacket()
{
byte lora_LRegData;
byte lora_Ltemp;
String floatstring;
lora_Ltemp = lora_readRXready();
if (lora_Ltemp == 0)
{
//Serial.print("NP."); //NP = No Packet
}
if (lora_Ltemp == 64) //if no receive error, print packet contents as ASCII
{
digitalWrite(PLED1, HIGH);
digitalWrite(PBUZZ, HIGH);
//Serial.println("Packet Ready ");
lora_ReadPacket();
//lora_RXPKTInfo(); //print the info on received packet
//lora_RXBuffPrint(0); //Print contents of RX buffer as ASCII,decimal or HEX
FillPayloadArray(lora_RXStart, lora_RXEnd);
Tlat = convertstring(results[0]);
Tlon = convertstring(results[1]);
Talt = results[2].toInt();
Tvolt = convertstring(results[3]);
if(Tlat<0) { Ns = "S"; } else { Ns = "N"; }
if(Tlon<0) { Ew = "W"; } else { Ew = "E"; }
//Serial.println(Tlat,5);
//Serial.println(Tlon,5);
//Serial.println(Talt);
//Serial.println(Tvolt);
if(Tlat < 0) { Tlat= -Tlat; }
unsigned int Deg_Lat = Tlat;
Lat = 100*(Deg_Lat) + (Tlat - Deg_Lat)*60;
if(Tlon < 0) { Tlon= -Tlon; }
unsigned int Deg_Lon = Tlon;
Lon = 100*(Deg_Lon) + (Tlon - Deg_Lon)*60;
//Serial.println(" ");
//Serial.print("Lat: ");
//Serial.println(Lat);
//Serial.print("Lon: ");
//Serial.println(Lon);
//Serial.println(" ");
// building GGA sentence
outString = "GNGGA,000000,"; //SentenceIdentifier,Time
if(Tlat<10) {outString += "0"; }
outString += String(Lat,4); //latitude
outString += ",";
outString += Ns; //N or S latitude
outString += ",";
if(Tlon<100) {outString += "0"; }
if(Tlon<10) {outString += "0"; }
outString += String(Lon,4); //longitude
outString += ",";
outString += Ew; //E or W longitude
outString += ",1,10,1.5,"; //,FixQuality,NumberOfSats,HDOP,
outString += Talt; //Altitude [m]
outString += ".0,M,0.0,M,,,"; //,M,HeightAboveWGS84,M,-,-,
// checksum calculation
for (byte x = start_with; x<end_with; x++)
{ // XOR every character in between '$' and '*'
CRC = CRC ^ outString[x] ;
}
// finalizing and sending GPGGA sentence
Serial.print("$");
Serial.print(outString);
Serial.print("*");
Serial.println(CRC,HEX);
// OLED Display
Display();
// Upcounter
cnt = cnt+1;
if(cnt>999) {cnt=1; }
outString = "";
lora_RXtoReady(); // ready for next and clear flags
digitalWrite(PLED1, LOW);
digitalWrite(PBUZZ, LOW);
}
if (lora_Ltemp == 96)
{
//Serial.println();
//Serial.println("CRC Error in packet");
lora_RXtoReady(); // ready for next and clear flags
}
}
////////////////////////////////////////////////////////////////////////
void Display()
{
u8g.firstPage();
do {
u8g.setFont(u8g_font_unifont);
u8g.setPrintPos(2,10);
u8g.print("LoRa-Decoder");
u8g.setPrintPos(104,10);
if(cnt<100) {
u8g.print("0"); }
if(cnt<10) {
u8g.print("0"); }
u8g.print(cnt);
u8g.setPrintPos(5,28);
u8g.print("Lat: ");
u8g.print(Tlat,5);
// u8g.print(" ");
// u8g.print(Ns);
u8g.setPrintPos(5,40);
u8g.print("Lon: ");
u8g.print(Tlon,5);
// u8g.print(" ");
// u8g.print(Ew);
u8g.setPrintPos(5,52);
u8g.print("A: ");
u8g.print(Talt);
u8g.print("m");
u8g.setPrintPos(80,52);
if (lora_PacketSNR > 127)
{
u8g.print("-");
u8g.print((255 - lora_PacketSNR) / 4);
}
else
{
u8g.print("+");
u8g.print( (lora_PacketSNR) / 4);
}
u8g.print("db");
u8g.setPrintPos(5,64);
u8g.print("UBatt: ");
u8g.print(Tvolt);
u8g.print("V");
} while
( u8g.nextPage() );
}