first commit

This commit is contained in:
2021-05-11 20:43:42 +03:00
commit 9f3ffaba30
381 changed files with 69596 additions and 0 deletions

View File

@@ -0,0 +1,419 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 28/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This program is an example of a basic GPS tracker. The program reads the GPS,
waits for an updated fix and transmits location and altitude, number of satellites in view, the HDOP
value, the fix time of the GPS and the battery voltage. This transmitter can be also be used to
investigate GPS performance. At startup there should be a couple of seconds of recognisable text from
the GPS printed to the serial monitor. If you see garbage or funny characters its likley the GPS baud
rate is wrong. If the transmitter is turned on from cold, the receiver will pick up the cold fix time,
which is an indication of GPS performance. The GPS will be powered on for around 4 seconds before the
timing of the fix starts. Outside with a good view of the sky most GPSs should produce a fix in around
45 seconds. The number of satellites and HDOP are good indications to how well a GPS is working.
The program writes direct to the LoRa devices internal buffer, no memory buffer is used.
The LoRa settings are configured in the Settings.h file.
The program has the option of using a pin to control the power to the GPS (GPSPOWER), if the GPS module
or board being used has this feature. To not use this feature set the define for GPSPOWER in the
Settings.h file to '#define GPSPOWER -1'. Also set the GPSONSTATE and GPSOFFSTATE to the appropriate logic
levels.
There is also an option of using a logic pin to turn the resistor divider used to read battery voltage on
and off. This reduces current used in sleep mode. To use the feature set the define for pin BATVREADON
in 'Settings.h' to the pin used. If not using the feature set the pin number to -1.
Serial monitor baud rate is set at 115200.
*******************************************************************************************************/
#define Program_Version "V1.2"
#define authorname "Stuart Robinson"
#include <SPI.h>
#include <SX127XLT.h>
#include "Settings.h"
#include <ProgramLT_Definitions.h>
SX127XLT LT;
#include <TinyGPS++.h> //get library here > http://arduiniana.org/libraries/tinygpsplus/
TinyGPSPlus gps; //create the TinyGPS++ object
#ifdef USESOFTSERIALGPS
#include <SoftwareSerial.h>
SoftwareSerial GPSserial(RXpin, TXpin);
#endif
#ifdef USEHARDWARESERIALGPS
#define GPSserial HARDWARESERIALPORT
#endif
uint8_t TXStatus = 0; //used to store current status flag bits of Tracker transmitter (TX)
uint8_t TXPacketL; //length of LoRa packet (TX)
float TXLat; //Latitude from GPS on Tracker transmitter (TX)
float TXLon; //Longitude from GPS on Tracker transmitter (TX)
float TXAlt; //Altitude from GPS on Tracker transmitter (TX)
uint8_t TXSats; //number of GPS satellites seen (TX)
uint32_t TXHdop; //HDOP from GPS on Tracker transmitter (TX)
uint16_t TXVolts; //Volts (battery) level on Tracker transmitter (TX)
uint32_t TXGPSFixTime; //GPS fix time in hot fix mode of GPS on Tracker transmitter (TX)
uint32_t TXPacketCount, TXErrorsCount; //keep count of OK packets and send errors
void loop()
{
if (gpsWaitFix(WaitGPSFixSeconds))
{
sendLocation(TXLat, TXLon, TXAlt, TXHdop, TXGPSFixTime);
Serial.println();
Serial.print(F("Waiting "));
Serial.print(Sleepsecs);
Serial.println(F("s"));
delay(Sleepsecs * 1000); //this sleep is used to set overall transmission cycle time
}
else
{
send_Command(NoFix); //send notification of no GPS fix.
}
}
bool gpsWaitFix(uint32_t waitSecs)
{
//waits a specified number of seconds for a fix, returns true for good fix
uint32_t startmS, waitmS, GPSonTime;
bool GPSfix = false;
float tempfloat;
uint8_t GPSchar;
GPSonTime = millis();
GPSserial.begin(9600); //start GPSserial
Serial.print(F("Wait GPS Fix "));
Serial.print(waitSecs);
Serial.println(F("s"));
waitmS = waitSecs * 1000; //convert seconds wait into mS
startmS = millis();
while ((uint32_t) (millis() - startmS) < waitmS)
{
if (GPSserial.available() > 0)
{
GPSchar = GPSserial.read();
gps.encode(GPSchar);
Serial.write(GPSchar);
}
if (gps.location.isUpdated() && gps.altitude.isUpdated() && gps.date.isUpdated())
{
GPSfix = true;
Serial.println();
Serial.print(F("Have GPS Fix "));
TXGPSFixTime = millis() - GPSonTime;
Serial.print(TXGPSFixTime);
Serial.println(F("mS"));
TXLat = gps.location.lat();
TXLon = gps.location.lng();
TXAlt = gps.altitude.meters();
TXSats = gps.satellites.value();
TXHdop = gps.hdop.value();
tempfloat = ( (float) TXHdop / 100);
Serial.print(TXLat, 5);
Serial.print(F(","));
Serial.print(TXLon, 5);
Serial.print(F(","));
Serial.print(TXAlt, 1);
Serial.print(F(","));
Serial.print(TXSats);
Serial.print(F(","));
Serial.print(tempfloat, 2);
Serial.println();
break; //exit while loop reading GPS
}
}
//if here then there has either been a fix or no fix and a timeout
if (GPSfix)
{
setStatusByte(GPSFix, 1); //set status bit to flag a GPS fix
}
else
{
setStatusByte(GPSFix, 0); //set status bit to flag no fix
Serial.println();
Serial.println(F("Timeout - No GPSFix"));
Serial.println();
GPSfix = false;
}
GPSserial.end(); //serial RX interrupts interfere with SPI, so stop GPSserial
return GPSfix;
}
void sendLocation(float Lat, float Lon, float Alt, uint32_t Hdop, uint32_t fixtime)
{
uint8_t len;
uint16_t IRQStatus;
Serial.print(F("Send Location"));
TXVolts = readSupplyVoltage(); //get the latest supply\battery volts
LT.startWriteSXBuffer(0); //initialise buffer write at address 0
LT.writeUint8(LocationPacket); //identify type of packet
LT.writeUint8(Broadcast); //who is the packet sent too
LT.writeUint8(ThisNode); //tells receiver where is packet from
LT.writeFloat(Lat); //add latitude
LT.writeFloat(Lon); //add longitude
LT.writeFloat(Alt); //add altitude
LT.writeUint8(TXSats); //add number of satellites
LT.writeUint32(Hdop); //add hdop
LT.writeUint8(TXStatus); //add tracker status
LT.writeUint32(fixtime); //add GPS fix time in mS
LT.writeUint16(TXVolts); //add tracker supply volts
LT.writeUint32(millis()); //add uptime in mS
len = LT.endWriteSXBuffer(); //close buffer write
digitalWrite(LED1, HIGH);
TXPacketL = LT.transmitSXBuffer(0, len, 10000, TXpower, WAIT_TX);
digitalWrite(LED1, LOW);
if (TXPacketL)
{
TXPacketCount++;
Serial.println(F(" - Done "));
Serial.print(F("SentOK,"));
Serial.print(TXPacketCount);
Serial.print(F(",Errors,"));
Serial.println(TXErrorsCount);
}
else
{
//if here there was an error transmitting packet
TXErrorsCount++;
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
Serial.print(F(" SendError,"));
Serial.print(F("Length,"));
Serial.print(TXPacketL); //print transmitted packet length
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX); //print IRQ status
LT.printIrqStatus(); //prints the text of which IRQs set
Serial.println();
}
}
void setStatusByte(uint8_t bitnum, uint8_t bitval)
{
//program the status byte
if (bitval == 0)
{
bitClear(TXStatus, bitnum);
}
else
{
bitSet(TXStatus, bitnum);
}
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
//flash LED to show tracker is alive
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void send_Command(char cmd)
{
bool SendOK;
uint8_t len;
Serial.print(F("Send Cmd "));
Serial.write(cmd);
LT.startWriteSXBuffer(0);
LT.writeUint8(cmd); //packet addressing used indentify type of packet
LT.writeUint8(Broadcast); //who is the packet sent to
LT.writeUint8(ThisNode); //where is packet from
LT.writeUint16(TXVolts);
len = LT.endWriteSXBuffer();
digitalWrite(LED1, HIGH);
SendOK = LT.transmitSXBuffer(0, len, 10000, TXpower, WAIT_TX); //timeout set at 10 seconds
digitalWrite(LED1, LOW);
if (SendOK)
{
Serial.println(F(" - Done"));
}
else
{
Serial.println(F(" - Error"));
}
}
uint16_t readSupplyVoltage()
{
//relies on 1V internal reference and 91K & 11K resistor divider
//returns supply in mV @ 10mV per AD bit read
uint16_t temp;
uint16_t voltage = 0;
uint8_t index;
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, HIGH); //turn on MOSFET connecting resitor divider in circuit
}
analogReference(INTERNAL);
temp = analogRead(SupplyAD);
for (index = 0; index <= 4; index++) //sample AD 5 times
{
temp = analogRead(SupplyAD);
voltage = voltage + temp;
}
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, LOW); //turn off MOSFET connecting resitor divider in circuit
}
voltage = ((voltage / 5) * ADMultiplier) + DIODEMV;
return voltage;
}
void GPSON()
{
if (GPSPOWER >= 0)
{
digitalWrite(GPSPOWER, GPSONSTATE); //power up GPS
}
}
void GPSOFF()
{
if (GPSPOWER)
{
digitalWrite(GPSPOWER, GPSOFFSTATE); //power off GPS
}
}
void GPSTest()
{
uint32_t startmS;
startmS = millis();
while ( (uint32_t) (millis() - startmS) < 2000) //allows for millis() overflow
{
if (GPSserial.available() > 0)
{
Serial.write(GPSserial.read());
}
}
Serial.println();
Serial.println();
Serial.flush();
}
void setup()
{
if (GPSPOWER >= 0)
{
pinMode(GPSPOWER, OUTPUT);
GPSON();
}
if (BATVREADON >= 0)
{
pinMode(BATVREADON, OUTPUT);
}
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
led_Flash(2, 125); //two quick LED flashes to indicate program start
Serial.begin(115200);
Serial.println();
Serial.print(F(__TIME__));
Serial.print(F(" "));
Serial.println(F(__DATE__));
Serial.println(F(Program_Version));
Serial.println();
Serial.println(F("23_GPS_Tracker_Transmitter Starting"));
SPI.begin();
if (LT.begin(NSS, NRESET, DIO0, LORA_DEVICE))
{
Serial.println(F("LoRa Device found"));
led_Flash(2, 125);
delay(1000);
}
else
{
Serial.println(F("No device responding"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
Serial.println();
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
Serial.println();
LT.printOperatingSettings(); //reads and prints the configured operating settings, useful check
Serial.println();
TXVolts = readSupplyVoltage();
Serial.print(F("Supply "));
Serial.print(TXVolts);
Serial.println(F("mV"));
send_Command(PowerUp); //send power up command, includes supply mV
Serial.println(F("Startup GPS check"));
GPSserial.begin(9600);
GPSTest();
Serial.println();
Serial.println();
Serial.println(F("Wait for first GPS fix"));
gpsWaitFix(WaitFirstGPSFixSeconds);
sendLocation(TXLat, TXLon, TXAlt, TXHdop, TXGPSFixTime);
}

View File

@@ -0,0 +1,65 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 16/12/19
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitiosn to match your own setup.
#define NSS 10 //select on LoRa device
#define NRESET 9 //reset on LoRa device
#define DIO0 3 //DIO0 on LoRa device, used for RX and TX done
#define GPSPOWER -1 //Pin that controls power to GPS, set to -1 if not used
#define GPSONSTATE HIGH //logic level to turn GPS on via pin GPSPOWER
#define GPSOFFSTATE LOW //logic level to turn GPS off via pin GPSPOWER
#define RXpin A3 //pin number for GPS RX input into Arduino - TX from GPS
#define TXpin A2 //pin number for GPS TX output from Arduino- RX into GPS
#define LED1 8 //On board LED, high for on
#define SupplyAD A7 //pin for reading supply\battery voltage
#define BATVREADON 8 //turns on battery resistor divider, high for on, -1 if not used
const float ADMultiplier = 10.0; //multiplier for supply volts calculation
#define DIODEMV 98 //mV voltage drop accross diode at approx 8mA
#define LORA_DEVICE DEVICE_SX1278 //this is the device we are using
//******* Setup LoRa Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 434000000; //frequency of transmissions
const uint32_t Offset = 0; //offset frequency for calibration purposes
const uint8_t Bandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF12; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t Optimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t TXpower = 10; //LoRa TX power
#define ThisNode 'T' //a character that identifies this tracker
//**************************************************************************************************
// GPS Settings
//**************************************************************************************************
#define USESOFTSERIALGPS //if your using software serial for the GPS, enable this define
//#define USEHARDWARESERIALGPS //if your using hardware serial for the GPS, enable this define
//#define HARDWARESERIALPORT Serial2 //if your using hardware serial for the GPS, define the port here
#define GPSBaud 9600 //GPS Baud rate
#define WaitGPSFixSeconds 30 //time in seconds to wait for a new GPS fix
#define WaitFirstGPSFixSeconds 120 //time to seconds to wait for the first GPS fix at startup
#define Sleepsecs 15 //seconds between transmissions, this delay is used to set overall transmission cycle time

View File

@@ -0,0 +1,323 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 28/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This program is an basic receiver for the '23_Simple_GPS_Tracker_Transmitter' program.
The program reads the received packet from the tracker transmitter and displays the results on
the serial monitor. The LoRa and frequency settings provided in the Settings.h file must
match those used by the transmitter.
The program receives direct from the LoRa devices internal buffer.
Serial monitor baud rate is set at 115200.
*******************************************************************************************************/
#define Program_Version "V1.2"
#include <SPI.h>
#include <SX127XLT.h>
SX127XLT LT;
#include "Settings.h"
#include <ProgramLT_Definitions.h>
uint32_t RXpacketCount; //count of received packets
uint8_t RXPacketL; //length of received packet
int16_t PacketRSSI; //RSSI of received packet
int8_t PacketSNR; //signal to noise ratio of received packet
uint8_t PacketType; //for packet addressing, identifies packet type
uint8_t Destination; //for packet addressing, identifies the destination (receiving) node
uint8_t Source; //for packet addressing, identifies the source (transmiting) node
uint8_t TXStatus; //A status byte
float TXLat; //latitude
float TXLon; //longitude
float TXAlt; //altitude
uint32_t TXHdop; //HDOP, indication of fix quality, horizontal dilution of precision, low is good
uint32_t TXGPSFixTime; //time in mS for fix
uint16_t TXVolts; //supply\battery voltage
uint8_t TXSats; //number of sattelites in use
uint32_t TXupTimemS; //up time of TX in mS
void loop()
{
RXPacketL = LT.receiveSXBuffer(0, 0, WAIT_RX); //returns 0 if packet error of some sort
digitalWrite(LED1, HIGH);
if (BUZZER > 0)
{
digitalWrite(BUZZER, HIGH);
}
PacketRSSI = LT.readPacketRSSI();
PacketSNR = LT.readPacketSNR();
if (RXPacketL == 0)
{
packet_is_Error();
}
else
{
packet_is_OK();
}
digitalWrite(LED1, LOW);
if (BUZZER > 0)
{
digitalWrite(BUZZER, LOW);
}
Serial.println();
}
void readPacketAddressing()
{
//the transmitter is using packet addressing, so read in the details
LT.startReadSXBuffer(0);
PacketType = LT.readUint8();
Destination = LT.readUint8();
Source = LT.readUint8();
LT.endReadSXBuffer();
}
void packet_is_OK()
{
float tempHdop;
RXpacketCount++;
Serial.print(F("Packet OK > "));
readPacketAddressing();
if (PacketType == PowerUp)
{
LT.startReadSXBuffer(0);
LT.readUint8(); //read byte from FIFO, not used
LT.readUint8(); //read byte from FIFO, not used
LT.readUint8(); //read byte from FIFO, not used
TXVolts = LT.readUint16();
LT.endReadSXBuffer();
Serial.print(F("Tracker transmitter powerup - battery "));
Serial.print(TXVolts);
Serial.print(F("mV"));
}
if (PacketType == LocationPacket)
{
//packet has been received, now read from the SX12XX FIFO in the correct order.
Serial.print(F("LocationPacket "));
LT.startReadSXBuffer(0);
PacketType = LT.readUint8();
Destination = LT.readUint8();
Source = LT.readUint8();
TXLat = LT.readFloat();
TXLon = LT.readFloat();
TXAlt = LT.readFloat();
TXSats = LT.readUint8();
TXHdop = LT.readUint32();
TXStatus = LT.readUint8();
TXGPSFixTime = LT.readUint32();
TXVolts = LT.readUint16();
TXupTimemS = LT.readUint32();
RXPacketL = LT.endReadSXBuffer();
tempHdop = ( (float) TXHdop / 100); //need to convert Hdop read from GPS as uint32_t to a float for display
Serial.write(PacketType);
Serial.write(Destination);
Serial.write(Source);
Serial.print(F(","));
Serial.print(TXLat, 5);
Serial.print(F(","));
Serial.print(TXLon, 5);
Serial.print(F(","));
Serial.print(TXAlt, 1);
Serial.print(F("m,"));
Serial.print(TXSats);
Serial.print(F(","));
Serial.print(tempHdop, 2);
Serial.print(F(","));
Serial.print(TXStatus);
Serial.print(F(","));
Serial.print(TXGPSFixTime);
Serial.print(F("mS,"));
Serial.print(TXVolts);
Serial.print(F("mV,"));
Serial.print((TXupTimemS/1000));
Serial.print(F("s,"));
printpacketDetails();
return;
}
if (PacketType == LocationBinaryPacket)
{
//packet from locator has been received, now read from the SX12XX FIFO in the correct order.
Serial.print(F("LocationBinaryPacket "));
LT.startReadSXBuffer(0);
PacketType = LT.readUint8();
Destination = LT.readUint8();
Source = LT.readUint8();
TXLat = LT.readFloat();
TXLon = LT.readFloat();
TXAlt = LT.readInt16();
TXStatus = LT.readUint8();
RXPacketL = LT.endReadSXBuffer();
tempHdop = ( (float) TXHdop / 100); //need to convert Hdop read from GPS as uint32_t to a float for display
Serial.write(PacketType);
Serial.write(Destination);
Serial.write(Source);
Serial.print(F(","));
Serial.print(TXLat, 5);
Serial.print(F(","));
Serial.print(TXLon, 5);
Serial.print(F(","));
Serial.print(TXAlt, 0);
Serial.print(F("m,"));
Serial.print(TXStatus);
printpacketDetails();
return;
}
if (PacketType == NoFix)
{
Serial.print(F("No Tracker GPS fix "));
printpacketDetails();
return;
}
}
void printpacketDetails()
{
uint16_t IRQStatus;
Serial.print(F(",RSSI,"));
Serial.print(PacketRSSI);
Serial.print(F("dBm,SNR,"));
Serial.print(PacketSNR);
Serial.print(F("dB,Packets,"));
Serial.print(RXpacketCount);
Serial.print(F(",Length,"));
Serial.print(RXPacketL);
IRQStatus = LT.readIrqStatus();
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX);
}
void packet_is_Error()
{
uint16_t IRQStatus;
if (BUZZER > 0)
{
digitalWrite(BUZZER, LOW);
delay(100);
digitalWrite(BUZZER, HIGH);
}
IRQStatus = LT.readIrqStatus(); //get the IRQ status
Serial.print(F("PacketError,RSSI"));
Serial.print(PacketRSSI);
Serial.print(F("dBm,SNR,"));
Serial.print(PacketSNR);
Serial.print(F("dB,Length,"));
Serial.print(LT.readRXPacketL()); //get the real packet length
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX);
LT.printIrqStatus();
digitalWrite(LED1, LOW);
if (BUZZER > 0)
{
digitalWrite(BUZZER, LOW);
delay(100);
digitalWrite(BUZZER, HIGH);
}
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
led_Flash(2, 125); //two quick LED flashes to indicate program start
Serial.begin(115200);
Serial.println();
Serial.print(F(__TIME__));
Serial.print(F(" "));
Serial.println(F(__DATE__));
Serial.println(F(Program_Version));
Serial.println();
Serial.println(F("24_GPS_Tracker_Receiver Starting"));
if (BUZZER >= 0)
{
pinMode(BUZZER, OUTPUT);
Serial.println(F("BUZZER Enabled"));
}
else
{
Serial.println(F("BUZZER Not Enabled"));
}
SPI.begin();
if (LT.begin(NSS, NRESET, DIO0, DEVICE))
{
Serial.println(F("LoRa device found"));
led_Flash(2, 125);
}
else
{
Serial.println(F("No device responding"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
Serial.println();
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
Serial.println();
Serial.println(F("Receiver ready"));
Serial.println();
}

View File

@@ -0,0 +1,35 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 22/03/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitiosn to match your own setup.
#define NSS 10 //select on LoRa device
#define NRESET 9 //reset on LoRa device
#define DIO0 3 //DIO0 on LoRa device, used for RX and TX done
#define LED1 8 //On board LED, high for on
#define BUZZER -1 //Buzzer if fitted, high for on. Set to -1 if not used
#define DEVICE DEVICE_SX1278 //this is the device we are using
//******* Setup LoRa Test Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 434000000; //frequency of transmissions
const uint32_t Offset = 0; //offset frequency for calibration purposes
const uint8_t Bandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF12; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t Optimisation = LDRO_AUTO; //low data rate optimisation setting

View File

@@ -0,0 +1,634 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 28/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This program is an example of a functional GPS tracker receiver using lora.
It is capable of picking up the trackers location packets from many kilometres away with only basic antennas.
The program receives the location packets from the remote tracker transmitter and writes them on an OLED
display and also prints the information to the Arduino IDE serial monitor. The program can read a locally
attached GPS and when that has a fix, will display the distance and direction to the remote tracker.
The program writes direct to the lora devices internal buffer, no memory buffer is used. The lora settings
are configured in the Settings.h file.
The receiver recognises two types of tracker packet, the one from the matching program '23_GPS_Tracker_Transmitter'
(LocationPacket, 27 bytes) which causes these fields to be printed to the serial monitor;
Latitude, Longitude, Altitude, Satellites, HDOP, TrackerStatusByte, GPS Fixtime, Battery mV, Distance, Direction,
Distance, Direction, PacketRSSI, PacketSNR, NumberPackets, PacketLength, IRQRegister.
This is a long packet which at the long range LoRa settings takes just over 3 seconds to transmit.
The receiver also recognises a much shorter location only packet (LocationBinaryPacket, 11 bytes) and when
received this is printed to the serial monitor;
Latitude, Longitude, Altitude, TrackerStatusByte, Distance, Direction, PacketRSSI, PacketSNR, NumberPackets,
PacketLength, IRQRegister.
Most of the tracker information (for both types of packet) is shown on the OLED display. If there has been a
tracker transmitter GPS fix the number\identifier of that tracker is shown on row 0 right of screen and if there
is a recent local (receiver) GPS fix an 'R' is displayed row 1 right of screen.
When the tracker transmitter starts up or is reset its sends a power up message containing the battery voltage
which is shown on the OLED and printer to the serial monitor.
The program has the option of using a pin to control the power to the GPS, if the GPS module being used has this
feature. To use the option change the define in Settings.h;
'#define GPSPOWER -1' from -1 to the pin number being used. Also set the GPSONSTATE and GPSOFFSTATE defines to
the appropriate logic levels.
The program by default uses software serial to read the GPS, you can use hardware serial by commenting out this
line in the Settings.h file;
#define USE_SOFTSERIAL_GPS
And then defining the hardware serial port you are using, which defaults to Serial1.
Serial monitor baud rate is set at 115200.
*******************************************************************************************************/
#define Program_Version "V1.2"
#include <SPI.h>
#include <SX127XLT.h>
SX127XLT LT;
#include "Settings.h"
#include <ProgramLT_Definitions.h>
#include <U8x8lib.h> //https://github.com/olikraus/u8g2
//U8X8_SSD1306_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //standard 0.96" SSD1306
U8X8_SH1106_128X64_NONAME_HW_I2C disp(U8X8_PIN_NONE); //1.3" OLED often sold as 1.3" SSD1306
#include <TinyGPS++.h> //http://arduiniana.org/libraries/tinygpsplus/
TinyGPSPlus gps; //create the TinyGPS++ object
#ifdef USESOFTSERIALGPS
#include <SoftwareSerial.h>
SoftwareSerial GPSserial(RXpin, TXpin);
#endif
#ifdef USEHARDWARESERIALGPS
#define GPSserial HARDWARESERIALPORT
#endif
uint32_t RXpacketCount; //count of received packets
uint8_t RXPacketL; //length of received packet
int8_t PacketRSSI; //signal strength (RSSI) dBm of received packet
int8_t PacketSNR; //signal to noise ratio (SNR) dB of received packet
uint8_t PacketType; //for packet addressing, identifies packet type
uint8_t Destination; //for packet addressing, identifies the destination (receiving) node
uint8_t Source; //for packet addressing, identifies the source (transmiting) node
uint8_t TXStatus; //status byte from tracker transmitter
uint8_t TXSats; //number of sattelites in use
float TXLat; //latitude
float TXLon; //longitude
float TXAlt; //altitude
float RXLat; //latitude
float RXLon; //longitude
float RXAlt; //altitude
uint32_t TXHdop; //HDOP, indication of fix quality, horizontal dilution of precision, low is good
uint32_t TXGPSFixTime; //time in mS for fix
uint16_t TXVolts; //supply\battery voltage
uint16_t RXVolts; //supply\battery voltage
float TXdistance; //calculated distance to tracker
uint16_t TXdirection; //calculated direction to tracker
uint16_t RXerrors;
uint32_t TXupTimemS; //up time of TX in mS
uint32_t LastRXGPSfixCheck; //used to record the time of the last GPS fix
bool TXLocation = false; //set to true when at least one tracker location packet has been received
bool RXGPSfix = false; //set to true if the local GPS has a recent fix
uint8_t FixCount = DisplayRate; //used to keep track of number of GPS fixes before display updated
void loop()
{
RXPacketL = LT.receiveSXBuffer(0, 0, NO_WAIT); //returns 0 if packet error of some sort
while (!digitalRead(DIO0))
{
readGPS(); //If the DIO pin is low, no packet arrived, so read the GPS
}
//something has happened in receiver
digitalWrite(LED1, HIGH);
if (BUZZER > 0)
{
digitalWrite(BUZZER, HIGH);
}
RXPacketL = LT.readRXPacketL();
PacketRSSI = LT.readPacketRSSI();
PacketSNR = LT.readPacketSNR();
if (RXPacketL == 0)
{
packet_is_Error();
}
else
{
packet_is_OK();
}
digitalWrite(LED1, LOW);
if (BUZZER > 0)
{
digitalWrite(BUZZER, LOW);
}
Serial.println();
}
void readGPS()
{
if (GPSserial.available() > 0)
{
gps.encode(GPSserial.read());
}
if ( (uint32_t) (millis() - LastRXGPSfixCheck) > NoRXGPSfixms)
{
RXGPSfix = false;
LastRXGPSfixCheck = millis();
dispscreen1();
}
if (gps.location.isUpdated() && gps.altitude.isUpdated() && gps.date.isUpdated())
{
RXGPSfix = true;
RXLat = gps.location.lat();
RXLon = gps.location.lng();
RXAlt = gps.altitude.meters();
printRXLocation();
LastRXGPSfixCheck = millis();
if ( FixCount == 1) //update screen when FIX count counts down from DisplayRate to 1
{
FixCount = DisplayRate;
dispscreen1();
}
FixCount--;
}
}
bool readTXStatus(byte bitnum)
{
return bitRead(TXStatus, bitnum);
}
void printRXLocation()
{
Serial.print(F("LocalGPS "));
Serial.print(RXLat, 5);
Serial.print(F(","));
Serial.print(RXLon, 5);
Serial.print(F(","));
Serial.print(RXAlt, 1);
Serial.println();
}
void readPacketAddressing()
{
LT.startReadSXBuffer(0);
PacketType = LT.readUint8();
Destination = LT.readUint8();
Source = LT.readUint8();
LT.endReadSXBuffer();
}
void packet_is_OK()
{
//uint16_t IRQStatus;
float tempfloat;
RXpacketCount++;
readPacketAddressing();
if (PacketType == PowerUp)
{
LT.startReadSXBuffer(0);
LT.readUint8(); //read byte from SXBuffer, not used
LT.readUint8(); //read byte from SXBuffer, not used
LT.readUint8(); //read byte from SXBuffer, not used
TXVolts = LT.readUint16(); //read tracker transmitter voltage
LT.endReadSXBuffer();
Serial.print(F("Tracker Powerup - Battery "));
Serial.print(TXVolts);
Serial.println(F("mV"));
dispscreen2();
}
if (PacketType == LocationPacket)
{
//packet has been received, now read from the SX12XX FIFO in the correct order.
Serial.print(F("LocationPacket "));
TXLocation = true;
LT.startReadSXBuffer(0); //start the read of received packet
PacketType = LT.readUint8(); //read in the PacketType
Destination = LT.readUint8(); //read in the Packet destination address
Source = LT.readUint8(); //read in the Packet source address
TXLat = LT.readFloat(); //read in the tracker latitude
TXLon = LT.readFloat(); //read in the tracker longitude
TXAlt = LT.readFloat(); //read in the tracker altitude
TXSats = LT.readUint8(); //read in the satellites in use by tracker GPS
TXHdop = LT.readUint32(); //read in the HDOP of tracker GPS
TXStatus = LT.readUint8(); //read in the tracker status byte
TXGPSFixTime = LT.readUint32(); //read in the last fix time of tracker GPS
TXVolts = LT.readUint16(); //read in the tracker supply\battery volts
TXupTimemS = LT.readUint32(); //read in the TX uptime in mS
RXPacketL = LT.endReadSXBuffer(); //end the read of received packet
if (RXGPSfix) //if there has been a local GPS fix do the distance and direction calculation
{
TXdirection = (int16_t) TinyGPSPlus::courseTo(RXLat, RXLon, TXLat, TXLon);
TXdistance = TinyGPSPlus::distanceBetween(RXLat, RXLon, TXLat, TXLon);
}
else
{
TXdistance = 0;
TXdirection = 0;
}
Serial.write(PacketType);
Serial.write(Destination);
Serial.write(Source);
Serial.print(F(","));
Serial.print(TXLat, 5);
Serial.print(F(","));
Serial.print(TXLon, 5);
Serial.print(F(","));
Serial.print(TXAlt, 1);
Serial.print(F(","));
Serial.print(TXSats);
Serial.print(F(","));
tempfloat = ( (float) TXHdop / 100); //need to convert Hdop read from GPS as uint32_t to a float for display
Serial.print(tempfloat, 2);
Serial.print(F(","));
Serial.print(TXStatus);
Serial.print(F(","));
Serial.print(TXGPSFixTime);
Serial.print(F("mS,"));
Serial.print(TXVolts);
Serial.print(F("mV,"));
Serial.print((TXupTimemS/1000));
Serial.print(F("s,"));
Serial.print(TXdistance, 0);
Serial.print(F("m,"));
Serial.print(TXdirection);
Serial.print(F("d"));
printpacketDetails();
dispscreen1(); //and show the packet detail it on screen
return;
}
if (PacketType == LocationBinaryPacket)
{
//packet from locator has been received, now read from the SX12XX FIFO in the correct order.
TXLocation = true;
Serial.print(F("LocationBinaryPacket "));
LT.startReadSXBuffer(0);
PacketType = LT.readUint8();
Destination = LT.readUint8();
Source = LT.readUint8();
TXLat = LT.readFloat();
TXLon = LT.readFloat();
TXAlt = LT.readInt16();
TXStatus = LT.readUint8();
RXPacketL = LT.endReadSXBuffer();
if (RXGPSfix) //if there has been a local GPS fix do the distance and direction calculation
{
TXdirection = (int16_t) TinyGPSPlus::courseTo(RXLat, RXLon, TXLat, TXLon);
TXdistance = TinyGPSPlus::distanceBetween(RXLat, RXLon, TXLat, TXLon);
}
else
{
TXdistance = 0;
TXdirection = 0;
}
Serial.write(PacketType);
Serial.write(Destination);
Serial.write(Source);
Serial.print(F(","));
Serial.print(TXLat, 5);
Serial.print(F(","));
Serial.print(TXLon, 5);
Serial.print(F(","));
Serial.print(TXAlt, 0);
Serial.print(F("m,"));
Serial.print(TXStatus);
Serial.print(F(","));
Serial.print(TXdistance, 0);
Serial.print(F("m,"));
Serial.print(TXdirection);
Serial.print(F("d"));
printpacketDetails();
dispscreen1();
return;
}
}
void printpacketDetails()
{
uint16_t IRQStatus;
Serial.print(F(",RSSI,"));
Serial.print(PacketRSSI);
Serial.print(F("dBm,SNR,"));
Serial.print(PacketSNR);
Serial.print(F("dB,Packets,"));
Serial.print(RXpacketCount);
Serial.print(F(",Length,"));
Serial.print(RXPacketL);
IRQStatus = LT.readIrqStatus();
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX);
}
void packet_is_Error()
{
uint16_t IRQStatus;
if (BUZZER >= 0)
{
digitalWrite(BUZZER, LOW);
delay(100);
digitalWrite(BUZZER, HIGH);
}
IRQStatus = LT.readIrqStatus(); //get the IRQ status
RXerrors++;
Serial.print(F("PacketError,RSSI"));
Serial.print(PacketRSSI);
Serial.print(F("dBm,SNR,"));
Serial.print(PacketSNR);
Serial.print(F("dB,Length,"));
Serial.print(LT.readRXPacketL()); //get the real packet length
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX);
LT.printIrqStatus();
digitalWrite(LED1, LOW);
if (BUZZER >= 0)
{
digitalWrite(BUZZER, LOW);
delay(100);
digitalWrite(BUZZER, HIGH);
}
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
unsigned int index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void dispscreen1()
{
//show received packet data on display
float tempfloat;
disp.clearLine(0);
disp.setCursor(0, 0);
disp.print(TXLat, 5);
disp.clearLine(1);
disp.setCursor(0, 1);
disp.print(TXLon, 5);
disp.clearLine(2);
disp.setCursor(0, 2);
disp.print(TXAlt,0);
disp.print(F("m"));
disp.clearLine(3);
disp.setCursor(0, 3);
disp.print(F("RSSI "));
disp.print(PacketRSSI);
disp.print(F("dBm"));
disp.clearLine(4);
disp.setCursor(0, 4);
disp.print(F("SNR "));
if (PacketSNR > 0)
{
disp.print(F("+"));
}
if (PacketSNR == 0)
{
disp.print(F(" "));
}
if (PacketSNR < 0)
{
disp.print(F("-"));
}
disp.print(PacketSNR);
disp.print(F("dB"));
if (PacketType == LocationPacket)
{
disp.clearLine(5);
disp.setCursor(0, 5);
tempfloat = ((float) TXVolts / 1000);
disp.print(F("Batt "));
disp.print(tempfloat, 2);
disp.print(F("v"));
}
disp.clearLine(6);
disp.setCursor(0, 6);
disp.print(F("Packets "));
disp.print(RXpacketCount);
disp.clearLine(7);
if (RXGPSfix)
{
disp.setCursor(15, 1);
disp.print(F("R"));
}
else
{
disp.setCursor(15, 1);
disp.print(F(" "));
disp.setCursor(0, 7);
disp.print(F("No Local Fix"));
}
if (RXGPSfix && TXLocation) //only display distance and direction if have received tracker packet and have local GPS fix
{
disp.clearLine(7);
disp.setCursor(0, 7);
disp.print(TXdistance, 0);
disp.print(F("m "));
disp.print(TXdirection);
disp.print(F("d"));
}
if (readTXStatus(GPSFix))
{
disp.setCursor(15, 0);
disp.write(Source);
}
}
void dispscreen2()
{
//show tracker powerup data on display
float tempfloat;
disp.clear();
disp.setCursor(0, 0);
disp.print(F("Tracker Powerup"));
disp.setCursor(0, 1);
disp.print(F("Battery "));
tempfloat = ((float) TXVolts / 1000);
disp.print(tempfloat, 2);
disp.print(F("v"));
}
void GPSON()
{
if (GPSPOWER >= 0)
{
digitalWrite(GPSPOWER, GPSONSTATE); //power up GPS
}
}
void GPSOFF()
{
if (GPSPOWER >= 0)
{
digitalWrite(GPSPOWER, GPSOFFSTATE); //power off GPS
}
}
void GPSTest()
{
uint32_t startmS;
startmS = millis();
while ( (uint32_t) (millis() - startmS) < 2000) //allows for millis() overflow
{
if (GPSserial.available() > 0)
{
Serial.write(GPSserial.read());
}
}
Serial.println();
Serial.println();
Serial.flush();
}
void setup()
{
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
led_Flash(2, 125); //two quick LED flashes to indicate program start
Serial.begin(115200);
Serial.println();
Serial.print(F(__TIME__));
Serial.print(F(" "));
Serial.println(F(__DATE__));
Serial.println(F(Program_Version));
Serial.println();
Serial.println(F("25_GPS_Tracker_Receiver_With_Display_and_GPS Starting"));
if (BUZZER >= 0)
{
pinMode(BUZZER, OUTPUT);
}
SPI.begin();
disp.begin();
disp.setFont(u8x8_font_chroma48medium8_r);
Serial.print(F("Checking LoRa device - ")); //Initialize LoRa
disp.setCursor(0, 0);
if (LT.begin(NSS, NRESET, DIO0, LORA_DEVICE))
{
Serial.println(F("Receiver ready"));
disp.print(F("Receiver ready"));
led_Flash(2, 125);
delay(1000);
}
else
{
Serial.println(F("No LoRa device responding"));
disp.print(F("No LoRa device"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
Serial.println();
Serial.println(F("Startup GPS check"));
if (GPSPOWER >= 0)
{
pinMode(GPSPOWER, OUTPUT);
}
GPSON();
GPSserial.begin(GPSBaud);
GPSTest();
Serial.println();
Serial.println();
Serial.println(F("Receiver ready"));
Serial.println();
}

View File

@@ -0,0 +1,59 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 16/12/19
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitiosn to match your own setup. Some pins such as DIO1,
//DIO2, BUZZER SWITCH1 may not be in used by this sketch so they do not need to be
//connected and should be set to -1.
#define NSS 10 //select on LoRa device
#define NRESET 9 //reset on LoRa device
#define DIO0 3 //DIO0 on LoRa device, used for RX and TX done
#define LED1 8 //On board LED, high for on
#define BUZZER -1 //Buzzer if fitted, high for on. Set to -1 if not used
#define RXpin A3 //pin number for GPS RX input into Arduino - TX from GPS
#define TXpin A2 //pin number for GPS TX output from Arduino- RX into GPS
#define GPSPOWER 4 //Pin that controls power to GPS, set to -1 if not used
#define GPSONSTATE HIGH //logic level to turn GPS on via pin GPSPOWER
#define GPSOFFSTATE LOW //logic level to turn GPS off via pin GPSPOWER
#define LORA_DEVICE DEVICE_SX1278 //this is the device we are using
//******* Setup LoRa Test Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 434000000; //frequency of transmissions
const uint32_t Offset = 0; //offset frequency for calibration purposes
const uint8_t Bandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF12; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t Optimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t TXpower = 10; //LoRa transmit power in dBm
//**************************************************************************************************
// GPS Settings
//**************************************************************************************************
#define USESOFTSERIALGPS //if your using software serial for the GPS, enable this define
//#define USEHARDWARESERIALGPS //if your using hardware serial for the GPS, enable this define
//#define HARDWARESERIALPORT Serial2 //if your using hardware serial for the GPS, define the port here
#define GPSBaud 9600 //GPS Baud rate
#define NoRXGPSfixms 15000 //max number of mS to allow before no local GPS fix flagged
#define DisplayRate 7 //when working OK the GPS will get a new fix every second or so
//this rate defines how often the display should be updated

View File

@@ -0,0 +1,173 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 02/02/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This program will receive a lora packet and relay (re-transmit) it. The receiving
and transmitting can use different frequencies and lora settings, although in this example they are
the same. The receiving and transmitting settings are in the 'Settings.h' file. If the relay is located
in an advantageous position, for instance on top of a tall tree, building or in an radio controlled model
then the range at which trackers or nodes on the ground can be received is considerably increased.
In these circumstances the relay may listen at a long range setting using SF12 for example and then
re-transmit back to the ground at SF7.
For an example of the use of such a program see this report;
https://stuartsprojects.github.io/2016/08/15/how-to-search-500-square-kilometres-in-10-minutes.html
Serial monitor baud rate is set at 9600.
*******************************************************************************************************/
#include <SPI.h>
#include <SX127XLT.h>
#include "Settings.h"
SX127XLT LT;
uint8_t RXPacketL, TXPacketL;
int8_t PacketRSSI, PacketSNR;
uint16_t RXPacketErrors;
void loop()
{
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
RXPacketL = LT.receiveSXBuffer(0, 0, WAIT_RX); //returns 0 if packet error of some sort, no timeout set
digitalWrite(LED1, HIGH); //something has happened
if (BUZZER > 0) //turn buzzer on
{
digitalWrite(BUZZER, HIGH);
}
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
PacketSNR = LT.readPacketSNR(); //read the received SNR value
if (RXPacketL == 0) //if the LT.receive() function detects an error, RXpacketL == 0
{
packet_is_Error();
}
else
{
packet_is_OK();
}
if (BUZZER > 0)
{
digitalWrite(BUZZER, LOW); //buzzer off
}
Serial.println();
}
void packet_is_OK()
{
//a packet has been received, so change to relay settings and transmit buffer
Serial.print(F("PacketOK "));
printreceptionDetails();
delay(packet_delay / 2);
digitalWrite(LED1, LOW);
delay(packet_delay / 2);
Serial.print(F(" Retransmit"));
LT.setupLoRa(RelayFrequency, RelayOffset, RelaySpreadingFactor, RelayBandwidth, RelayCodeRate, RelayOptimisation);
digitalWrite(LED1, HIGH);
TXPacketL = LT.transmitSXBuffer(0, RXPacketL, 10000, TXpower, WAIT_TX);
Serial.print(F(" - Done"));
digitalWrite(LED1, LOW);
}
void packet_is_Error()
{
uint16_t IRQStatus;
RXPacketErrors++;
IRQStatus = LT.readIrqStatus();
led_Flash(5, 50);
if (IRQStatus & IRQ_RX_TIMEOUT)
{
Serial.print(F("RXTimeout "));
}
else
{
Serial.print(F("PacketError "));
printreceptionDetails();
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX);
LT.printIrqStatus();
}
}
void printreceptionDetails()
{
Serial.print(F("RSSI,"));
Serial.print(PacketRSSI);
Serial.print(F("dBm,SNR,"));
Serial.print(PacketSNR);
Serial.print(F("dB,Length,"));
Serial.print(LT.readRXPacketL());
}
void led_Flash(uint16_t flashdelay, uint16_t flashes)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
delay(flashdelay);
digitalWrite(LED1, HIGH);
delay(flashdelay);
digitalWrite(LED1, LOW);
}
}
void setup()
{
pinMode(LED1, OUTPUT);
led_Flash(2, 125);
Serial.begin(9600);
SPI.begin();
if (LT.begin(NSS, NRESET, DIO0, DIO1, DIO2, LORA_DEVICE))
{
led_Flash(2, 125);
}
else
{
Serial.println(F("Device error"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
Serial.print(F("ListenSettings,"));
LT.printModemSettings();
Serial.println();
LT.setupLoRa(RelayFrequency, RelayOffset, RelaySpreadingFactor, RelayBandwidth, RelayCodeRate, RelayOptimisation);
Serial.print(F("RelaySettings,"));
LT.printModemSettings();
Serial.println();
Serial.println(F("Relay Ready"));
}

View File

@@ -0,0 +1,51 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 02/02/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitiosn to match your own setup. Some pins such as DIO1,
//DIO2, may not be in used by this sketch so they do not need to be connected and
//should be set to -1.
#define NSS 10 //select on LoRa device
#define NRESET 9 //reset on LoRa device
#define DIO0 3 //DIO0 on LoRa device, used for RX and TX done
#define DIO1 -1 //DIO1 on LoRa device, normally not used so set to -1
#define DIO2 -1 //DIO2 on LoRa device, normally not used so set to -1
#define LED1 8 //On board LED, high for on
#define BUZZER -1 //normally not used so set to -1
#define LORA_DEVICE DEVICE_SX1278 //this is the device we are using
//******* Setup LoRa Test Parameters Here ! ***************
//LoRa receiving parameters
const uint32_t Frequency = 434000000; //frequency of transmissions
const uint32_t Offset = 0; //offset frequency for calibration purposes
const uint8_t Bandwidth = LORA_BW_125; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t Optimisation = LDRO_AUTO; //low data rate optimisation setting
//LoRa relay (re-transmitting) parameters
const uint32_t RelayFrequency = 434000000; //frequency of transmissions
const uint32_t RelayOffset = 0; //offset frequency for calibration purposes
const uint8_t RelayBandwidth = LORA_BW_125; //LoRa bandwidth
const uint8_t RelaySpreadingFactor = LORA_SF7; //LoRa spreading factor
const uint8_t RelayCodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t RelayOptimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t TXpower = 10; //LoRa TX power in dBm
#define packet_delay 500 //mS delay before received packet transmitted

View File

@@ -0,0 +1,807 @@
/******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 28/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This is a tracker intended for use as a high altitude balloon (HAB) tracker. The
program sends out a standard format payload with LoRa that is compatible with the HABHUB online tracking
system.
The HAB payload is constructed thus;
PayloadID,Sequence,Time,Lat,Lon,Alt,Satellites,Volts,Temperature,Resets,Status,Errors,TXGPSfixms,Checksum
Field 0 1 2 3 4 5 6 7 8 9 10 11 12 13
The LoRa and frequency settings can be changed in the Settings.h file. There is the option of sending
out a much shorter Search mode binary location only payload. This is intended for ground based searching
and locating. The frequency and LoRa settings of the Search mode packet can be different to the Tracker
mode used by the HAB payload. There is also the option of sending the HAB payload in FSK RTTY format,
see the Settings.h file for all the options. FSK RTTY gets sent at the same frequency as the Tracker mode
HAB packet. The LT.transmitFSKRTTY() function sends at 1 start bit, 7 data bits, no parity and 2 stop bits.
For full control of the FSK RTTY setting you can use the following alternative function;
LT.transmitFSKRTTY(chartosend, databits, stopbits, parity, baudPerioduS, pin)
There is a matching Balloon Tracker Receiver program which writes received data to the Serial monitor as well
as a small OLED display.
In the Settings.h file you can set the configuration for either a Ublox GPS or a Quectel L70\L80. The GPSs
are configured for high altitude balloon mode.
It is strongly recommended that a FRAM option is fitted for this transmitter. The sequence, resets and error
nembers are stred in non-volatile memory. This defaults to EEPROM which has a limited endurance of only
100,000 writes, so in theory the limt is reached after the transmission of 100,000 hab packets. The use of
a FRAM will extend the life of the tracker to circa 100,000,000,000,000 transmissions.
Changes:
240420 - Change to work with Easy Pro Mini style modules
300420 - Improve error detection for UBLOX GPS library
ToDo:
Serial monitor baud rate is set at 115200
*******************************************************************************************************/
#define Program_Version "V1.1"
#include <Arduino.h>
#include <SX127XLT.h> //include the appropriate library
SX127XLT LT; //create a library class instance called LT
#include "Settings.h"
#include "ProgramLT_Definitions.h"
//**************************************************************************************************
// HAB tracker data - these are the variables transmitted in payload
//**************************************************************************************************
uint32_t TXSequence; //sequence number of payload
uint8_t TXHours; //Hours
uint8_t TXMinutes; //Minutes
uint8_t TXSeconds; //Seconds
float TXLat; //latitude from GPS
float TXLon; //longitude from GPS
uint16_t TXAlt; //altitude from GPS
uint8_t TXSatellites; //satellites used by GPS
uint16_t TXVolts; //measured tracker supply volts
int8_t TXTemperature; //measured temperature
uint16_t TXResets; //number of tracker resets
uint8_t TXStatus = 0; //used to store current status flag bits
uint16_t TXErrors; //number of tracker Errors
uint32_t TXGPSfixms; //fix time of GPS
//**************************************************************************************************
uint8_t TXPacketL; //length of LoRa packet sent
uint8_t TXBUFFER[TXBUFFER_SIZE]; //buffer for packet to send
#include Memory_Library
#include <SPI.h>
#include <TinyGPS++.h> //http://arduiniana.org/libraries/tinygpsplus/
TinyGPSPlus gps; //create the TinyGPS++ object
#ifdef USESOFTSERIALGPS
//#include <NeoSWSerial.h> //https://github.com/SlashDevin/NeoSWSerial
//NeoSWSerial GPSserial(RXpin, TXpin); //The NeoSWSerial library is an option to use and is more relaible
//at GPS init than software serial
#include <SoftwareSerial.h>
SoftwareSerial GPSserial(RXpin, TXpin);
#endif
#ifdef USEHARDWARESERIALGPS
#define GPSserial HARDWARESERIALPORT
#endif
#ifdef USEI2CGPS
#include <Wire.h>
#endif
#include GPS_Library //include previously defined GPS Library
#include <OneWire.h> //get library here > https://github.com/PaulStoffregen/OneWire
OneWire oneWire(ONE_WIRE_BUS); //create instance of OneWire library
#include <DallasTemperature.h> //get library here > https://github.com/milesburton/Arduino-TXTemperature-Control-Library
DallasTemperature sensor(&oneWire); //create instance of dallas library
uint32_t GPSstartms; //start time waiting for GPS to get a fix
void loop()
{
Serial.println(F("Start Loop"));
GPSstartms = millis();
if (!gpsWaitFix(WaitGPSFixSeconds))
{
GPS_OutputOff();
sendCommand(NoFix); //report a GPS fix error
delay(1000); //give receiver enough time to report NoFix
}
Serial.println();
do_Transmissions(); //do the transmissions
Serial.println(F("Sleep"));
LT.setSleep(CONFIGURATION_RETENTION); //put LoRa device to sleep, preserve lora register settings
Serial.flush(); //make sure no serial output pending before goint to sleep
delay(SleepTimesecs * 1000);
Serial.println(F("Wake"));
LT.wake(); //wake the LoRa device from sleep
}
void do_Transmissions()
{
//this is where all the transmisions get sent
uint32_t startTimemS;
uint8_t index;
incMemoryUint32(addr_SequenceNum); //increment Sequence number
if (readConfigByte(SearchEnable))
{
setSearchMode();
TXPacketL = buildLocationOnly(TXLat, TXLon, TXAlt, TXStatus); //put location data in SX12xx buffer
Serial.print(F("Search packet > "));
Serial.print(TXLat, 5);
Serial.print(F(","));
Serial.print(TXLon, 5);
Serial.print(F(","));
Serial.print(TXAlt);
Serial.print(F(","));
Serial.print(TXStatus);
digitalWrite(LED1, HIGH);
startTimemS = millis();
TXPacketL = LT.transmitSXBuffer(0, TXPacketL, 10000, SearchTXpower, WAIT_TX);
printTXtime(startTimemS, millis());
reportCompletion();
Serial.println();
}
delay(1000); //gap between transmissions
setTrackerMode();
TXPacketL = buildHABPacket();
Serial.print(F("HAB Packet > "));
printBuffer(TXBUFFER, (TXPacketL + 1)); //print the buffer (the packet to send) as ASCII
digitalWrite(LED1, HIGH);
startTimemS = millis();
TXPacketL = LT.transmit(TXBUFFER, (TXPacketL + 1), 10000, TrackerTXpower, WAIT_TX); //will return packet length sent if OK, otherwise 0 if transmit error
digitalWrite(LED1, LOW);
printTXtime(startTimemS, millis());
reportCompletion();
Serial.println();
delay(1000); //gap between transmissions
if (readConfigByte(FSKRTTYEnable)) //FSKRTTY is sent last, so that receiver has time to use AFSK upload
{
LT.setupDirect(TrackerFrequency, Offset);
LT.startFSKRTTY(FrequencyShift, NumberofPips, PipPeriodmS, PipDelaymS, LeadinmS);
startTimemS = millis() - LeadinmS;
Serial.print(F("FSK RTTY > $$$"));
Serial.flush();
LT.transmitFSKRTTY('$', BaudPerioduS, LED1); //send a '$' as sync
LT.transmitFSKRTTY('$', BaudPerioduS, LED1); //send a '$' as sync
LT.transmitFSKRTTY('$', BaudPerioduS, LED1); //send a '$' as sync
for (index = 0; index <= (TXPacketL - 1); index++) //its TXPacketL-1 since we dont want to send the null at the end
{
LT.transmitFSKRTTY(TXBUFFER[index], BaudPerioduS, LED1);
Serial.write(TXBUFFER[index]);
}
LT.transmitFSKRTTY(13, BaudPerioduS, LED1); //send carriage return
LT.transmitFSKRTTY(10, BaudPerioduS, LED1); //send line feed
LT.endFSKRTTY(); //stop transmitting carrier
digitalWrite(LED1, LOW); //LED off
printTXtime(startTimemS, millis());
TXPacketL += 4; //add the two $ at beginning and CR/LF at end
reportCompletion();
Serial.println();
}
}
void printTXtime(uint32_t startmS, uint32_t endmS)
{
Serial.print(F(" "));
Serial.print(endmS - startmS);
Serial.print(F("mS"));
}
void reportCompletion()
{
Serial.print(F(" "));
if (TXPacketL == 0)
{
Serial.println();
reporttransmitError();
}
else
{
Serial.print(TXPacketL);
Serial.print(F("bytes"));
setStatusByte(LORAError, 0);
}
}
void printBuffer(uint8_t *buffer, uint8_t size)
{
uint8_t index;
for (index = 0; index < size; index++)
{
Serial.write(buffer[index]);
}
}
uint8_t buildHABPacket()
{
//build the HAB tracker payload
uint16_t index, j, CRC;
uint8_t Count, len;
char LatArray[12], LonArray[12];
TXSequence = readMemoryUint32(addr_SequenceNum); //Sequence number is kept in non-volatile memory so it survives TXResets
TXResets = readMemoryUint16(addr_ResetCount); //reset count is kept in non-volatile memory so it survives TXResets
TXVolts = readSupplyVoltage();
Serial.print(F("TXVolts "));
Serial.print(TXVolts);
Serial.println(F("mV"));
TXTemperature = (int8_t) readTempDS18B20();
TXErrors = readMemoryUint16(addr_TXErrors);
dtostrf(TXLat, 7, 5, LatArray); //format is dtostrf(FLOAT,WIDTH,PRECISION,BUFFER);
dtostrf(TXLon, 7, 5, LonArray); //converts float to character array
len = sizeof(TXBUFFER);
memset(TXBUFFER, 0, len); //clear array to 0s
Count = snprintf((char*) TXBUFFER,
TXBUFFER_SIZE,
"$%s,%lu,%02d:%02d:%02d,%s,%s,%d,%d,%d,%d,%d,%d,%d,%lu",
FlightID,
TXSequence,
TXHours,
TXMinutes,
TXSeconds,
LatArray,
LonArray,
TXAlt,
TXSatellites,
TXVolts,
TXTemperature,
TXResets,
TXStatus,
TXErrors,
TXGPSfixms
);
CRC = 0xffff; //start value for CRC16
for (index = 1; index < Count; index++) //element 1 is first character after $ at start (for LoRa)
{
CRC ^= (((uint16_t)TXBUFFER[index]) << 8);
for (j = 0; j < 8; j++)
{
if (CRC & 0x8000)
CRC = (CRC << 1) ^ 0x1021;
else
CRC <<= 1;
}
}
TXBUFFER[Count++] = '*';
TXBUFFER[Count++] = Hex((CRC >> 12) & 15); //add the checksum bytes to the end
TXBUFFER[Count++] = Hex((CRC >> 8) & 15);
TXBUFFER[Count++] = Hex((CRC >> 4) & 15);
TXBUFFER[Count] = Hex(CRC & 15);
return Count;
}
char Hex(uint8_t lchar)
{
//used in CRC calculation in buildHABPacket
char Table[] = "0123456789ABCDEF";
return Table[lchar];
}
uint8_t buildLocationOnly(float Lat, float Lon, uint16_t Alt, uint8_t stat)
{
uint8_t len;
LT.startWriteSXBuffer(0); //initialise buffer write at address 0
LT.writeUint8(LocationBinaryPacket); //identify type of packet
LT.writeUint8(Broadcast); //who is the packet sent too
LT.writeUint8(ThisNode); //tells receiver where is packet from
LT.writeFloat(Lat); //add latitude
LT.writeFloat(Lon); //add longitude
LT.writeInt16(Alt); //add altitude
LT.writeUint8(stat); //add tracker status
len = LT.endWriteSXBuffer(); //close buffer write
return len;
}
void reporttransmitError()
{
uint16_t IRQStatus;
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
Serial.print(F("TXError,"));
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX); //print IRQ status
LT.printIrqStatus(); //prints the text of which IRQs set
incMemoryUint16(addr_TXErrors); //increase the error count
setStatusByte(LORAError, 1);
}
void incMemoryUint32(uint32_t addr)
{
uint32_t val = readMemoryUint32(addr);
val++;
writeMemoryUint32(addr, val);
}
void incMemoryUint16(uint32_t addr)
{
uint16_t val = readMemoryUint16(addr);
val++;
writeMemoryUint16(addr, val);
}
void setStatusByte(uint8_t bitnum, uint8_t bitval)
{
//program the status byte
if (bitval == 0)
{
bitClear(TXStatus, bitnum);
}
else
{
bitSet(TXStatus, bitnum);
}
}
uint8_t readConfigByte(uint8_t bitnum)
{
return bitRead(Default_config1, bitnum);
}
void setTrackerMode()
{
Serial.println(F("setTrackerMode"));
LT.setupLoRa(TrackerFrequency, Offset, TrackerSpreadingFactor, TrackerBandwidth, TrackerCodeRate, TrackerOptimisation);
}
void setSearchMode()
{
Serial.println(F("setSearchMode"));
LT.setupLoRa(SearchFrequency, Offset, SearchSpreadingFactor, SearchBandwidth, SearchCodeRate, SearchOptimisation);
}
uint8_t sendCommand(char cmd)
{
uint8_t len;
TXVolts = readSupplyVoltage();
Serial.print(F("Send Cmd "));
Serial.write(cmd);
Serial.println();
LT.startWriteSXBuffer(0); //start the write packet to buffer process
LT.writeUint8(cmd); //this byte defines the packet type
LT.writeUint8(Broadcast); //destination address of the packet, the receivers address
LT.writeUint8(ThisNode); //source address of this node
LT.writeUint16(TXVolts); //add the battery voltage
LT.writeUint8(TXStatus); //add the status byte
len = LT.endWriteSXBuffer(); //close the packet, get the length of data to be sent
//now transmit the packet, set a timeout of 5000mS, wait for it to complete sending
digitalWrite(LED1, HIGH); //turn on LED as an indicator
TXPacketL = LT.transmitSXBuffer(0, len, 5000, TrackerTXpower, WAIT_TX);
digitalWrite(LED1, LOW); //turn off indicator LED
return TXPacketL; //TXPacketL will be 0 if there was an error sending
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
//flash LED to show tracker is alive
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void clearAllMemory()
{
//clears the whole of non-volatile
Serial.println(F("Clear Memory"));
fillMemory(addr_StartMemory, addr_EndMemory, 0);
}
float readTempDS18B20()
{
float DS18B20TXTemperature;
sensor.requestTemperatures();
DS18B20TXTemperature = sensor.getTempCByIndex(0);
return DS18B20TXTemperature;
}
void printTempDS18B20()
{
float DS18B20TXTemperature;
DS18B20TXTemperature = readTempDS18B20();
Serial.print(F("Temperature "));
Serial.print(DS18B20TXTemperature, 1);
Serial.println(F("c"));
}
void printSupplyVoltage()
{
//get and display supply volts on terminal or monitor
Serial.print(F("Volts "));
Serial.print(readSupplyVoltage());
Serial.println(F("mV"));
}
uint16_t readSupplyVoltage()
{
//relies on internal reference and 91K & 11K resistor divider
//returns supply in mV @ 10mV per AD bit read
uint16_t temp;
uint16_t volts = 0;
uint8_t index;
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, HIGH); //turn MOSFET connection resitor divider in circuit
}
analogReference(INTERNAL);
temp = analogRead(SupplyAD);
for (index = 0; index <= 9; index++) //sample AD 10 times
{
temp = analogRead(SupplyAD);
volts = volts + temp;
delay(10);
}
volts = ( (float) (volts / 10) * ADMultiplier);
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, LOW); //turn MOSFET connection resitor divider in circuit
}
return volts;
}
//***********************************************************
// Start GPS Functions
//***********************************************************
void GPSTest()
{
uint8_t GPSchar;
uint32_t startmS;
startmS = millis();
while ( (uint32_t) (millis() - startmS) < 2000) //allows for millis() overflow
{
GPSchar = GPS_GetByte();
if (GPSchar != 0xFF)
{
Serial.write(GPSchar);
}
}
Serial.println();
Serial.println();
Serial.flush();
}
bool gpsWaitFix(uint16_t waitSecs)
{
//waits a specified number of seconds for a fix, returns true for good fix
uint32_t startmS, waitmS;
uint8_t GPSchar;
Serial.flush();
Serial.print(F("Wait GPS Fix "));
Serial.print(waitSecs);
Serial.println(F("s "));
Serial.flush();
GPS_OutputOn();
waitmS = waitSecs * 1000;
startmS = millis();
while ( (uint32_t) (millis() - startmS) < waitmS) //allows for millis() overflow
{
do
{
GPSchar = GPS_GetByte();
if (GPSchar != 0xFF)
{
gps.encode(GPSchar);
Serial.write(GPSchar);
}
}
while (GPSchar != 0xFF);
if (gps.location.isUpdated() && gps.altitude.isUpdated() && gps.date.isUpdated())
{
TXLat = gps.location.lat();
TXLon = gps.location.lng();
TXAlt = (uint16_t) gps.altitude.meters();
//Altitude is used as an unsigned integer, so that the binary payload is as short as possible.
//However gps.altitude.meters(); can return a negative value which converts to
//65535 - Altitude, which we dont want. So we will assume any value over 60,000M is zero
if (TXAlt > 60000)
{
TXAlt = 0;
}
TXHours = gps.time.hour(),
TXMinutes = gps.time.minute(),
TXSeconds = gps.time.second(),
TXSatellites = gps.satellites.value();
setStatusByte(GPSFix, 1);
TXGPSfixms = millis() - GPSstartms;
Serial.flush();
Serial.print(F("Have GPS Fix "));
Serial.print(TXGPSfixms);
Serial.print(F("mS"));
Serial.println();
GPSprintTime();
GPSprintDate();
Serial.flush();
return true;
}
}
//if here then there has been no fix and a timeout
GPS_OutputOff();
setStatusByte(GPSFix, 0); //set status bit to flag no fix
incMemoryUint16(addr_TXErrors);
Serial.println(F("Error No GPS Fix"));
return false;
}
void GPSprintTime()
{
uint8_t hours, mins, secs;
hours = gps.time.hour();
mins = gps.time.minute();
secs = gps.time.second();
Serial.print(F("Time "));
if (hours < 10)
{
Serial.print(F("0"));
}
Serial.print(hours);
Serial.print(F(":"));
if (mins < 10)
{
Serial.print(F("0"));
}
Serial.print(mins);
Serial.print(F(":"));
if (secs < 10)
{
Serial.print(F("0"));
}
Serial.println(secs);
}
void GPSprintDate()
{
Serial.print(F("Date "));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.println(gps.date.year());
}
//***********************************************************
// End GPS Functions
//***********************************************************
void setup()
{
uint32_t i;
uint16_t j;
Serial.begin(115200); //Setup Serial console ouput
Serial.println();
Serial.println();
Serial.println(F("67_HAB_Balloon_Tracker_Transmitter Starting"));
memoryStart(Memory_Address); //setup the memory
j = readMemoryUint16(addr_ResetCount);
j++;
writeMemoryUint16(addr_ResetCount, j);
j = readMemoryUint16(addr_ResetCount);
Serial.print(F("TXResets "));
Serial.println(j);
if (GPSPOWER >= 0) //if GPS needs power switching, turn it on
{
pinMode(GPSPOWER, OUTPUT);
digitalWrite(GPSPOWER, GPSONSTATE);
}
if (BATVREADON >= 0)
{
pinMode(BATVREADON, OUTPUT); //for MOSFET controlling battery volts resistor divider
}
#ifdef QUECTELINUSE
Serial.println(F("Quectel GPS library"));
#endif
#ifdef UBLOXINUSE
Serial.println(F("UBLOX GPS library"));
#endif
#ifdef ClearAllMemory
clearAllMemory();
#endif
SPI.begin(); //initialize SPI
if (LT.begin(NSS, NRESET, DIO0, LORA_DEVICE))
{
led_Flash(2, 125);
}
else
{
Serial.println(F("LoRa Device error"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
setTrackerMode();
Serial.print(F("Config "));
Serial.println(Default_config1, BIN);
j = readMemoryUint16(addr_TXErrors);
Serial.print(F("TXErrors "));
Serial.println(j);
Serial.print(F("TXSequence "));
i = readMemoryUint32(addr_SequenceNum);
Serial.println(i);
Serial.print(F("ThisNode "));
Serial.println(ThisNode);
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
Serial.println();
printSupplyVoltage();
printTempDS18B20();
Serial.println();
TXStatus = 0; //clear all TX status bits
sendCommand(PowerUp); //send power up command, includes supply mV and config, on tracker settings
GPS_OutputOn();
Serial.println();
Serial.println(F("GPS output test"));
Serial.flush();
GPSTest(); //copy GPS output to serial monitor as a test
GPS_Setup(); //GPS should have had plenty of time to initialise by now
GPS_SetBalloonMode();
delay(2000);
if (GPS_CheckBalloonMode()) //Check that GPS is configured for high altitude balloon mode
{
Serial.println();
GPS_OutputOff(); //GPS interrupts cause problems with lora device, so turn off for now
setStatusByte(GPSError, 0);
setStatusByte(GPSConfigError, 0);
//Alert user to GPS OK, turn LED on and send a FM tone
digitalWrite(LED1, HIGH);
Serial.println(F("GPS Config OK")); //check tone indicates navigation model 6 set
Serial.println();
Serial.flush();
LT.setupDirect(TrackerFrequency, Offset); //need direct mode for tones
LT.toneFM(1500, 500, deviation, adjustfreq, TrackerTXpower); //Transmit an FM tone, 1000hz, 3000ms
delay(1000);
digitalWrite(LED1, LOW);
}
else
{
setStatusByte(GPSConfigError, 1);
incMemoryUint16(addr_TXErrors);
Serial.println(F("GPS Error"));
Serial.println();
setTrackerMode();
sendCommand(NoGPS); //make sure receiver knows about GPS error
led_Flash(100, 25); //long very rapid flash for GPS error
}
GPSstartms = millis();
setTrackerMode(); //so that commands indicating wait for a GPS go out
while (!gpsWaitFix(5)) //wait for the initial GPS fix, this could take a while
{
sendCommand(NoFix);
led_Flash(2, 50); //two short LED flashes to indicate GPS waiting for fix
}
LT.setupDirect(TrackerFrequency, Offset); //need direct mode for tones
digitalWrite(LED1, HIGH);
LT.toneFM(500, 2000, deviation, adjustfreq, TrackerTXpower);
digitalWrite(LED1, LOW);
GPS_OutputOn();
delay(2000); //GPS may be in software backup allow time for it to wakeup
GPS_SetCyclicMode(); //set this regardless of whether hot fix mode is enabled
GPS_OutputOff();
}

View File

@@ -0,0 +1,143 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 29/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//**************************************************************************************************
// 1) Hardware related definitions and options - specify lora board type and pins here
//**************************************************************************************************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup.
#define NSS 10 //select on LoRa device
#define NRESET 9 //reset on LoRa device
#define DIO0 3 //DIO0 on LoRa device, used for RX and TX done
#define LED1 8 //On board LED, high for on
#define BATVREADON 8 //Pin that turns on the resistor divider to read battery volts
#define ONE_WIRE_BUS 4 //for DS18B20 temperature sensor
#define ADMultiplier 5.25 //adjustment to convert into mV of battery voltage. for 100K\10K divider
#define SupplyAD A0 //Resistor divider for battery connected here
#define RXpin A3 //pin number for GPS RX input into Arduino - TX from GPS
#define TXpin A2 //pin number for GPS TX output from Arduino- RX into GPS
#define GPSPOWER -1 //Pin that powers GPS on\off, set to -1 if not used
#define GPSONSTATE HIGH //logic level to turn GPS on via pin GPSPOWER
#define GPSOFFSTATE LOW //logic level to turn GPS off via pin GPSPOWER
#define LORA_DEVICE DEVICE_SX1278 //this is the device we are using
//**************************************************************************************************
// 2) Program Options
//**************************************************************************************************
//#define ClearAllMemory //Clears memory of stored tracker information, counts, errors etc
//**************************************************************************************************
// 3) LoRa modem settings
//**************************************************************************************************
//LoRa Modem Parameters
const uint32_t Offset = 0; //offset frequency for calibration purposes
//Tracker mode
const uint32_t TrackerFrequency = 434000000; //frequency of transmissions
const uint8_t TrackerBandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t TrackerSpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t TrackerCodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t TrackerOptimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t TrackerTXpower = 10; //LoRa TX power in dBm
//Search mode
const uint32_t SearchFrequency = 434000000; //frequency of transmissionsconst
uint8_t SearchBandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t SearchSpreadingFactor = LORA_SF12; //LoRa spreading factor
const uint8_t SearchCodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t SearchOptimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t SearchTXpower = 10; //LoRa TX power in dBm
const uint16_t deviation = 10000; //deviation in hz for FM tones
const float adjustfreq = 0.9; //adjustment to tone frequency
const uint8_t TXBUFFER_SIZE = 128; //defines the maximum size of the trasnmit buffer;
//**************************************************************************************************
// 4) GPS Options
//**************************************************************************************************
#define GPSBaud 9600 //GPS Baud rate
//#define USEI2CGPS //enable this define if your using a Ublox over the I2C interface
//#define GPS_Library <UBLOXI2CGPS.h> //and define this library file for the UBLOX GPS over I2C
#define USESOFTSERIALGPS //if your using software serial for the GPS, enable this define
//#define USEHARDWARESERIALGPS //if your using hardware serial for the GPS, enable this define
#define HARDWARESERIALPORT Serial1 //if your using hardware serial for the GPS, define the port here
//#define GPS_Library <UBLOXSerialGPS.h> //use library file for UBLOX GPS
#define GPS_Library <QuectelSerialGPS.h> //use library file for Quectel GPS
const uint16_t WaitGPSFixSeconds = 60; //when in flight the time to wait for a new GPS fix
//**************************************************************************************************
// 5) FSK RTTY Settings
//**************************************************************************************************
uint32_t FrequencyShift = 500; //hertz frequency shift, approx, sent at nearest 61.03515625hz step
uint8_t NumberofPips = 4; //number of marker pips to send
uint16_t PipDelaymS = 1000; //mS between pips when carrier is off
uint16_t PipPeriodmS = 100; //mS length of pip
uint16_t BaudPerioduS = 10000; //uS period for baud, 10000uS for 100baud
uint16_t LeadinmS = 1000; //ms of leadin constant shifted carrier
//****************************************************************************************************
// 6) Program Default Option settings - This section determines which options are on or off by default,
// these are saved in the Default_config1 byte. These options are set in this way so that it is
// possible (in future program changes) to alter the options remotly.
//**************************************************************************************************
uint8_t OptionOff = 0;
uint8_t OptionOn = 1;
const char option_SearchEnable = OptionOn; //set to OptionOn to enable transmit of Search mode packet
const char option_FSKRTTYEnable = OptionOn; //set to OptionOn to enable transmit of FSKRTTY
#define option_SearchEnable_SUM (option_SearchEnable*1)
#define option_FSKRTTYEnable_SUM (option_FSKRTTYEnable*4)
const uint16_t Default_config1 = (option_SearchEnable_SUM + option_FSKRTTYEnable_SUM);
//const uint16_t Default_config1 = 0x05; //Phew, the default config can always be set manually........
//0x05 would turn on transmit of search mode and FSKRTTY
//**************************************************************************************************
// 7) Memory settings - define the type of memory to use for non-Volatile storage.
// Default is internal ATmega device EEPROM but EEPROM has a limited write endurance of 'only'
// 100,000 writes. Since the non-Volatile memory selected is written to at each transmission loop
// and error, its highly recommended to use one of the FRAM options, these have an endurance of
// 100,000,000,000,000 writes.
//**************************************************************************************************
#define Memory_Library <EEPROM_Memory.h>
//#define Memory_Library <FRAM_MB85RC16PNF.h>
//#define Memory_Library <FRAM_FM24CL64.h>
int16_t Memory_Address = 0x50; //default I2C address of MB85RC16PNF and FM24CL64 FRAM
//**************************************************************************************************
// 8) HAB Flight Settings
//**************************************************************************************************
char FlightID[] = "Flight1"; //flight ID for HAB packet
const uint16_t SleepTimesecs = 13; //sleep time in seconds after each TX loop
const char ThisNode = '1'; //tracker number for search packet

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1,103 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 29/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//**************************************************************************************************
// 1) Hardware related definitions and options - specify lora board type and pins here
//**************************************************************************************************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitiosn to match your own setup.
#define NSS 10 //select on LoRa device
#define NRESET 9 //reset on LoRa device
#define DIO0 3 //DIO0 on LoRa device, used for RX and TX done
#define LED1 8 //On board LED, high for on
#define SWITCH1 2 //if pin shorted to ground, switch is active
#define RXpin A3 //pin number for GPS RX input into Arduino - TX from GPS
#define TXpin A2 //pin number for GPS TX output from Arduino- RX into GPS
#define GPSPOWER -1 //Pin that controls power to GPS, set to -1 if not used
#define GPSONSTATE HIGH //logic level to turn GPS on via pin GPSPOWER
#define GPSOFFSTATE LOW //logic level to turn GPS off via pin GPSPOWER
#define AUDIOOUT 6 //pin used to output Audio tones for HAB packet upload
#define CHECK 8 //this pin is toggled inside the AFSKRTTY library, high for logic 1, low for logic 0, so it can be used to check the timing.
#define LORA_DEVICE DEVICE_SX1278 //this is the LoRa device we are using
//**************************************************************************************************
// 2) Program Options
//**************************************************************************************************
//**************************************************************************************************
// 3) LoRa modem settings
//**************************************************************************************************
const uint32_t Offset = 0; //offset frequency for calibration purposes
//Tracker mode
const uint32_t TrackerFrequency = 434000000; //frequency of transmissions
const uint8_t TrackerBandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t TrackerSpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t TrackerCodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t TrackerOptimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t TrackerTXpower = 10; //LoRa TX power in dBm
const uint8_t TrackerMode = 1; //used for receiver to tell whatmode it is in
//Search mode
const uint32_t SearchFrequency = 434000000; //frequency of transmissions
const uint8_t SearchBandwidth = LORA_BW_062;; //LoRa bandwidth
const uint8_t SearchSpreadingFactor = LORA_SF12; //LoRa spreading factor
const uint8_t SearchCodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t SearchOptimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t SearchTXpower = 10; //LoRa TX power in dBm
const uint8_t SearchMode = 2; //used for receiver to tell whatmode it is in
const uint8_t RXBUFFER_SIZE = 128; //RX buffer size
//**************************************************************************************************
// 4) GPS Options
//**************************************************************************************************
const uint16_t GPSBaud = 9600; //GPS Baud rate
#define USESOFTSERIALGPS //if your using software serial for the GPS, enable this define
//#define USEHARDWARESERIALGPS //if your using hardware serial for the GPS, enable this define
#define HARDWARESERIALPORT Serial1 //if using hardware serial enable this define for hardware serial port
const uint16_t WaitGPSFixSeconds = 30; //time to wait for a new GPS fix
const uint16_t NoRXGPSfixms = 15000; //max number of mS to allow before no local fix flagged
const uint8_t DisplayRate = 7; //when working OK the GPS will get a new fix every second or so
//this rate defines how often the display should be updated
//**************************************************************************************************
// 6) AFSK RTTY Settings - For PC upload into Dl-Fldigi in HAB mode.
// Sent at 200baud, 7 bit, no parity, 2 stop bits.
// Shift circa 360hz, low tone 1000hz, high tone 1400hz (measured on an Arduino Due)
// See screenshot 'AFSKRTTY2_DL-Fldigi_Settings.jpg' in this folder for the settings used
//
//**************************************************************************************************
#define UPLOADHABPACKET //comment in define to output HAB packet as AFSKRTTY for PC upload
const uint16_t leadinmS = 2000; //number of ms for AFSK constant lead in tone
const uint16_t leadoutmS = 0; //number of ms for AFSK constant lead out tone
const uint16_t LOWPERIODUS = 1000; //actual period in uS of to give a 200baud
const uint8_t LOWCYCLES = 5; //cycles of low frequency tone for 200baud
const uint16_t HIGHPERIODUS = 714; //actual high period in uS to give a 200baud
const uint8_t HIGHCYCLES = 7; //cycles of high frequency tone for 200baud
const int8_t ADJUSTUS = 0; //uS to subtract from tone generation loop to match frequency

View File

@@ -0,0 +1,786 @@
/******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 28/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This is a tracker intended for use as a high altitude balloon (HAB) tracker. The
program sends out a standard format payload with LoRa that is compatible with the HABHUB online tracking
system.
The HAB payload is constructed thus;
PayloadID,Sequence,Time,Lat,Lon,Alt,Satellites,Volts,Temperature,Resets,Status,Errors,TXGPSfixms,Checksum
Field 0 1 2 3 4 5 6 7 8 9 10 11 12 13
The LoRa and frequency settings can be changed in the Settings.h file. There is the option of sending
out a much shorter Search mode binary location only payload. This is intended for ground based searching
and locating. The frequency and LoRa settings of the Search mode packet can be different to the Tracker
mode used by the HAB payload. There is also the option of sending the HAB payload in FSK RTTY format,
see the Settings.h file for all the options. FSK RTTY gets sent at the same frequency as the Tracker mode
HAB packet. The LT.transmitFSKRTTY() function sends at 1 start bit, 7 data bits, no parity and 2 stop bits.
For full control of the FSK RTTY setting you can use the following alternative function;
LT.transmitFSKRTTY(chartosend, databits, stopbits, parity, baudPerioduS, pin)
There is a matching Balloon Tracker Receiver program which writes received data to the Serial monitor as well
as a small OLED display.
In the Settings.h file you can set the configuration for either a Ublox GPS or a Quectel L70\L80. The GPSs
are configured for high altitude balloon mode.
It is strongly recommended that a FRAM option is fitted for this transmitter. The sequence, resets and error
nembers are stred in non-volatile memory. This defaults to EEPROM which has a limited endurance of only
100,000 writes, so in theory the limt is reached after the transmission of 100,000 hab packets. The use of
a FRAM will extend the life of the tracker to circa 100,000,000,000,000 transmissions.
Changes:
240420 - Change to work with Easy Pro Mini style modules
300420 - Improve error detection for UBLOX GPS library
ToDo:
Serial monitor baud rate is set at 115200
*******************************************************************************************************/
#define Program_Version "V1.1"
#include <Arduino.h>
#include <SX127XLT.h> //include the appropriate library
SX127XLT LT; //create a library class instance called LT
#include "Settings.h"
#include "ProgramLT_Definitions.h"
//**************************************************************************************************
// HAB tracker data - these are the variables transmitted in payload
//**************************************************************************************************
uint32_t TXSequence; //sequence number of payload
uint8_t TXHours; //Hours
uint8_t TXMinutes; //Minutes
uint8_t TXSeconds; //Seconds
float TXLat; //latitude from GPS
float TXLon; //longitude from GPS
uint16_t TXAlt; //altitude from GPS
uint8_t TXSatellites; //satellites used by GPS
uint16_t TXVolts; //measured tracker supply volts
int8_t TXTemperature; //measured temperature
uint16_t TXResets; //number of tracker resets
uint8_t TXStatus = 0; //used to store current status flag bits
uint16_t TXErrors; //number of tracker Errors
uint32_t TXGPSfixms; //fix time of GPS
//**************************************************************************************************
uint8_t TXPacketL; //length of LoRa packet sent
uint8_t TXBUFFER[TXBUFFER_SIZE]; //buffer for packet to send
#include Memory_Library
#include <SPI.h>
#include <TinyGPS++.h> //http://arduiniana.org/libraries/tinygpsplus/
TinyGPSPlus gps; //create the TinyGPS++ object
#ifdef USESOFTSERIALGPS
//#include <NeoSWSerial.h> //https://github.com/SlashDevin/NeoSWSerial
//NeoSWSerial GPSserial(RXpin, TXpin); //The NeoSWSerial library is an option to use and is more relaible
//at GPS init than software serial
#include <SoftwareSerial.h>
SoftwareSerial GPSserial(RXpin, TXpin);
#endif
#ifdef USEHARDWARESERIALGPS
#define GPSserial HARDWARESERIALPORT
#endif
#ifdef USEI2CGPS
#include <Wire.h>
#endif
#include <OneWire.h> //get library here > https://github.com/PaulStoffregen/OneWire
OneWire oneWire(ONE_WIRE_BUS); //create instance of OneWire library
#include <DallasTemperature.h> //get library here > https://github.com/milesburton/Arduino-TXTemperature-Control-Library
DallasTemperature sensor(&oneWire); //create instance of dallas library
uint32_t GPSstartms; //start time waiting for GPS to get a fix
void loop()
{
Serial.println(F("Start Loop"));
GPSstartms = millis();
if (!gpsWaitFix(WaitGPSFixSeconds))
{
GPSOutputOff();
sendCommand(NoFix); //report a GPS fix error
delay(1000); //give receiver enough time to report NoFix
}
Serial.println();
do_Transmissions(); //do the transmissions
Serial.println(F("Sleep"));
LT.setSleep(CONFIGURATION_RETENTION); //put LoRa device to sleep, preserve lora register settings
Serial.flush(); //make sure no serial output pending before goint to sleep
delay(SleepTimesecs * 1000);
Serial.println(F("Wake"));
LT.wake(); //wake the LoRa device from sleep
}
void do_Transmissions()
{
//this is where all the transmisions get sent
uint32_t startTimemS;
uint8_t index;
incMemoryUint32(addr_SequenceNum); //increment Sequence number
if (readConfigByte(SearchEnable))
{
setSearchMode();
TXPacketL = buildLocationOnly(TXLat, TXLon, TXAlt, TXStatus); //put location data in SX12xx buffer
Serial.print(F("Search packet > "));
Serial.print(TXLat, 5);
Serial.print(F(","));
Serial.print(TXLon, 5);
Serial.print(F(","));
Serial.print(TXAlt);
Serial.print(F(","));
Serial.print(TXStatus);
digitalWrite(LED1, HIGH);
startTimemS = millis();
TXPacketL = LT.transmitSXBuffer(0, TXPacketL, 10000, SearchTXpower, WAIT_TX);
printTXtime(startTimemS, millis());
reportCompletion();
Serial.println();
}
delay(1000); //gap between transmissions
setTrackerMode();
TXPacketL = buildHABPacket();
Serial.print(F("HAB Packet > "));
printBuffer(TXBUFFER, (TXPacketL + 1)); //print the buffer (the packet to send) as ASCII
digitalWrite(LED1, HIGH);
startTimemS = millis();
TXPacketL = LT.transmit(TXBUFFER, (TXPacketL + 1), 10000, TrackerTXpower, WAIT_TX); //will return packet length sent if OK, otherwise 0 if transmit error
digitalWrite(LED1, LOW);
printTXtime(startTimemS, millis());
reportCompletion();
Serial.println();
delay(1000); //gap between transmissions
if (readConfigByte(FSKRTTYEnable)) //FSKRTTY is sent last, so that receiver has time to use AFSK upload
{
LT.setupDirect(TrackerFrequency, Offset);
LT.startFSKRTTY(FrequencyShift, NumberofPips, PipPeriodmS, PipDelaymS, LeadinmS);
startTimemS = millis() - LeadinmS;
Serial.print(F("FSK RTTY > $$$"));
Serial.flush();
LT.transmitFSKRTTY('$', BaudPerioduS, LED1); //send a '$' as sync
LT.transmitFSKRTTY('$', BaudPerioduS, LED1); //send a '$' as sync
LT.transmitFSKRTTY('$', BaudPerioduS, LED1); //send a '$' as sync
for (index = 0; index <= (TXPacketL - 1); index++) //its TXPacketL-1 since we dont want to send the null at the end
{
LT.transmitFSKRTTY(TXBUFFER[index], BaudPerioduS, LED1);
Serial.write(TXBUFFER[index]);
}
LT.transmitFSKRTTY(13, BaudPerioduS, LED1); //send carriage return
LT.transmitFSKRTTY(10, BaudPerioduS, LED1); //send line feed
LT.endFSKRTTY(); //stop transmitting carrier
digitalWrite(LED1, LOW); //LED off
printTXtime(startTimemS, millis());
TXPacketL += 4; //add the two $ at beginning and CR/LF at end
reportCompletion();
Serial.println();
}
}
void printTXtime(uint32_t startmS, uint32_t endmS)
{
Serial.print(F(" "));
Serial.print(endmS - startmS);
Serial.print(F("mS"));
}
void reportCompletion()
{
Serial.print(F(" "));
if (TXPacketL == 0)
{
Serial.println();
reporttransmitError();
}
else
{
Serial.print(TXPacketL);
Serial.print(F("bytes"));
setStatusByte(LORAError, 0);
}
}
void printBuffer(uint8_t *buffer, uint8_t size)
{
uint8_t index;
for (index = 0; index < size; index++)
{
Serial.write(buffer[index]);
}
}
uint8_t buildHABPacket()
{
//build the HAB tracker payload
uint16_t index, j, CRC;
uint8_t Count, len;
char LatArray[12], LonArray[12];
TXSequence = readMemoryUint32(addr_SequenceNum); //Sequence number is kept in non-volatile memory so it survives TXResets
TXResets = readMemoryUint16(addr_ResetCount); //reset count is kept in non-volatile memory so it survives TXResets
TXVolts = readSupplyVoltage();
Serial.print(F("TXVolts "));
Serial.print(TXVolts);
Serial.println(F("mV"));
TXTemperature = (int8_t) readTempDS18B20();
TXErrors = readMemoryUint16(addr_TXErrors);
dtostrf(TXLat, 7, 5, LatArray); //format is dtostrf(FLOAT,WIDTH,PRECISION,BUFFER);
dtostrf(TXLon, 7, 5, LonArray); //converts float to character array
len = sizeof(TXBUFFER);
memset(TXBUFFER, 0, len); //clear array to 0s
Count = snprintf((char*) TXBUFFER,
TXBUFFER_SIZE,
"$%s,%lu,%02d:%02d:%02d,%s,%s,%d,%d,%d,%d,%d,%d,%d,%lu",
FlightID,
TXSequence,
TXHours,
TXMinutes,
TXSeconds,
LatArray,
LonArray,
TXAlt,
TXSatellites,
TXVolts,
TXTemperature,
TXResets,
TXStatus,
TXErrors,
TXGPSfixms
);
CRC = 0xffff; //start value for CRC16
for (index = 1; index < Count; index++) //element 1 is first character after $ at start (for LoRa)
{
CRC ^= (((uint16_t)TXBUFFER[index]) << 8);
for (j = 0; j < 8; j++)
{
if (CRC & 0x8000)
CRC = (CRC << 1) ^ 0x1021;
else
CRC <<= 1;
}
}
TXBUFFER[Count++] = '*';
TXBUFFER[Count++] = Hex((CRC >> 12) & 15); //add the checksum bytes to the end
TXBUFFER[Count++] = Hex((CRC >> 8) & 15);
TXBUFFER[Count++] = Hex((CRC >> 4) & 15);
TXBUFFER[Count] = Hex(CRC & 15);
return Count;
}
char Hex(uint8_t lchar)
{
//used in CRC calculation in buildHABPacket
char Table[] = "0123456789ABCDEF";
return Table[lchar];
}
uint8_t buildLocationOnly(float Lat, float Lon, uint16_t Alt, uint8_t stat)
{
uint8_t len;
LT.startWriteSXBuffer(0); //initialise buffer write at address 0
LT.writeUint8(LocationBinaryPacket); //identify type of packet
LT.writeUint8(Broadcast); //who is the packet sent too
LT.writeUint8(ThisNode); //tells receiver where is packet from
LT.writeFloat(Lat); //add latitude
LT.writeFloat(Lon); //add longitude
LT.writeInt16(Alt); //add altitude
LT.writeUint8(stat); //add tracker status
len = LT.endWriteSXBuffer(); //close buffer write
return len;
}
void reporttransmitError()
{
uint16_t IRQStatus;
IRQStatus = LT.readIrqStatus(); //read the the interrupt register
Serial.print(F("TXError,"));
Serial.print(F(",IRQreg,"));
Serial.print(IRQStatus, HEX); //print IRQ status
LT.printIrqStatus(); //prints the text of which IRQs set
incMemoryUint16(addr_TXErrors); //increase the error count
setStatusByte(LORAError, 1);
}
void incMemoryUint32(uint32_t addr)
{
uint32_t val = readMemoryUint32(addr);
val++;
writeMemoryUint32(addr, val);
}
void incMemoryUint16(uint32_t addr)
{
uint16_t val = readMemoryUint16(addr);
val++;
writeMemoryUint16(addr, val);
}
void setStatusByte(uint8_t bitnum, uint8_t bitval)
{
//program the status byte
if (bitval == 0)
{
bitClear(TXStatus, bitnum);
}
else
{
bitSet(TXStatus, bitnum);
}
}
uint8_t readConfigByte(uint8_t bitnum)
{
return bitRead(Default_config1, bitnum);
}
void setTrackerMode()
{
Serial.println(F("setTrackerMode"));
LT.setupLoRa(TrackerFrequency, Offset, TrackerSpreadingFactor, TrackerBandwidth, TrackerCodeRate, TrackerOptimisation);
}
void setSearchMode()
{
Serial.println(F("setSearchMode"));
LT.setupLoRa(SearchFrequency, Offset, SearchSpreadingFactor, SearchBandwidth, SearchCodeRate, SearchOptimisation);
}
uint8_t sendCommand(char cmd)
{
uint8_t len;
TXVolts = readSupplyVoltage();
Serial.print(F("Send Cmd "));
Serial.write(cmd);
Serial.println();
LT.startWriteSXBuffer(0); //start the write packet to buffer process
LT.writeUint8(cmd); //this byte defines the packet type
LT.writeUint8(Broadcast); //destination address of the packet, the receivers address
LT.writeUint8(ThisNode); //source address of this node
LT.writeUint16(TXVolts); //add the battery voltage
LT.writeUint8(TXStatus); //add the status byte
len = LT.endWriteSXBuffer(); //close the packet, get the length of data to be sent
//now transmit the packet, set a timeout of 5000mS, wait for it to complete sending
digitalWrite(LED1, HIGH); //turn on LED as an indicator
TXPacketL = LT.transmitSXBuffer(0, len, 5000, TrackerTXpower, WAIT_TX);
digitalWrite(LED1, LOW); //turn off indicator LED
return TXPacketL; //TXPacketL will be 0 if there was an error sending
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
//flash LED to show tracker is alive
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void clearAllMemory()
{
//clears the whole of non-volatile
Serial.println(F("Clear Memory"));
fillMemory(addr_StartMemory, addr_EndMemory, 0);
}
float readTempDS18B20()
{
float DS18B20TXTemperature;
sensor.requestTemperatures();
DS18B20TXTemperature = sensor.getTempCByIndex(0);
return DS18B20TXTemperature;
}
void printTempDS18B20()
{
float DS18B20TXTemperature;
DS18B20TXTemperature = readTempDS18B20();
Serial.print(F("Temperature "));
Serial.print(DS18B20TXTemperature, 1);
Serial.println(F("c"));
}
void printSupplyVoltage()
{
//get and display supply volts on terminal or monitor
Serial.print(F("Volts "));
Serial.print(readSupplyVoltage());
Serial.println(F("mV"));
}
uint16_t readSupplyVoltage()
{
//relies on internal reference and 91K & 11K resistor divider
//returns supply in mV @ 10mV per AD bit read
uint16_t temp;
uint16_t volts = 0;
uint8_t index;
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, HIGH); //turn MOSFET connection resitor divider in circuit
}
analogReference(INTERNAL);
temp = analogRead(SupplyAD);
for (index = 0; index <= 9; index++) //sample AD 10 times
{
temp = analogRead(SupplyAD);
volts = volts + temp;
delay(10);
}
volts = ( (float) (volts / 10) * ADMultiplier);
if (BATVREADON >= 0)
{
digitalWrite(BATVREADON, LOW); //turn MOSFET connection resitor divider in circuit
}
return volts;
}
//***********************************************************
// Start GPS Functions
//***********************************************************
void GPSTest()
{
uint8_t GPSchar;
uint32_t startmS;
startmS = millis();
while ( (uint32_t) (millis() - startmS) < 2000) //allows for millis() overflow
{
if (GPSserial.available() > 0)
{
GPSchar = GPSserial.read();
Serial.write(GPSchar);
}
}
Serial.println();
Serial.println();
Serial.flush();
}
bool gpsWaitFix(uint16_t waitSecs)
{
//waits a specified number of seconds for a fix, returns true for good fix
uint32_t startmS, waitmS;
uint8_t GPSchar;
Serial.flush();
Serial.print(F("Wait GPS Fix "));
Serial.print(waitSecs);
Serial.println(F("s "));
Serial.flush();
GPSOutputOn();
waitmS = waitSecs * 1000;
startmS = millis();
while ( (uint32_t) (millis() - startmS) < waitmS) //allows for millis() overflow
{
if (GPSserial.available() > 0)
{
GPSchar = GPSserial.read();
gps.encode(GPSchar);
Serial.write(GPSchar);
}
if (gps.location.isUpdated() && gps.altitude.isUpdated() && gps.date.isUpdated())
{
TXLat = gps.location.lat();
TXLon = gps.location.lng();
TXAlt = (uint16_t) gps.altitude.meters();
//Altitude is used as an unsigned integer, so that the binary payload is as short as possible.
//However gps.altitude.meters(); can return a negative value which converts to
//65535 - Altitude, which we dont want. So we will assume any value over 60,000M is zero
if (TXAlt > 60000)
{
TXAlt = 0;
}
TXHours = gps.time.hour(),
TXMinutes = gps.time.minute(),
TXSeconds = gps.time.second(),
TXSatellites = gps.satellites.value();
setStatusByte(GPSFix, 1);
TXGPSfixms = millis() - GPSstartms;
Serial.flush();
Serial.println();
Serial.print(F("Have GPS Fix "));
Serial.print(TXGPSfixms);
Serial.print(F("mS"));
Serial.println();
GPSprintTime();
GPSprintDate();
Serial.flush();
return true;
}
}
//if here then there has been no fix and a timeout
GPSOutputOff();
setStatusByte(GPSFix, 0); //set status bit to flag no fix
incMemoryUint16(addr_TXErrors);
Serial.println(F("Error No GPS Fix"));
return false;
}
void GPSprintTime()
{
uint8_t hours, mins, secs;
hours = gps.time.hour();
mins = gps.time.minute();
secs = gps.time.second();
Serial.print(F("Time "));
if (hours < 10)
{
Serial.print(F("0"));
}
Serial.print(hours);
Serial.print(F(":"));
if (mins < 10)
{
Serial.print(F("0"));
}
Serial.print(mins);
Serial.print(F(":"));
if (secs < 10)
{
Serial.print(F("0"));
}
Serial.println(secs);
}
void GPSprintDate()
{
Serial.print(F("Date "));
Serial.print(gps.date.day());
Serial.print(F("/"));
Serial.print(gps.date.month());
Serial.print(F("/"));
Serial.println(gps.date.year());
}
void GPSOutputOn()
{
GPSserial.begin(GPSBaud);
while (GPSserial.available()) GPSserial.read(); //make sure input buffer is empty
}
void GPSOutputOff()
{
//turns off serial output from GPS
GPSserial.end();
}
//***********************************************************
// End GPS Functions
//***********************************************************
void setup()
{
uint32_t i;
uint16_t j;
Serial.begin(115200); //Setup Serial console ouput
Serial.println();
Serial.println();
Serial.println(F("67_HAB_Balloon_Tracker_Transmitter Starting"));
memoryStart(Memory_Address); //setup the memory
j = readMemoryUint16(addr_ResetCount);
j++;
writeMemoryUint16(addr_ResetCount, j);
j = readMemoryUint16(addr_ResetCount);
Serial.print(F("TXResets "));
Serial.println(j);
if (GPSPOWER >= 0) //if GPS needs power switching, turn it on
{
pinMode(GPSPOWER, OUTPUT);
digitalWrite(GPSPOWER, GPSONSTATE);
}
if (BATVREADON >= 0)
{
pinMode(BATVREADON, OUTPUT); //for MOSFET controlling battery volts resistor divider
}
#ifdef QUECTELINUSE
Serial.println(F("Quectel GPS library"));
#endif
#ifdef UBLOXINUSE
Serial.println(F("UBLOX GPS library"));
#endif
#ifdef ClearAllMemory
clearAllMemory();
#endif
SPI.begin(); //initialize SPI
if (LT.begin(NSS, NRESET, DIO0, LORA_DEVICE))
{
led_Flash(2, 125);
}
else
{
Serial.println(F("LoRa Device error"));
while (1)
{
led_Flash(50, 50); //long fast speed flash indicates device error
}
}
setTrackerMode();
Serial.print(F("Config "));
Serial.println(Default_config1, BIN);
j = readMemoryUint16(addr_TXErrors);
Serial.print(F("TXErrors "));
Serial.println(j);
Serial.print(F("TXSequence "));
i = readMemoryUint32(addr_SequenceNum);
Serial.println(i);
Serial.print(F("ThisNode "));
Serial.println(ThisNode);
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
Serial.println();
printSupplyVoltage();
printTempDS18B20();
Serial.println();
TXStatus = 0; //clear all TX status bits
sendCommand(PowerUp); //send power up command, includes supply mV and config, on tracker settings
GPSOutputOn();
Serial.println();
Serial.println(F("GPS output test"));
Serial.flush();
GPSTest(); //copy GPS output to serial monitor as a test
delay(2000);
GPSstartms = millis();
setTrackerMode(); //so that commands indicating wait for a GPS go out
while (!gpsWaitFix(5)) //wait for the initial GPS fix, this could take a while
{
sendCommand(NoFix);
led_Flash(2, 50); //two short LED flashes to indicate GPS waiting for fix
}
LT.setupDirect(TrackerFrequency, Offset); //need direct mode for tones
digitalWrite(LED1, HIGH);
LT.toneFM(500, 2000, deviation, adjustfreq, TrackerTXpower);
digitalWrite(LED1, LOW);
GPSOutputOn();
delay(2000); //GPS may be in software backup allow time for it to wakeup
GPSOutputOff();
}

View File

@@ -0,0 +1,137 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 29/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//**************************************************************************************************
// 1) Hardware related definitions and options - specify lora board type and pins here
//**************************************************************************************************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup.
#define NSS 10 //select on LoRa device
#define NRESET 9 //reset on LoRa device
#define DIO0 3 //DIO0 on LoRa device, used for RX and TX done
#define LED1 8 //On board LED, high for on
#define BATVREADON 8 //Pin that turns on the resistor divider to read battery volts
#define ONE_WIRE_BUS 4 //for DS18B20 temperature sensor
#define ADMultiplier 5.25 //adjustment to convert into mV of battery voltage. for 100K\10K divider
#define SupplyAD A0 //Resistor divider for battery connected here
#define RXpin A3 //pin number for GPS RX input into Arduino - TX from GPS
#define TXpin A2 //pin number for GPS TX output from Arduino- RX into GPS
#define GPSPOWER -1 //Pin that powers GPS on\off, set to -1 if not used
#define GPSONSTATE HIGH //logic level to turn GPS on via pin GPSPOWER
#define GPSOFFSTATE LOW //logic level to turn GPS off via pin GPSPOWER
#define LORA_DEVICE DEVICE_SX1278 //this is the device we are using
//**************************************************************************************************
// 2) Program Options
//**************************************************************************************************
//#define ClearAllMemory //Clears memory of stored tracker information, counts, errors etc
//**************************************************************************************************
// 3) LoRa modem settings
//**************************************************************************************************
//LoRa Modem Parameters
const uint32_t Offset = 0; //offset frequency for calibration purposes
//Tracker mode
const uint32_t TrackerFrequency = 434000000; //frequency of transmissions
const uint8_t TrackerBandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t TrackerSpreadingFactor = LORA_SF8; //LoRa spreading factor
const uint8_t TrackerCodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t TrackerOptimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t TrackerTXpower = 10; //LoRa TX power in dBm
//Search mode
const uint32_t SearchFrequency = 434000000; //frequency of transmissionsconst
uint8_t SearchBandwidth = LORA_BW_062; //LoRa bandwidth
const uint8_t SearchSpreadingFactor = LORA_SF12; //LoRa spreading factor
const uint8_t SearchCodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t SearchOptimisation = LDRO_AUTO; //low data rate optimisation setting
const int8_t SearchTXpower = 10; //LoRa TX power in dBm
const uint16_t deviation = 10000; //deviation in hz for FM tones
const float adjustfreq = 0.9; //adjustment to tone frequency
const uint8_t TXBUFFER_SIZE = 128; //defines the maximum size of the trasnmit buffer;
//**************************************************************************************************
// 4) GPS Options - Settings for a generic GPS, no attempt is made to put the GPS into balloon mode
//**************************************************************************************************
#define GPSBaud 9600 //GPS Baud rate
#define USESOFTSERIALGPS //if your using software serial for the GPS, enable this define
//#define USEHARDWARESERIALGPS //if your using hardware serial for the GPS, enable this define
#define HARDWARESERIALPORT Serial1 //if your using hardware serial for the GPS, define the port here
const uint16_t WaitGPSFixSeconds = 60; //when in flight the time to wait for a new GPS fix
//**************************************************************************************************
// 5) FSK RTTY Settings
//**************************************************************************************************
uint32_t FrequencyShift = 500; //hertz frequency shift, approx, sent at nearest 61.03515625hz step
uint8_t NumberofPips = 4; //number of marker pips to send
uint16_t PipDelaymS = 1000; //mS between pips when carrier is off
uint16_t PipPeriodmS = 100; //mS length of pip
uint16_t BaudPerioduS = 10000; //uS period for baud, 10000uS for 100baud
uint16_t LeadinmS = 1000; //ms of leadin constant shifted carrier
//****************************************************************************************************
// 6) Program Default Option settings - This section determines which options are on or off by default,
// these are saved in the Default_config1 byte. These options are set in this way so that it is
// possible (in future program changes) to alter the options remotly.
//**************************************************************************************************
uint8_t OptionOff = 0;
uint8_t OptionOn = 1;
const char option_SearchEnable = OptionOn; //set to OptionOn to enable transmit of Search mode packet
const char option_FSKRTTYEnable = OptionOn; //set to OptionOn to enable transmit of FSKRTTY
#define option_SearchEnable_SUM (option_SearchEnable*1)
#define option_FSKRTTYEnable_SUM (option_FSKRTTYEnable*4)
const uint16_t Default_config1 = (option_SearchEnable_SUM + option_FSKRTTYEnable_SUM);
//const uint16_t Default_config1 = 0x05; //Phew, the default config can always be set manually........
//0x05 would turn on transmit of search mode and FSKRTTY
//**************************************************************************************************
// 7) Memory settings - define the type of memory to use for non-Volatile storage.
// Default is internal ATmega device EEPROM but EEPROM has a limited write endurance of 'only'
// 100,000 writes. Since the non-Volatile memory selected is written to at each transmission loop
// and error, its highly recommended to use one of the FRAM options, these have an endurance of
// 100,000,000,000,000 writes.
//**************************************************************************************************
#define Memory_Library <EEPROM_Memory.h>
//#define Memory_Library <FRAM_MB85RC16PNF.h>
//#define Memory_Library <FRAM_FM24CL64.h>
int16_t Memory_Address = 0x50; //default I2C address of MB85RC16PNF and FM24CL64 FRAM
//**************************************************************************************************
// 8) HAB Flight Settings
//**************************************************************************************************
char FlightID[] = "Flight1"; //flight ID for HAB packet
const uint16_t SleepTimesecs = 13; //sleep time in seconds after each TX loop
const char ThisNode = '1'; //tracker number for search packet

View File

@@ -0,0 +1,98 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 29/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This test program has been written to check that the hardware for sending AFSK RTTY on
been connected correctly. AFSKRTTY can be used to upload packets received from a high altitude balloon
tracker as LoRa into DL-FLDIGI running on a PC and from there uploaded to an Internet connected tracking
system.
The AFSK RTTY library has been tested and will work on an Arduion Pro Mini 8Mhz, Arduino DUE and ESP32
when used with this startup command;
startAFSKRTTY(AUDIOOUTpin, CHECKpin, 5, 1000, 7, 714, 0, 1000);
This outputs AFSKRTTY at 200baud, 7 databits, 1 startbit, 2 stopbits, no parity, low tone 1000hz, hightone 1400hz.
The audio comes out of the pin passed via AUDIOOUTpin and the bit timing can be checked by looking at
the CHECKpin on a scope or analyser.
A low pass filter consiting of a deries 47K resistor and parallel 470nF capacitor was used to reduce the output
for feeding into a PC soundcard.
A screenshot of the FLDIGI settings used is in the folder containing this program; 'AFSKRTTY2_DL-Fldigi_Settings.jpg'
Serial monitor baud rate is set at 9600
*******************************************************************************************************/
#include <AFSKRTTY2.h> //AFSK RTTY library for microcontrollers without the tone() function
//Choose whichever test pattern takes your fancy
//uint8_t testBuffer[] = "0123456789* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *";
//uint8_t testBuffer[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
uint8_t testBuffer[] = "$$$$MyFlight1,2213,14:54:37,51.48230,-3.18136,15,6,3680,23,66,3,0*2935";
const uint16_t leadinmS = 1000; //number of ms for AFSK constant lead in tone
const uint16_t leadoutmS = 0; //number of ms for AFSK constant lead out tone
const uint16_t LOWPERIODUS = 1000; //actual period in uS of to give a 200baud
const uint8_t LOWCYCLES = 5; //cycles of low frequency tone for 200baud
const uint16_t HIGHPERIODUS = 714; //actual high period in uS to give a 200baud
const uint8_t HIGHCYCLES = 7; //cycles of high frequency tone for 200baud
const int8_t ADJUSTUS = 0; //uS to subtract from tone generation loop to match frequency
const int8_t AUDIOOUT = 6; //pin used to output Audio tones
const int8_t CHECK = 8; //this pin is toggled inside the AFSKRTTY library, high for logic 1, low for logic 0, so it can be used to check the timing.
void loop()
{
uint8_t index;
uint8_t chartosend;
uint8_t len = sizeof(testBuffer) - 1; //must NOT send null at end of buffer
Serial.print(F("Sending AFSK RTTY "));
Serial.flush();
startAFSKRTTY(AUDIOOUT, CHECK, LOWCYCLES, LOWPERIODUS, HIGHCYCLES, HIGHPERIODUS, ADJUSTUS, leadinmS);
sendAFSKRTTY(13);
sendAFSKRTTY(10);
for (index = 0; index < len; index++)
{
chartosend = testBuffer[index];
sendAFSKRTTY(chartosend);
Serial.write(chartosend);
}
sendAFSKRTTY(13);
sendAFSKRTTY(10);
endAFSKRTTY(AUDIOOUT, CHECK, leadoutmS);
digitalWrite(CHECK, LOW);
Serial.println();
delay(1000);
}
void setup()
{
pinMode(CHECK, OUTPUT); //setup pin as output for indicator LED
Serial.begin(9600);
Serial.println();
Serial.println(F("70_AFSKRTTY_Upload_Test"));
Serial.println();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1,183 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 23/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
/*******************************************************************************************************
Program Operation - This is a test program for using the LoRa device to transmit upper side band FSK
RTTY. With the LoRa device in FSK direct mode, the frequency of the generated carrier is shifted up
or down at the correct baud rate depending on whether a logic 0 or 1 is being sent.
The desired shift in frequency is defined in the Settings.h file as 'FrequencyShift'. When the program
starts the actual frequency shift will be calculated according to the discrete frequency steps the
LoRa device can be set to. This example uses the library function for sending FSKRTTY that is fixed at
7 databits, 1 stop bit and no parity bit. If you want to vary these settings see the example;
'78_FSKRTTY_Transmitter_Test_Configurable.ino'
Before the actual data transmission starts you can send a series of marker pips which are short bursts
of up shifted carrier which will be heard as beeps in a correctly tuned receiver. These pips can aid
in setting the receiver decode frequemcy to match the transmission. on some LoRa devices, such as the SX127x
series there can be considerable temperature induced frequency drift. This drift can be caused by outside
temperature changes or the RF device self heating when transmit is turned on. The duration of the pips,
the gaps between them and the period of leadin carrier before the data starts can all be set. To send no
pips just set the number to 0.
Serial monitor baud rate is set at 9600
*******************************************************************************************************/
#define Program_Version "V1.1"
#include <SPI.h> //the lora device is SPI based
#include <SX127XLT.h> //include the appropriate SX12XX library
#include "Settings.h" //include the setiings file, frequencies, LoRa settings etc
SX127XLT LT; //create a library class instance called LT
//Choose whichever test pattern takes your fancy
//uint8_t testBuffer[] = "0123456789* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *"; //This string is sent as AFSK RTTY, 7 bit, 2 Stop bit, no parity, 300 baud.
//uint8_t testBuffer[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789";
//uint8_t testBuffer[] = "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
uint8_t testBuffer[] = "$$$$MyFlight1,2213,14:54:37,51.48230,-3.18136,15,6,3680,23,66,3,0*2935";
uint8_t freqShiftRegs[3]; //to hold returned registers that set frequency
void loop()
{
uint8_t index;
printRegisterSetup(FrequencyShift);
Serial.println();
LT.setupDirect(Frequency, Offset);
LT.startFSKRTTY(FrequencyShift, NumberofPips, PipPeriodmS, PipDelaymS, LeadinmS);
Serial.print(F("Start RTTY micros() = "));
Serial.println(micros());
Serial.print(F("Seconds to overflow "));
Serial.println(((0xFFFFFFFF - micros()) / 1E6),0);
LT.transmitFSKRTTY(13, BaudPerioduS, LED1); //send carriage return
LT.transmitFSKRTTY(10, BaudPerioduS, LED1); //send line feed
for (index = 0; index < (sizeof(testBuffer)-1); index++)
{
LT.transmitFSKRTTY(testBuffer[index], BaudPerioduS, LED1);
Serial.write(testBuffer[index]);
}
LT.transmitFSKRTTY(13, BaudPerioduS, LED1); //send carriage return
LT.transmitFSKRTTY(10, BaudPerioduS, LED1); //send line feed
Serial.println();
Serial.print(F("END RTTY micros() = "));
Serial.println(micros());
digitalWrite(LED1, LOW);
Serial.println();
Serial.println();
LT.setMode(MODE_STDBY_RC);
delay(2000);
}
void printRegisterSetup(uint32_t shift)
{
uint32_t nonShiftedFreq, ShiftedFreq;
uint32_t freqShift;
float exactfreqShift;
LT.setRfFrequency(Frequency, Offset); //ensure base frequecy is set
LT.getRfFrequencyRegisters(freqShiftRegs); //fill buffer with frequency setting registers values
nonShiftedFreq = ( (uint32_t) freqShiftRegs[0] << 16 ) + ( (uint32_t) freqShiftRegs[1] << 8 ) + freqShiftRegs[2];
Serial.print(F("NoShift Registers 0x"));
Serial.println(nonShiftedFreq, HEX);
LT.setRfFrequency((Frequency + shift), Offset); //set shifted frequecy
LT.getRfFrequencyRegisters(freqShiftRegs); //fill buffer with frequency setting registers values
ShiftedFreq = ( (uint32_t) freqShiftRegs[0] << 16 ) + ( (uint32_t) freqShiftRegs[1] << 8 ) + freqShiftRegs[2];
Serial.print(F("Shifted Registers 0x"));
Serial.println(ShiftedFreq, HEX);
freqShift = ShiftedFreq - nonShiftedFreq;
exactfreqShift = freqShift * FREQ_STEP;
Serial.print(F("FSKRTTY register shift "));
Serial.println(freqShift,HEX);
Serial.print(F("FSKRTTY frequency shift "));
Serial.print(exactfreqShift, 8);
Serial.println(F("hZ"));
LT.setRfFrequency(Frequency, Offset); //ensure base frequecy is set
}
void printRegisterBuffer()
{
Serial.print(freqShiftRegs[0],HEX);
Serial.print(F(" "));
Serial.print(freqShiftRegs[1],HEX);
Serial.print(F(" "));
Serial.print(freqShiftRegs[2],HEX);
Serial.println();
}
void led_Flash(uint16_t flashes, uint16_t delaymS)
{
uint16_t index;
for (index = 1; index <= flashes; index++)
{
digitalWrite(LED1, HIGH);
delay(delaymS);
digitalWrite(LED1, LOW);
delay(delaymS);
}
}
void setup()
{
pinMode(LED1, OUTPUT); //setup pin as output for indicator LED
led_Flash(2, 125); //two quick LED flashes to indicate program start
Serial.begin(9600);
Serial.println();
Serial.print(F(__TIME__));
Serial.print(F(" "));
Serial.println(F(__DATE__));
Serial.println(F(Program_Version));
Serial.println();
Serial.println(F("71_FSKRTTY_Transmitter_Test"));
SPI.begin();
//SPI beginTranscation is normally part of library routines, but if it is disabled in library
//a single instance is needed here, so uncomment the program line below
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
//setup hardware pins used by device, then check if device is found
if (LT.begin(NSS, NRESET, DIO0, LORA_DEVICE))
{
Serial.println(F("LoRa Device found"));
led_Flash(2, 125); //two further quick LED flashes to indicate device found
delay(1000);
}
else
{
Serial.println(F("No device responding"));
while (1)
{
led_Flash(50, 50); //long fast speed LED flash indicates device error
}
}
LT.setupDirect(Frequency, Offset);
Serial.print(F("Transmitter ready"));
Serial.println();
}

View File

@@ -0,0 +1,45 @@
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 23/12/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup. Some pins such as DIO1,
//DIO2 are not used by this particular sketch so they are set to -1 and not connected.
#define NSS 10 //select pin on LoRa device
#define NRESET 9 //reset pin on LoRa device
#define LED1 4 //on board LED, high for on
#define DIO0 3 //DIO0 pin on LoRa device, used for RX and TX done
#define LORA_DEVICE DEVICE_SX1278 //we need to define the device we are using
//******* Setup Direct Modem Parameters Here ! ***************
const uint32_t Frequency = 434000000; //frequency of transmissions in hertz
const uint32_t Offset = 0; //offset frequency for calibration purposes
const uint16_t deviation = 10000; //deviation, total frequency shift low to high
const float adjustfreq = 0.9; //adjustment to tone frequency
const int8_t TXpower = 10; //LoRa transmit power in dBm
//******* Setup FSKRTTY Settings here ! ***************
uint32_t FrequencyShift = 500; //hertz frequency shift, approx, sent at nearest 61.03515625hz step
uint8_t NumberofPips = 2; //number of marker pips to send
uint16_t PipDelaymS = 500; //mS between pips, carrier off
uint16_t PipPeriodmS = 100; //mS length of pip
uint16_t BaudPerioduS = 10000; //uS period for baud, 10000uS for 100baud
uint16_t LeadinmS = 2000; //ms of leadin, shifted carrier
uint8_t DataBits = 7; //number of databits, normally 7 or 8
uint8_t StopBits = 2; //number of stopbits, normally 1 or 2
uint8_t Parity = ParityNone; //parity on data bits, ParityNone, ParityOdd, ParityEven, ParityZero, ParityOne