├── Parts └── HAB2.xls ├── Pictures ├── HAB2 PCB.jpg ├── IMG_1916.JPG ├── IMG_1920.JPG ├── IMG_1922.JPG ├── IMG_1924.JPG ├── IMG_1926.JPG ├── IMG_1928.JPG ├── IMG_1930.JPG ├── IMG_1932.JPG ├── IMG_1935.JPG ├── IMG_1940.JPG ├── IMG_1943.JPG ├── IMG_1948.JPG ├── IMG_1951.JPG ├── IMG_1953.JPG ├── Inverted Pips.jpg ├── Normal Pips.jpg ├── Tracker_HAB2.jpg ├── Breakout and TC74.JPG ├── Tracker HAB2 Parts.jpg ├── Breakout and BMP280.JPG └── GPS Breakout 200917.jpg ├── Board ├── GPS Breakout 200917 PCB.pdf └── HAB2 Tracker RFM9x PCB 090218.pdf ├── Build ├── Versatile GPS Breakout board.pdf └── HAB2 Minimum Parts Tracker Build.pdf ├── Programs ├── Using the Tracker Programs.doc ├── Configuring the Tracker HAB Program.doc ├── README.md ├── I2C_Scanner │ ├── I2C_Scanner.ino │ └── I2C_Scanner.h ├── TC74_Temperature_Sensor_Test │ └── TC74_Temperature_Sensor_Test.ino ├── HAB2_UBLOX_EchoGPS_I2C │ └── HAB2_UBLOX_EchoGPS_I2C.ino ├── HAB2_UBLOX_EchoGPS_Serial │ └── HAB2_UBLOX_EchoGPS_Serial.ino ├── LoRa_Module_Test │ └── LoRa_Module_Test.ino ├── Tracker_GPSBeacon_Beta_101017 │ ├── Tracker_GPSBeacon_Settings.h │ └── Tracker_GPSBeacon_Beta_101017.ino ├── Tracker_HAB2_FSKRTTYONLY_101017 │ ├── Tracker_HAB2_FSKRTTYONLY_Settings.h │ └── Tracker_HAB2_FSKRTTYONLY_101017.ino ├── Tracker_HAB2_Bare_Bones_200518 │ ├── Tracker_HAB2_Settings.h │ └── Tracker_HAB2_Bare_Bones_200518.ino └── Tracker_HAB2_101017 │ ├── Tracker_HAB2_Settings.h │ └── Tracker_HAB2_101017.ino ├── Schematic ├── GPS Breakout 200917 Schematic.pdf ├── HAB2 Tracker RFM9x 090218 Schematic.pdf └── HAB2 Tracker DRF1278F 070618 Schematic.pdf └── README.md /Parts/HAB2.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Parts/HAB2.xls -------------------------------------------------------------------------------- /Pictures/HAB2 PCB.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/HAB2 PCB.jpg -------------------------------------------------------------------------------- /Pictures/IMG_1916.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1916.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1920.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1920.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1922.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1922.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1924.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1924.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1926.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1926.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1928.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1928.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1930.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1930.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1932.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1932.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1935.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1935.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1940.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1940.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1943.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1943.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1948.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1948.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1951.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1951.JPG -------------------------------------------------------------------------------- /Pictures/IMG_1953.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/IMG_1953.JPG -------------------------------------------------------------------------------- /Pictures/Inverted Pips.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/Inverted Pips.jpg -------------------------------------------------------------------------------- /Pictures/Normal Pips.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/Normal Pips.jpg -------------------------------------------------------------------------------- /Pictures/Tracker_HAB2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/Tracker_HAB2.jpg -------------------------------------------------------------------------------- /Pictures/Breakout and TC74.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/Breakout and TC74.JPG -------------------------------------------------------------------------------- /Pictures/Tracker HAB2 Parts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/Tracker HAB2 Parts.jpg -------------------------------------------------------------------------------- /Board/GPS Breakout 200917 PCB.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Board/GPS Breakout 200917 PCB.pdf -------------------------------------------------------------------------------- /Pictures/Breakout and BMP280.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/Breakout and BMP280.JPG -------------------------------------------------------------------------------- /Pictures/GPS Breakout 200917.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Pictures/GPS Breakout 200917.jpg -------------------------------------------------------------------------------- /Build/Versatile GPS Breakout board.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Build/Versatile GPS Breakout board.pdf -------------------------------------------------------------------------------- /Board/HAB2 Tracker RFM9x PCB 090218.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Board/HAB2 Tracker RFM9x PCB 090218.pdf -------------------------------------------------------------------------------- /Programs/Using the Tracker Programs.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Programs/Using the Tracker Programs.doc -------------------------------------------------------------------------------- /Build/HAB2 Minimum Parts Tracker Build.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Build/HAB2 Minimum Parts Tracker Build.pdf -------------------------------------------------------------------------------- /Schematic/GPS Breakout 200917 Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Schematic/GPS Breakout 200917 Schematic.pdf -------------------------------------------------------------------------------- /Programs/Configuring the Tracker HAB Program.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Programs/Configuring the Tracker HAB Program.doc -------------------------------------------------------------------------------- /Schematic/HAB2 Tracker RFM9x 090218 Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Schematic/HAB2 Tracker RFM9x 090218 Schematic.pdf -------------------------------------------------------------------------------- /Schematic/HAB2 Tracker DRF1278F 070618 Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StuartsProjects/HAB2/HEAD/Schematic/HAB2 Tracker DRF1278F 070618 Schematic.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The Programs for the HAB2 tracker need the Tracker Library installed see here; 2 | 3 | https://github.com/StuartsProjects/Tracker-Library 4 | 5 | The HAB2 tracker board is a minimal component count high altitude balloon tracker. 6 | 7 | The components required to build the tracker are described in the 'HAB2 Minimum Parts Tracker Build.pdf' file 8 | that will be found in the \Build folder. 9 | 10 | The programs have been tested against version 1.8.5 of the Arduino IDE. Note that this 11 | version of the IDE has the -permissive attribute set for the compiler, this allows the 12 | complier to tolerate some functions that previous versions (that did not have the -permissive 13 | attribute set as default) could not. As many as the complier warnings as possible have been 14 | removed, but these warnings should not prevent the programs compliing on version 1.8.5 of the IDE. 15 | 16 | There is a complier warning against the Flash-5 Library, but it is only a warning and not an error. 17 | 18 | The programs may not compile on old versions of the complier due to space issues or other changes 19 | that may have occured in the Arduino environment over time, it is not practical to test the 20 | programs against each particular version of the Arduino IDE. If you have problems, you will need 21 | to upgrade your Arduino IDE to a modern version. 22 | 23 | The user of these programs is expected to have had a reasonable level of experience in using the 24 | Arduino environment. Using the programs does require the user to make configuration changes so 25 | they will need to be able to cope with complier errors due to issues that they may create. 26 | 27 | Stuart Robinson 28 | 29 | 30 | -------------------------------------------------------------------------------- /Programs/README.md: -------------------------------------------------------------------------------- 1 | This folder contains the current version of the Tracker HAB2 programs. 2 | 3 | The programs requre the installation of the current Tracker Library files see here; 4 | 5 | https://github.com/StuartsProjects/Tracker-Library 6 | 7 | The programs in here are; 8 | 9 | Tracker_HAB2_xxxxxx - The HAB tracker transmitter, supports two way LoRa control and tracking 10 | 11 | FSKRTTY_HAB2_FSKRTTYONLY_xxxxxx - A FSK RTTY only version of the HAB tracker 12 | 13 | HAB2_UBLOX_EchoGPS_I2C - A test program for the UBLOX GPS in I2C mode, checks that Navigation model 6 can be set 14 | 15 | HAB2_UBLOX_EchoGPS_Serial - A test program for the UBLOX GPS in serial mode, checks that Navigation model 6 can be set 16 | 17 | I2C_Scanner - a basic I2C scanner, reports any I2C devices found 18 | 19 | Various third party Libraries may need to be installed, if not already present in your installation; 20 | 21 | Flash-5 Library - https://github.com/mikalhart/Flash/releases 22 | LowPower - https://github.com/rocketscream/Low-Power 23 | TinyGPS++ - http://arduiniana.org/libraries/tinygpsplus/ 24 | NeoSWSerial - https://github.com/SlashDevin/NeoSWSerial 25 | 26 | There is an issue with the Flash-5 library, changes to the Arduino IDE since the Library was published in 2014 27 | cause a compile error which is reported as ‘prog_char’ does not name a type. The solution to this is to edit the 28 | Flash.h file in the Flash-5 Library. Add the following lines in Flash.h, just after the #include 29 | i.e. around line 30 30 | 31 | #if ARDUINO >= 150 32 | typedef char prog_char __attribute__((__progmem__)); 33 | #endif 34 | 35 | If you have any problems with the programs do check that you are using the latest revision of the programs, the date 36 | is included as part of the program name. -------------------------------------------------------------------------------- /Programs/I2C_Scanner/I2C_Scanner.ino: -------------------------------------------------------------------------------- 1 | #define programname "I2C_Scanner" 2 | #define dateproduced "2/10/2017" 3 | #define aurthorname "Stuart Robinson" 4 | 5 | /* 6 | ******************************************************************************************************************************** 7 | 8 | Easy Build Tracker Programs for Arduino 9 | 10 | Copyright of the author Stuart Robinson - 2/10/2017 11 | 12 | These programs may be used free of charge for personal, recreational and educational purposes only. 13 | 14 | This program, or parts of it, may not be used for or in connection with any commercial purpose without the explicit permission 15 | of the author Stuart Robinson. 16 | 17 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 18 | free from errors. 19 | 20 | This program scans each address on the I2C bus and reports if a device was found, examples. 21 | 22 | UBLOX GPS 0x42 23 | TC74 Temperature Sensor 0x4c 24 | MB85RC16PNF FRAM 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57 25 | BME280 Sensor 0x76 26 | 27 | ******************************************************************************************************************************** 28 | */ 29 | 30 | 31 | #include 32 | #include 33 | #include "I2C_Scanner.h" 34 | #include "HAB2_Board_Definitions.h" 35 | 36 | unsigned int scancount; 37 | 38 | void loop() 39 | { 40 | scancount++; 41 | Serial.println(); 42 | Serial.print(scancount); 43 | Serial.print(" "); 44 | run_I2CScan(); 45 | delay(1000); 46 | } 47 | 48 | 49 | 50 | void setup() 51 | { 52 | Serial.begin(38400); //setup Serial console ouput 53 | Serial.println(F(programname)); 54 | Serial.println(F(dateproduced)); 55 | Serial.println(F(aurthorname)); 56 | Serial.println(); 57 | Serial.flush(); 58 | pinMode(GPSPOWER, OUTPUT); //in case Ublox GPS breakout is fitted 59 | digitalWrite(GPSPOWER, LOW); 60 | Wire.begin(); 61 | } 62 | 63 | 64 | -------------------------------------------------------------------------------- /Programs/TC74_Temperature_Sensor_Test/TC74_Temperature_Sensor_Test.ino: -------------------------------------------------------------------------------- 1 | //TC74_Test.ino 2 | /* 3 | ******************************************************************************************************************************** 4 | 5 | Easy Build Tracker Programs for Arduino 6 | 7 | Copyright of the author Stuart Robinson - 22/11/2017 8 | 9 | 10 | 11 | These programs may be used free of charge for personal, recreational and educational purposes only. 12 | 13 | This program, or parts of it, may not be used for or in connection with any commercial purpose without the explicit permission 14 | of the author Stuart Robinson. 15 | 16 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 17 | free from errors. 18 | 19 | This program reads the temperature from a TC74 sensor. 20 | 21 | ******************************************************************************************************************************** 22 | */ 23 | 24 | 25 | 26 | #include 27 | #include //https://github.com/Mario-H/TC74_I2C/blob/master/LICENSE.md 28 | 29 | #include "HAB2_Board_Definitions.h" 30 | 31 | 32 | 33 | TC74_I2C TC74(0x4c); //init with TC74 address, can be 0x48 to 0x4F depending on specific type 34 | 35 | int temperature = 0; 36 | 37 | #define TC74powersave 0 //set to 1 for TC74 powersave mode 38 | 39 | 40 | 41 | void loop() { 42 | 43 | if (TC74powersave) 44 | { 45 | TC74.NoPowersave(); //turn off powesave mode 46 | Serial.println("TC74 powersave off"); 47 | } 48 | 49 | temperature = TC74.ReadTemp(); 50 | 51 | Serial.print ("Temperature = "); 52 | if (temperature != 128) 53 | { 54 | Serial.print(temperature); 55 | Serial.println("C"); 56 | } 57 | else 58 | { 59 | Serial.println(" TC74 Error"); //value of 128 degrees is an error 60 | } 61 | 62 | if (TC74powersave) 63 | { 64 | TC74.Powersave(); //put TC74 in low current mode, approx 5uA 65 | Serial.println("TC74 powersave on"); 66 | } 67 | 68 | delay(3000); 69 | } 70 | 71 | 72 | 73 | void setup() { 74 | Serial.begin(38400); 75 | Serial.println("Starting TC74 Temperature Sensor Test"); 76 | Serial.println(); 77 | pinMode(GPSPOWER, OUTPUT); //in case power switching components for GPS breakout are fitted 78 | digitalWrite(GPSPOWER, LOW); 79 | 80 | TC74.Init(); 81 | } 82 | -------------------------------------------------------------------------------- /Programs/I2C_Scanner/I2C_Scanner.h: -------------------------------------------------------------------------------- 1 | // -------------------------------------- 2 | // i2c_scanner 3 | // 4 | // Version 1 5 | // This program (or code that looks like it) 6 | // can be found in many places. 7 | // For example on the Arduino.cc forum. 8 | // The original author is not know. 9 | // Version 2, Juni 2012, Using Arduino 1.0.1 10 | // Adapted to be as simple as possible by Arduino.cc user Krodal 11 | // Version 3, Feb 26 2013 12 | // V3 by louarnold 13 | // Version 4, March 3, 2013, Using Arduino 1.0.3 14 | // by Arduino.cc user Krodal. 15 | // Changes by louarnold removed. 16 | // Scanning addresses changed from 0...127 to 1...119, 17 | // according to the i2c scanner by Nick Gammon 18 | // http://www.gammon.com.au/forum/?id=10896 19 | // Version 5, March 28, 2013 20 | // As version 4, but address scans now to 127. 21 | // A sensor seems to use address 120. 22 | // Version 6, November 27, 2015. 23 | // Added waiting for the Leonardo serial communication. 24 | // 25 | // 26 | // This sketch tests the standard 7-bit addresses 27 | // Devices with higher bit address might not be seen properly. 28 | // 29 | 30 | 31 | 32 | 33 | void run_I2CScan() 34 | { 35 | byte error, address; 36 | int nDevices; 37 | 38 | Serial.println("Scanning for I2C Devices..."); 39 | 40 | nDevices = 0; 41 | for(address = 1; address < 127; address++ ) 42 | { 43 | // The i2c_scanner uses the return value of 44 | // the Write.endTransmisstion to see if 45 | // a device did acknowledge to the address. 46 | Wire.beginTransmission(address); 47 | error = Wire.endTransmission(); 48 | 49 | if (error == 0) 50 | { 51 | Serial.print("I2C device found at address 0x"); 52 | if (address<16) 53 | Serial.print("0"); 54 | Serial.println(address,HEX); 55 | 56 | nDevices++; 57 | } 58 | else if (error==4) 59 | { 60 | Serial.print("Unknown error at address 0x"); 61 | if (address<16) 62 | Serial.print("0"); 63 | Serial.println(address,HEX); 64 | } 65 | } 66 | if (nDevices == 0) 67 | Serial.println("No I2C devices found"); 68 | else 69 | Serial.println(); 70 | 71 | Wire.endTransmission(); 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /Programs/HAB2_UBLOX_EchoGPS_I2C/HAB2_UBLOX_EchoGPS_I2C.ino: -------------------------------------------------------------------------------- 1 | #define programname "HAB2_UBLOX_EchoGPS_I2C" 2 | #define programversion "V1.0" 3 | #define dateproduced "011017" 4 | #define aurthorname "Stuart Robinson" 5 | 6 | 7 | /* 8 | ******************************************************************************************************************************* 9 | Easy Build Tracker Programs for Arduino 10 | 11 | Copyright of the author Stuart Robinson - 1/10/17 12 | 13 | These programs may be used free of charge for personal, recreational and educational purposes only. 14 | 15 | This program, or parts of it, may not be used for or in connection with any commercial purpose without the explicit permission 16 | of the author Stuart Robinson. 17 | 18 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 19 | free from errors. 20 | 21 | This program reads the GPS via I2C. Stores the config settings for UBLOX GPS in Flash to save on RAM memory. 22 | 23 | To Do: 24 | 25 | ******************************************************************************************************************************* 26 | */ 27 | 28 | /* 29 | ******************************************************************************************************************************* 30 | The purpose of this program is to check that a UBLOX I2C GPS is working. Characters are read from the GPS 31 | and sent to the Serial monitor at 115200 baud. 32 | The program can is configured to send the commands for a UBLOX GPS that should configure it out of GLONASS mode. 33 | ******************************************************************************************************************************* 34 | */ 35 | 36 | 37 | #include 38 | #include 39 | 40 | #include "HAB2_Board_Definitions.h" //select board type here 41 | 42 | #include "Program_Definitions.h" //definitions for programs 43 | 44 | const unsigned long GPS_WaitAck_mS = 2000; //number of mS to wait for an ACK response from GPS 45 | const byte GPS_attempts = 3; //number of times the sending of GPS config will be attempted. 46 | const byte GPS_Reply_Size = 12; //size of GPS reply buffer 47 | boolean GPS_Config_Error; 48 | 49 | #define GPS_ALLOW_GPGSV //we want to see the GPGSV messages 50 | #include "UBLOX_I2CGPS.h" 51 | 52 | void loop() 53 | { 54 | byte i; 55 | 56 | Wire.beginTransmission(GPSI2CAddress); 57 | Wire.write(0xFF); 58 | 59 | while (1) 60 | { 61 | Wire.requestFrom(GPSI2CAddress, 1); 62 | i = Wire.read(); 63 | if (i != 0xFF) 64 | { 65 | Serial.write(i); 66 | } 67 | } 68 | } 69 | 70 | 71 | void led_Flash(unsigned int flashes, unsigned int delaymS) 72 | { 73 | unsigned int index; 74 | 75 | for (index = 1; index <= flashes; index++) 76 | { 77 | digitalWrite(LED1, HIGH); 78 | delay(delaymS); 79 | digitalWrite(LED1, LOW); 80 | delay(delaymS); 81 | } 82 | } 83 | 84 | 85 | void setup() 86 | { 87 | pinMode(GPSPOWER, OUTPUT); //setup pin for GPS Power Control 88 | digitalWrite(GPSPOWER, LOW); 89 | 90 | Serial.begin(115200); //connect at 115200 so we can read the GPS fast enough and also spit it out 91 | Serial.println(F(programname)); 92 | Serial.println(F(programversion)); 93 | Serial.println(F(dateproduced)); 94 | Serial.println(F(aurthorname)); 95 | 96 | pinMode(LED1, OUTPUT); 97 | led_Flash(2, 500); 98 | 99 | Wire.begin(); 100 | 101 | GPS_On(DoGPSPowerSwitch); //this will power the GPSon 102 | GPS_Setup(); 103 | 104 | if (!GPS_CheckNavigation()) //Check that UBLOX GPS is in Navigation model 6 105 | { 106 | Serial.println(); 107 | Serial.println(F("Warning GPS Error !")); 108 | Serial.println(); 109 | led_Flash(100, 25); 110 | } 111 | 112 | } 113 | 114 | 115 | -------------------------------------------------------------------------------- /Programs/HAB2_UBLOX_EchoGPS_Serial/HAB2_UBLOX_EchoGPS_Serial.ino: -------------------------------------------------------------------------------- 1 | #define programname "HAB2_UBLOX_EchoGPS_Serial" 2 | #define programversion "V1.0" 3 | #define dateproduced "011017" 4 | #define aurthorname "Stuart Robinson" 5 | 6 | 7 | /* 8 | ******************************************************************************************************************************* 9 | Easy Build Tracker Programs for Arduino 10 | 11 | Copyright of the author Stuart Robinson - 1/10/17 12 | 13 | These programs may be used free of charge for personal, recreational and educational purposes only. 14 | 15 | This program, or parts of it, may not be used for or in connection with any commercial purpose without the explicit permission 16 | of the author Stuart Robinson. 17 | 18 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 19 | free from errors. 20 | 21 | To Do: 22 | 23 | ******************************************************************************************************************************* 24 | */ 25 | 26 | /* 27 | ******************************************************************************************************************************* 28 | The purpose of this program is to check that a UBLOX Serial GPS is working. Characters are read from the GPS 29 | and sent to the Serial monitor at 115200 baud. 30 | The program can is configured to send the commands for a UBLOX GPS that should configure it out of GLONASS mode. 31 | ******************************************************************************************************************************* 32 | */ 33 | 34 | 35 | #include 36 | #include 37 | 38 | #include "HAB2_Board_Definitions.h" //select board type here 39 | 40 | 41 | #include "Program_Definitions.h" //definitions for programs 42 | const unsigned int GPS_Clear_DelaymS = 2000; //mS to wait after a GPS Clear command is sent 43 | const unsigned long GPS_WaitAck_mS = 2000; //number of mS to wait for an ACK response from GPS 44 | const byte GPS_attempts = 3; //number of times the sending of GPS config will be attempted. 45 | const byte GPS_Reply_Size = 12; //size of GPS reply buffer 46 | const unsigned int GPSBaud = 9600; //baud rate of GPS 47 | boolean GPS_Config_Error; 48 | 49 | #include //https://github.com/SlashDevin/NeoSWSerial 50 | NeoSWSerial GPSserial(GPSRX, GPSTX); //this library is more relaible at GPS init than software serial 51 | 52 | #define GPS_ALLOW_GPGSV //we want to see the GPGSV messages 53 | #include "UBLOX_SerialGPS2.h" 54 | 55 | 56 | void loop() 57 | { 58 | while (GPSserial.available() > 0) 59 | Serial.write(GPSserial.read()); 60 | } 61 | 62 | 63 | void led_Flash(unsigned int flashes, unsigned int delaymS) 64 | { 65 | unsigned int index; 66 | 67 | for (index = 1; index <= flashes; index++) 68 | { 69 | digitalWrite(LED1, HIGH); 70 | delay(delaymS); 71 | digitalWrite(LED1, LOW); 72 | delay(delaymS); 73 | } 74 | } 75 | 76 | 77 | void setup() 78 | { 79 | pinMode(GPSPOWER, OUTPUT); //setup pin for GPS Power Control 80 | digitalWrite(GPSPOWER, LOW); 81 | 82 | Serial.begin(115200); //connect at 115200 so we can read the GPS fast enough and also spit it out 83 | Serial.println(F(programname)); 84 | Serial.println(F(programversion)); 85 | Serial.println(F(dateproduced)); 86 | Serial.println(F(aurthorname)); 87 | 88 | pinMode(LED1, OUTPUT); //for Watchdog pulse input 89 | led_Flash(2, 500); 90 | 91 | pinMode(GPSPOWER, OUTPUT); //in case power switching components are fitted 92 | GPS_On(DoGPSPowerSwitch); //this will power the GPSon 93 | GPS_Setup(); 94 | 95 | if (!GPS_CheckNavigation()) //Check that UBLOX GPS is in Navigation model 6 96 | { 97 | Serial.println(); 98 | Serial.println(F("Warning GPS Error !")); 99 | Serial.println(); 100 | led_Flash(100, 25); 101 | } 102 | 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /Programs/LoRa_Module_Test/LoRa_Module_Test.ino: -------------------------------------------------------------------------------- 1 | #define programname "LoRa_Module_Test" 2 | #define programversion "V1.0" 3 | #define dateproduced "26/11/2017" 4 | #define aurthorname "Stuart Robinson" 5 | #include 6 | #include "Program_Definitions.h" //part of Tracker library 7 | #define LoRa_Device_in_MB1 //required if board is plug in modules 8 | 9 | /* 10 | ***************************************************************************************************************************** 11 | Tracker Test Programs 12 | 13 | Copyright of the author Stuart Robinson - 26/11/2017 14 | 15 | These programs may be used free of charge for personal, recreational and educational purposes only. 16 | 17 | This program, or parts of it, may not be used for or in connection with any commercial purpose without the explicit permission 18 | of the author Stuart Robinson. 19 | 20 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 21 | free from errors. 22 | ***************************************************************************************************************************** 23 | */ 24 | 25 | /* 26 | ******************************************************************************************************************************** 27 | Program operation 28 | 29 | This test program has been written to check that a connected LoRa module such as Dorji DRF127x or Hope RFM9x that it is funtional. 30 | The LoRa device should transmit an FM audio tones at the frequency specified that can be heard on a UHF handheld FM receiver. 31 | It might seem peverse to test a LoRa device by sending FM audio tones, but its the easiest way of checking that the LoRa device 32 | is actually transmitting. 33 | 34 | A program start (power on and reset) there will be a short sequence of 5 LED flashes, then the LED should be constant on for around 35 | 2.5 seconds. At this time the LoRa device should be sending an FM tone on the defined frequency. The register contents of the LoRa 36 | device will also be printed to the Arduino IDE serial monitor. A error detecting the LoRa device will result in a series of very 37 | fast LED flashes lasting around 5 seconds. The test sequence will repeat. 38 | 39 | Do not forget to fit an antenna to the LoRa device, you can destroy it if you use it without and antenna 40 | ******************************************************************************************************************************** 41 | */ 42 | 43 | /* 44 | ******************************************************************************************************************************** 45 | Connections 46 | 47 | The program uses the hardware SPI interface on the Arduino to connect to the LoRa device, so the SPI SCK, MOSI and MISO pins are 48 | assumed to be connected. The test program needs a minimum of one extra pin connected to act as chip select. Other pins 49 | may optionally be connected to the reset pin on the LoRa device and to DIO2 so that the LoRa device can transmit FM tones. 50 | You can explicitly define the required pins below by removing the two // characters in front of the #defines 51 | ******************************************************************************************************************************** 52 | */ 53 | 54 | //#define lora_NSS 10 //Arduino pin number for device select on LoRa device 55 | //#define lora_NReset 9 //Arduino pin number for reset pin on LoRa device, can be left not connected 56 | //#define lora_TonePin 7 //Arduino pin number connceted to DIO2 pin on LoRa device, used for FM audio tone generation 57 | //#define lora_DIO0 2 //Arduino pin number connceted to DIO0 pin on LoRa device, can be left not connected 58 | //#define LED1 8 //Arduino pin number for LED, when high LED should be on. 59 | 60 | /* 61 | *********************************************************************************************************************************************** 62 | As an alternative to explicitly defining the Arduino pins required, there are pre-defined board definition files for the Tracker boards 63 | included in the Tracker Library; 64 | 65 | https://github.com/StuartsProjects/Tracker-Library 66 | 67 | Select (include) the board definition file you require by removing the // characters before the appropriate include line in the list below 68 | *********************************************************************************************************************************************** 69 | */ 70 | 71 | #include "HAB2_Board_Definitions.h" 72 | 73 | #include 74 | 75 | const unsigned long Frequency = 434400000; //frequency of transmissions in hertz 76 | const int CalibrationOffset = 0; //you can use this to adjust the output, in hertz, steps are 61hz 77 | const byte Deviation = 0x52; //typical deviation for audio tones, approx 5khz 78 | 79 | const byte lora_RXBUFF_Size = 32; //needed for LoRa3 library 80 | const byte lora_TXBUFF_Size = 64; //needed for LoRa3 library 81 | byte keypress; //needed for LoRa3 library 82 | 83 | #include "LoRa4.h" //part of Tracker library 84 | 85 | #define Serial_Monitor_Baud 38400 //this is baud rate used for the Arduino IDE Serial Monitor 86 | 87 | void loop() 88 | { 89 | 90 | Serial.println(F("LED Flash")); 91 | Serial.println(); 92 | led_Flash(5,100); 93 | 94 | SPI.begin(); 95 | SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 96 | 97 | Serial.println(F("Checking LoRa Device")); 98 | Serial.println(); 99 | Serial.print(F("Registers after reset - ")); 100 | lora_ResetDev(); //ensure registers are in initial state 101 | lora_Print(); //initial print of registers 102 | 103 | Serial.println(); 104 | 105 | if (lora_CheckDevice() == true) 106 | { 107 | Serial.println(F("Device Present")); 108 | Serial.println(); 109 | Serial.print(F("Registers after setup - ")); 110 | lora_Setup(); //Do the initial LoRa Setup 111 | lora_Print(); 112 | lora_SetFreq(Frequency, CalibrationOffset); 113 | Serial.print(F("Transmit FM Tone")); 114 | digitalWrite(LED1, HIGH); 115 | lora_Tone(1000, 3500, 2); //Transmit an FM tone, 1000hz, 2500ms, 2dBm 116 | digitalWrite(LED1, LOW); 117 | Serial.println(F(" - Done")); 118 | Serial.println(); 119 | lora_Print(); 120 | } 121 | else 122 | { 123 | Serial.println(F("Device Not Found")); 124 | Serial.println(); 125 | lora_Print(); 126 | Serial.println(); 127 | led_Flash(100,25); 128 | } 129 | 130 | SPI.end(); 131 | Serial.println(); 132 | Serial.println(); 133 | delay(1500); 134 | } 135 | 136 | 137 | void led_Flash(unsigned int flashes, unsigned int delaymS) 138 | { 139 | //flash LED to show tracker is alive 140 | unsigned int index; 141 | 142 | for (index = 1; index <= flashes; index++) 143 | { 144 | digitalWrite(LED1, HIGH); 145 | delay(delaymS); 146 | digitalWrite(LED1, LOW); 147 | delay(delaymS); 148 | } 149 | } 150 | 151 | 152 | 153 | void setup() 154 | { 155 | pinMode(LED1, OUTPUT); //for PCB LED 156 | pinMode(13, OUTPUT); //for Pro Mini LED, Pin13 157 | pinMode(lora_NReset, OUTPUT); //LoRa Device reset line 158 | pinMode (lora_NSS, OUTPUT); //LoRa Device select line 159 | digitalWrite(lora_NSS, HIGH); 160 | digitalWrite(lora_NReset, HIGH); 161 | 162 | Serial.begin(Serial_Monitor_Baud); //setup Serial console ouput 163 | Serial.println(F(programname)); 164 | Serial.println(F(programversion)); 165 | Serial.println(F(dateproduced)); 166 | Serial.println(F(aurthorname)); 167 | Serial.println(); 168 | 169 | } 170 | -------------------------------------------------------------------------------- /Programs/Tracker_GPSBeacon_Beta_101017/Tracker_GPSBeacon_Settings.h: -------------------------------------------------------------------------------- 1 | //Tracker_GPSBeacon_Settings.h 2 | /* 3 | ****************************************************************************************************** 4 | 5 | Tracker Programs for Arduino 6 | 7 | Copyright of the author Stuart Robinson - 16/10/2017 8 | 9 | 10 | 11 | These programs may be used free of charge for personal, recreational and educational purposes only. 12 | 13 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 14 | the explicit permission of the author Stuart Robinson. 15 | 16 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the 17 | intended purpose and free from errors. 18 | 19 | To Do: 20 | 21 | Changes: 22 | 101017 Removed unused board definitions 23 | 24 | ****************************************************************************************************** 25 | */ 26 | 27 | //************************************************************************************************** 28 | // 1) Hardware related definitions and options - specify board type here 29 | //************************************************************************************************** 30 | 31 | #define CPU_VoltageRead 32 | //#define External_VoltageRead 33 | 34 | #define CPU_TemperatureRead 35 | //#define External_TemperatureRead 36 | const int Temperature_Adjust = 0; //to allow calibration of external temperature sensor 37 | 38 | #define Board_Definition "HAB2_Board_Definitions.h" //define the board to use here 39 | 40 | 41 | 42 | //************************************************************************************************** 43 | // 2) Program Options 44 | //************************************************************************************************** 45 | 46 | 47 | #define ConfigureDefaults //Configure settings from default program constants, save in memory and copy to RAM, need to do this once only 48 | //#define ClearAllMemory //Clears from start memory to end memory, normally 1kbyte, needs to be folloowed by ConfigureDefaults 49 | //#define ClearSavedData //zero the saved data, resets, sequence, Mahr 50 | //#define ConfigureFromMemory //Read settings from attached memory 51 | 52 | #define CheckTone //comment in to have a calibrate tone at startup, also indicates navigation model 6 set 53 | 54 | //#define DEBUG //if defined, prints additional debug information to terminal 55 | 56 | 57 | //************************************************************************************************** 58 | // 3) Frequency settings 59 | //************************************************************************************************** 60 | 61 | //Tracker mode 62 | const uint32_t TrackerMode_Frequency = 434400000; 63 | 64 | //Command mode 65 | const uint32_t CommandMode_Frequency = 434400000; 66 | 67 | //Bind mode - Change this with great care !!!!! 68 | const uint32_t BindMode_Frequency = 434100000; 69 | 70 | //this is the LoRa module frequency calibration offset in Hertz 71 | const int CalibrationOffset = 0; 72 | 73 | 74 | //************************************************************************************************** 75 | // 4) LoRa settings 76 | //************************************************************************************************** 77 | 78 | //Tracker mode 79 | #define TrackerMode_Bandwidth BW62500 80 | #define TrackerMode_SpreadingFactor SF8 81 | #define TrackerMode_CodeRate CR45 82 | #define TrackerMode_Power 10 83 | 84 | //Command mode 85 | #define CommandMode_Bandwidth BW62500 86 | #define CommandMode_SpreadingFactor SF8 87 | #define CommandMode_CodeRate CR45 88 | #define CommandMode_Power 10 89 | 90 | //Bind mode 91 | #define BindMode_Bandwidth BW500000 92 | #define BindMode_SpreadingFactor SF8 93 | #define BindMode_CodeRate CR45 94 | #define BindMode_Power 2 95 | 96 | #define SendBind //at startup tracker transmitter will send a bind packet 97 | //#define LORADEBUG //displays extra debug messages when using LoRa 98 | #define Accept_Commands //define this if you want to be able to remote control beacon 99 | 100 | 101 | const uint8_t Deviation = 0x52; //typical deviation for tones 102 | const uint8_t lora_RXBUFF_Size = 128; 103 | const uint8_t lora_TXBUFF_Size = 32; 104 | 105 | const uint16_t inter_Packet_delay = 500; //allows time for receiver to be ready to see a possible reply, in mS 106 | 107 | 108 | const uint8_t Cmd_WaitSecs = 5; //number of seconds to stay in waiting for command mode 109 | const uint8_t Command_Loops = 3; //if one command is received wait for this number of loops to keep control channel open 110 | 111 | //Key Definition 112 | const char key0 = 'L'; //Used to restrict access to some commands 113 | const char key1 = 'o'; 114 | const char key2 = 'R'; 115 | const char key3 = 'a'; 116 | 117 | //************************************************************************************************** 118 | // 5) GPS Options 119 | //************************************************************************************************** 120 | 121 | #define USE_SOFTSERIAL_GPS //need to include this if we are using softserial for GPS 122 | #define GPS_Library "UBLOX_SerialGPS2.h" //define the GPS library routines to use here, this is a version2 of the serial program, does not use Flash5 library 123 | //#define GPS_Library "UBLOX_I2CGPS.h" //define for using a UBLOX GPS with I2C interface 124 | 125 | //#define DEBUGNoGPS //test mode, does not use GPS 126 | //#define Use_Test_Location //to use test location for transmissions include this define 127 | 128 | //#define GPS_ALLOW_GPGSV //define this so that GPGSV senetences are not turned off 129 | 130 | #define GPSBaud 9600 //GPS Baud rate 131 | #define WhenNoGPSFix LeaveOn //What to do with GPS power when there is no fix at ends of wait period (LeaveOn or LeaveOff) 132 | #define WaitGPSFixSeconds 30 //in flight mode time to wait for a new GPS fix 133 | //#define Remove_GPS_Power //Some tracker boards can remove the power from the GPS, if so define this to use it 134 | #define Use_GPS_SoftwareBackup //some GPSs do not support this mode, Ubloxes do, used for GPS Hotfix option 135 | 136 | const uint32_t fixisoldmS = 10000; //if location has not updated in this number of mS, assume GPS has lost fix 137 | const uint32_t GPS_WaitAck_mS = 2000; //number of mS to wait for an ACK response from GPS 138 | const uint8_t GPS_attempts = 3; //number of times the sending of GPS config will be attempted. 139 | const uint8_t GPS_Reply_Size = 12; //size of GPS reply buffer 140 | const unsigned int GPS_Clear_DelaymS = 2000; //mS to wait after a GPS Clear command is sent 141 | 142 | //Centre of Cardiff Castle keep 143 | #define TestLatitude 51.48230 144 | #define TestLongitude -3.18136 145 | #define TestAltitude 48 146 | 147 | 148 | /* 149 | Passive GPS station: Swanbridge - C1ST1667 150 | https://www.ordnancesurvey.co.uk/gps/legacy-control-information/C1ST1667 151 | N 51 23'59.105955", W 3 11',47.413031 152 | 51.399751654166664, -3.196503619722222 153 | 154 | #define TestLatitude 51.399752 155 | #define TestLongitude -3.196504 156 | #define TestAltitude 0 157 | */ 158 | 159 | //************************************************************************************************** 160 | // 6) Which Memory to use for storage 161 | //************************************************************************************************** 162 | 163 | //#define Memory_Library "EEPROM_Memory.h" //define this file if the internal EEPROM is in use 164 | #define Memory_Library "I2CFRAM_MB85RC16PNF.h" //define this file if the I2C FRAM is in use 165 | 166 | 167 | //**************************************************************************************************** 168 | // 11) Program Default Option settings 169 | // This section determines which options are on or off by default, this is the Default_config1 byte 170 | // Take care here.......... 171 | //************************************************************************************************** 172 | 173 | #define OptionOff 0 174 | #define OptionOn 1 175 | 176 | const char option_TXEnable = OptionOn; 177 | const char option_AddressStrip = OptionOff; 178 | const char option_GPSHotFix = OptionOff; 179 | 180 | #define option_TXEnable_SUM (option_TXEnable*2) 181 | #define option_AddressStrip_SUM (option_AddressStrip*64) 182 | #define option_GPSHotFix_SUM (option_GPSHotFix*128) 183 | 184 | 185 | const uint8_t Default_config1 = (option_TXEnable_SUM + option_AddressStrip_SUM + option_GPSHotFix_SUM); 186 | //const uint16_t Default_config1 = 2; //Phew, the default config can always be set manually ............. 187 | 188 | 189 | //************************************************************************************************** 190 | // 13) Unique calibration settings for each Board 191 | // These settings are not part of a bind operation 192 | //************************************************************************************************** 193 | 194 | const float kelvin_offset = 325; //not used in this application but causes a complie error if missing 195 | const float temp_conversion_slope = 1.0; //not used in this application but causes a complie error if missing 196 | uint32_t adc_constant = 1200000; //if processor self read of its supply voltage reports high reduce this number 197 | 198 | //************************************************************************************************** 199 | // 15) Beacon settings 200 | //************************************************************************************************** 201 | 202 | 203 | const uint16_t Loop_Sleepsecs = 10; //sleep time in seconds between transmissions 204 | const boolean promiscuous_Mode = true; //if set to True remote control packets from any node accepted 205 | 206 | #define RemoteControlNode 'G' //normally used by tracker transmitter in promiscuous_Mode 207 | #define ControlledNode '1' //normally used by tracker transmitter in promiscuous_Mode 208 | #define ThisNode ControlledNode 209 | 210 | -------------------------------------------------------------------------------- /Programs/Tracker_HAB2_FSKRTTYONLY_101017/Tracker_HAB2_FSKRTTYONLY_Settings.h: -------------------------------------------------------------------------------- 1 | //Tracker_HAB2_FSKRTTYONLY_Settings.h 2 | /* 3 | ****************************************************************************************************** 4 | 5 | Tracker Programs for Arduino 6 | 7 | Copyright of the author Stuart Robinson - 10/10/2017 8 | 9 | 10 | 11 | These programs may be used free of charge for personal, recreational and educational purposes only. 12 | 13 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 14 | the explicit permission of the author Stuart Robinson. 15 | 16 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the 17 | intended purpose and free from errors. 18 | 19 | To Do: 20 | 21 | Changes: 22 | 101017 Removed unused board definitions 23 | 24 | ****************************************************************************************************** 25 | */ 26 | 27 | //************************************************************************************************** 28 | // 1) Hardware related definitions and options - specify board type here 29 | //************************************************************************************************** 30 | 31 | #define CPU_VoltageRead 32 | //#define External_VoltageRead 33 | 34 | #define CPU_TemperatureRead 35 | //#define External_TemperatureRead 36 | const int Temperature_Adjust = 0; //to allow calibration of external temperature sensor 37 | 38 | #define Board_Definition "HAB2_Board_Definitions.h" //define the board to use here 39 | 40 | 41 | //************************************************************************************************** 42 | // 2) Program Options 43 | //************************************************************************************************** 44 | 45 | 46 | #define ConfigureDefaults //Configure settings from default program constants, save in memory and copy to RAM, need to do this once only 47 | //#define ClearAllMemory //Clears from start memory to end memory, normally 1kbyte, needs to be folloowed by ConfigureDefaults 48 | //#define ClearSavedData //zero the saved data, resets, sequence, Mahr 49 | //#define ConfigureFromMemory //Read settings from attached memory 50 | 51 | const byte Output_len_max = 125; //maximum length for built payload 52 | #define CheckTone //comment in to have a calibrate tone at startup, also indicates navigation model 6 set 53 | 54 | //#define DEBUG /if defined, prints additional debug information to terminal 55 | 56 | 57 | 58 | //************************************************************************************************** 59 | // 3) Frequency settings 60 | //************************************************************************************************** 61 | 62 | //Tracker mode 63 | const unsigned long TrackerMode_Frequency = 434400000; 64 | 65 | //this is the LoRa module frequency calibration offset in Hertz 66 | const int CalibrationOffset = 0; 67 | 68 | 69 | //************************************************************************************************** 70 | // 4) LoRa settings 71 | //************************************************************************************************** 72 | 73 | //Tracker mode 74 | #define TrackerMode_Power 10 75 | 76 | //#define LORADEBUG //displays extra debug messages when using LoRa 77 | 78 | const byte Deviation = 0x52; //typical deviation for tones 79 | const byte lora_RXBUFF_Size = 1; //RX buffer not in use, so set to 1 80 | const byte lora_TXBUFF_Size = 128; 81 | 82 | 83 | //************************************************************************************************** 84 | // 5) GPS Options 85 | //************************************************************************************************** 86 | 87 | #define USE_SOFTSERIAL_GPS //need to include this if we are using softserial for GPS 88 | #define GPS_Library "UBLOX_SerialGPS.h" //define the GPS library routines to use here 89 | //#define GPS_Library "UBLOX_I2CGPS.h" 90 | 91 | //#define DEBUGNoGPS //test mode, does not use GPS 92 | 93 | #define GPSBaud 9600 //GPS Baud rate 94 | #define WhenNoGPSFix LeaveOn //What to do with GPS power when there is no fix at ends of wait period (LeaveOn or LeaveOff) 95 | #define WaitGPSFixSeconds 30 //in flight mode time to wait for a new GPS fix 96 | //#define Check_GPS_Navigation_Model_OK //every time the GPS is checked for a fix we can check for correct navigation mode on UBLOX 97 | 98 | const unsigned long fixisoldmS = 10000; //if location has not updated in this number of mS, assume GPS has lost fix 99 | const unsigned long GPS_WaitAck_mS = 2000; //number of mS to wait for an ACK response from GPS 100 | const unsigned int GPSFixs = 100; //number of GPS fixes between setting system clock from GPS 101 | const byte GPS_attempts = 3; //number of times the sending of GPS config will be attempted. 102 | const byte GPS_Reply_Size = 12; //size of GPS reply buffer 103 | 104 | 105 | //#define Use_Test_Location //to use test location for transmissions include this define 106 | 107 | //Centre of Cardiff Castle keep 108 | #define TestLatitude 51.48230 109 | #define TestLongitude -3.18136 110 | #define TestAltitude 48 111 | 112 | 113 | /* 114 | Passive GPS station: Swanbridge - C1ST1667 115 | https://www.ordnancesurvey.co.uk/gps/legacy-control-information/C1ST1667 116 | N 51 23'59.105955", W 3 11',47.413031 117 | 51.399751654166664, -3.196503619722222 118 | 119 | #define TestLatitude 51.399752 120 | #define TestLongitude -3.196504 121 | #define TestAltitude 0 122 | */ 123 | 124 | //************************************************************************************************** 125 | // 6) Which Memory to use for storage 126 | //************************************************************************************************** 127 | 128 | #define Memory_Library "EEPROM_Memory.h" 129 | 130 | 131 | //************************************************************************************************** 132 | // 8) FSK RTTY Settings 133 | //************************************************************************************************** 134 | 135 | #define ConstantTX //define thid to leave TX running permanently 136 | const unsigned int FSKRTTYbaudDelay = 9845; //delay for baud rate for FSK RTTY, 19800 for 50baud, 9845 for 100baud, 4865 for 200baud 137 | const byte FSKRTTYRegshift = 6; //number of frequency steps to use for shift 138 | const byte FSKRTTYpips = 5; //number of FSK lead in pips 139 | const int FSKRTTYleadin = 500; //number of ms for FSK constant lead in tone 140 | const byte sync_chars = 3; //number of extra $ sync characters to send 141 | 142 | 143 | //**************************************************************************************************** 144 | // 11) Program Default Option settings 145 | // This section determins which options are on or off by default, this is the default_config1 byte 146 | // Take care here.......... 147 | //************************************************************************************************** 148 | 149 | #define OptionOff 0 150 | #define OptionOn 1 151 | 152 | const char option_SearchEnable = OptionOn; 153 | const char option_TXEnable = OptionOn; 154 | const char option_FSKRTTYEnable = OptionOn; 155 | const char option_CheckFence = OptionOff; 156 | const char option_ShortPayloadEnable = OptionOff; 157 | const char option_RepeatEnable = OptionOff; 158 | const char option_AddressStrip = OptionOn; 159 | const char option_GPSHotFix = OptionOff; 160 | 161 | #define option_SearchEnable_SUM (option_SearchEnable*1) 162 | #define option_TXEnable_SUM (option_TXEnable*2) 163 | #define option_FSKRTTYEnable_SUM (option_FSKRTTYEnable*4) 164 | #define option_CheckFence_SUM (option_CheckFence*8) 165 | #define option_ShortPayloadEnable_SUM (option_ShortPayloadEnable*16) 166 | #define option_RepeatEnable_SUM (option_RepeatEnable*32) 167 | #define option_AddressStrip_SUM (option_AddressStrip*64) 168 | #define option_GPSHotFix_SUM (option_GPSHotFix*128) 169 | 170 | //See Program_Definitions.h in the Tracker library for details, the above options translate into Default_config1 byte of 1 + 2 + 4 + 64 = 71 171 | 172 | const unsigned int Default_config1 = (option_SearchEnable_SUM + option_TXEnable_SUM + option_FSKRTTYEnable_SUM + option_CheckFence_SUM + option_ShortPayloadEnable_SUM + option_RepeatEnable_SUM + option_AddressStrip_SUM + option_GPSHotFix_SUM); 173 | const unsigned int Default_config2 = 0; 174 | const unsigned int Default_config3 = 0; 175 | const unsigned int Default_config4 = 0; 176 | //const unsigned int const_Default_config = 71; //Phew, the default config can always be set manually ............. 177 | 178 | 179 | //************************************************************************************************** 180 | // 13) Unique calibration settings for each Board 181 | // These settings are not part of a bind operation 182 | //************************************************************************************************** 183 | 184 | const float kelvin_offset = 326; //if processor self read of temperature reports high, increase this number 185 | const float temp_conversion_slope = 1.058 ; //defines the rate of change between low and high temperatures 186 | const unsigned long adc_constant = 1146679; //if processor self read of its supply voltage reports high reduce this number 187 | 188 | 189 | //************************************************************************************************** 190 | // 14) HAB2 settings 191 | //************************************************************************************************** 192 | 193 | char Flight_ID[15] = "LoRaHAB2"; 194 | 195 | const float west_fence = -4; 196 | const float east_fence = 45; 197 | 198 | const unsigned int Loop_Sleepsecs = 25; //sleep time in seconds after each TX loop 199 | const unsigned int outside_fence_Sleep_seconds = 600; //approx 10 minutes 200 | 201 | #define ControlledNode '1' //normally used by tracker transmitter in promiscuous_Mode 202 | #define ThisNode ControlledNode 203 | 204 | const byte PayloadArraySize = 20; //Maximum number of fields when parsing long HAB payload 205 | 206 | 207 | 208 | -------------------------------------------------------------------------------- /Programs/Tracker_HAB2_Bare_Bones_200518/Tracker_HAB2_Settings.h: -------------------------------------------------------------------------------- 1 | //Tracker_HAB2_Settings.h 2 | /* 3 | ****************************************************************************************************** 4 | 5 | Tracker Programs for Arduino 6 | 7 | Copyright of the author Stuart Robinson - 20/05/2018 8 | 9 | 10 | 11 | These programs may be used free of charge for personal, recreational and educational purposes only. 12 | 13 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 14 | the explicit permission of the author Stuart Robinson. 15 | 16 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the 17 | intended purpose and free from errors. 18 | 19 | To Do: 20 | 21 | Changes: 22 | 23 | 24 | ****************************************************************************************************** 25 | */ 26 | 27 | //************************************************************************************************** 28 | // 1) Hardware related definitions and options - specify board type here 29 | //************************************************************************************************** 30 | 31 | #define External_VoltageRead 32 | 33 | #define External_TemperatureRead //assumes a TC74 is in use 34 | 35 | #define TC74_Address 0x4c //init with TC74 address, can be 0x48 to 0x4F depending on specific type 36 | 37 | const int Temperature_Adjust = 0; //to allow adjustment of external temperature sensor 38 | 39 | #define Board_Definition "HAB2_Board_Definitions.h" //define the board to use here 40 | 41 | //************************************************************************************************** 42 | // 2) Program Options 43 | //************************************************************************************************** 44 | 45 | 46 | #define ConfigureDefaults //Configure settings from default program constants, save in memory and copy to RAM, need to do this once only 47 | //#define ClearAllMemory //Clears from start memory to end memory, normally 1kbyte, needs to be followed by ConfigureDefaults 48 | 49 | const byte Output_len_max = 125; //maximum length for built payload 50 | #define CheckTone //comment in to have a calibrate tone at startup, also indicates navigation model 6 set 51 | 52 | //#define DEBUG //if defined, prints additional debug information to terminal 53 | 54 | 55 | //************************************************************************************************** 56 | // 3) Frequency settings 57 | //************************************************************************************************** 58 | 59 | //Tracker mode 60 | const unsigned long TrackerMode_Frequency = 434400000; 61 | 62 | //Search mode 63 | const unsigned long SearchMode_Frequency = 434300000; 64 | 65 | //this is the LoRa module frequency calibration offset in Hertz 66 | const int CalibrationOffset = 0; 67 | 68 | 69 | //************************************************************************************************** 70 | // 4) LoRa settings 71 | //************************************************************************************************** 72 | 73 | //Tracker mode 74 | #define TrackerMode_Bandwidth BW62500 75 | #define TrackerMode_SpreadingFactor SF8 76 | #define TrackerMode_CodeRate CR45 77 | #define TrackerMode_Power 10 78 | 79 | //Search mode 80 | #define SearchMode_Bandwidth BW62500 81 | #define SearchMode_SpreadingFactor SF12 82 | #define SearchMode_CodeRate CR45 83 | #define SearchMode_Power 10 84 | 85 | //#define LORADEBUG //displays extra debug messages when using LoRa 86 | 87 | const byte Deviation = 0x52; //typical deviation for tones 88 | const byte lora_RXBUFF_Size = 16; //RX mode is not used 89 | const byte lora_TXBUFF_Size = 128; 90 | 91 | const byte delayforRelaysecs = 2; //allows time for relay to re-transmit 92 | 93 | 94 | 95 | //************************************************************************************************** 96 | // 5) GPS Options 97 | //************************************************************************************************** 98 | 99 | //#define USE_SOFTSERIAL_GPS //need to include this if we are using softserial for GPS 100 | //#define GPS_Library "UBLOX_SerialGPS.h" //define the GPS library routines to use here 101 | #define GPS_Library "UBLOX_I2CGPS2.h" 102 | 103 | //#define DEBUGNoGPS //test mode, does not use GPS 104 | //#define Use_Test_Location //to use test location for transmissions include this define 105 | 106 | //#define GPS_ALLOW_GPGSV //define this so that GPGSV senetences are not turned off 107 | //#define Checkfor_GNNS_Mode //define this if you want to check for GNNS sentences from GPS, not needed for latest TinyGPS++ 108 | 109 | #define GPSBaud 9600 //GPS Baud rate 110 | #define WhenNoGPSFix LeaveOn //What to do with GPS power when there is no fix at ends of wait period (LeaveOn or LeaveOff) 111 | const byte WaitGPSFixSeconds = 30; //in flight mode time to wait for a new GPS fix 112 | //#define Remove_GPS_Power //Some tracker boards can remove the power from the GPS, if so define this to use it 113 | #define Use_GPS_SoftwareBackup //some GPSs do not support this mode, Ubloxes do, used for GPS Hotfix option 114 | //#define Check_GPS_Navigation_Model_OK //every time the GPS is checked for a fix we can ceck for correct navigation mode on UBLOX 115 | 116 | const unsigned long GPSShutdownTimemS = 1900; //Software backup mode takes around 1.9secs to power down, used in maHr calculation 117 | const unsigned long fixisoldmS = 10000; //if location has not updated in this number of mS, assume GPS has lost fix 118 | const unsigned long GPS_WaitAck_mS = 2000; //number of mS to wait for an ACK response from GPS 119 | const unsigned int GPSFixs = 100; //number of GPS fixes between setting system clock from GPS 120 | const byte GPS_attempts = 3; //number of times the sending of GPS config will be attempted. 121 | const byte GPS_Reply_Size = 12; //size of GPS reply buffer 122 | const unsigned int GPS_Clear_DelaymS = 2000; //mS to wait after a GPS Clear command is sent 123 | 124 | //Centre of Cardiff Castle keep 125 | #define TestLatitude 51.48230 126 | #define TestLongitude -3.18136 127 | #define TestAltitude 48 128 | 129 | 130 | /* 131 | Passive GPS station: Swanbridge - C1ST1667 132 | https://www.ordnancesurvey.co.uk/gps/legacy-control-information/C1ST1667 133 | N 51 23'59.105955", W 3 11',47.413031 134 | 51.399751654166664, -3.196503619722222 135 | 136 | #define TestLatitude 51.399752 137 | #define TestLongitude -3.196504 138 | #define TestAltitude 0 139 | */ 140 | 141 | //************************************************************************************************** 142 | // 6) Which Memory to use for storage 143 | //************************************************************************************************** 144 | 145 | #define Memory_Library "EEPROM_Memory.h" //define this file if the internal EEPROM is in use 146 | 147 | //************************************************************************************************** 148 | // 8) FSK RTTY Settings 149 | //************************************************************************************************** 150 | 151 | const unsigned int FSKRTTYbaudDelay = 9845; //delay for baud rate for FSK RTTY, 19800 for 50baud, 9845 for 100baud, 4865 for 200baud 152 | const byte FSKRTTYRegshift = 6; //number of frequency steps to use for shift 153 | const byte FSKRTTYpips = 5; //number of FSK lead in pips 154 | const int FSKRTTYleadin = 500; //number of ms for FSK constant lead in tone 155 | const byte sync_chars = 3; //number of extra $ sync characters to send 156 | 157 | 158 | //************************************************************************************************** 159 | // 9) AFSK RTTY Options 160 | //************************************************************************************************** 161 | 162 | const byte delayforAFSKuploadSecs = 4; //allows time for AFSK upload on receiver 163 | 164 | 165 | //**************************************************************************************************** 166 | // 11) Program Default Option settings 167 | // This section determines which options are on or off by default, this is the Default_config1 byte 168 | // Take care here.......... 169 | //************************************************************************************************** 170 | 171 | #define OptionOff 0 172 | #define OptionOn 1 173 | 174 | const char option_SearchEnable = OptionOn; 175 | const char option_TXEnable = OptionOn; 176 | const char option_FSKRTTYEnable = OptionOn; 177 | const char option_CheckFence = OptionOff; 178 | const char option_ShortPayloadEnable = OptionOff; 179 | const char option_RepeatEnable = OptionOff; 180 | const char option_AddressStrip = OptionOn; 181 | const char option_GPSHotFix = OptionOff; 182 | 183 | #define option_SearchEnable_SUM (option_SearchEnable*1) 184 | #define option_TXEnable_SUM (option_TXEnable*2) 185 | #define option_FSKRTTYEnable_SUM (option_FSKRTTYEnable*4) 186 | #define option_CheckFence_SUM (option_CheckFence*8) 187 | #define option_ShortPayloadEnable_SUM (option_ShortPayloadEnable*16) 188 | #define option_RepeatEnable_SUM (option_RepeatEnable*32) 189 | #define option_AddressStrip_SUM (option_AddressStrip*64) 190 | #define option_GPSHotFix_SUM (option_GPSHotFix*128) 191 | 192 | //See Program_Definitions.h in the Tracker library for details, the above options translate into Default_config1 byte of 1 + 2 + 4 + 64 = 71 193 | 194 | const unsigned int Default_config1 = (option_SearchEnable_SUM + option_TXEnable_SUM + option_FSKRTTYEnable_SUM + option_CheckFence_SUM + option_ShortPayloadEnable_SUM + option_RepeatEnable_SUM + option_AddressStrip_SUM + option_GPSHotFix_SUM); 195 | const unsigned int Default_config2 = 0; 196 | const unsigned int Default_config3 = 0; 197 | const unsigned int Default_config4 = 0; 198 | //const unsigned int Default_config1 = 71; //Phew, the default config can always be set manually ............. 199 | 200 | 201 | //************************************************************************************************** 202 | // 12) Miscellaneous program settings 203 | //************************************************************************************************** 204 | 205 | 206 | 207 | 208 | 209 | //************************************************************************************************** 210 | // 13) Unique calibration settings for each Board 211 | // These settings are not part of a bind operation 212 | //************************************************************************************************** 213 | 214 | const float kelvin_offset = 326; //if processor self read of temperature reports high, increase this number 215 | const float temp_conversion_slope = 1.058 ; //defines the rate of change between low and high temperatures 216 | const unsigned long adc_constant = 1146679; //if processor self read of its supply voltage reports high reduce this number 217 | 218 | 219 | //************************************************************************************************** 220 | // 14) HAB2 settings 221 | //************************************************************************************************** 222 | 223 | char Flight_ID[15] = "MyFlight1"; 224 | 225 | const unsigned int Loop_Sleepsecs = 25; //sleep time in seconds after each TX loop 226 | 227 | const char ThisNode = '1'; 228 | 229 | 230 | -------------------------------------------------------------------------------- /Programs/Tracker_HAB2_101017/Tracker_HAB2_Settings.h: -------------------------------------------------------------------------------- 1 | //Tracker_HAB2_Settings.h 2 | /* 3 | ****************************************************************************************************** 4 | 5 | Tracker Programs for Arduino 6 | 7 | Copyright of the author Stuart Robinson - 10/10/2017 8 | 9 | These programs may be used free of charge for personal, recreational and educational purposes only. 10 | 11 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 12 | the explicit permission of the author Stuart Robinson. 13 | 14 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the 15 | intended purpose and free from errors. 16 | 17 | To Do: 18 | 19 | Changes: 20 | 101017 Removed unused board definitions 21 | 22 | ****************************************************************************************************** 23 | */ 24 | 25 | //************************************************************************************************** 26 | // 1) Hardware related definitions and options - specify board type here 27 | //************************************************************************************************** 28 | 29 | #define CPU_VoltageRead 30 | //#define External_VoltageRead 31 | 32 | #define CPU_TemperatureRead 33 | //#define External_TemperatureRead //assumes a TC74 is in use 34 | 35 | const int Temperature_Adjust = 0; //to allow calibration of external temperature sensor 36 | #define TC74_Address 0x4c //init with TC74 address, can be 0x48 to 0x4F depending on specific type 37 | 38 | #define Board_Definition "HAB2_Board_Definitions.h" //define the board to use here 39 | 40 | const float runmA = 4; //processor run current 41 | const float SleepmA = 0.22; //approx current in sleep, Ublox GPS consumes circa 200uA 42 | 43 | 44 | //************************************************************************************************** 45 | // 2) Program Options 46 | //************************************************************************************************** 47 | 48 | 49 | #define ConfigureDefaults //Configure settings from default program constants, save in memory and copy to RAM, need to do this once only 50 | #define ClearAllMemory //Clears from start memory to end memory, normally 1kbyte, needs to be folloowed by ConfigureDefaults 51 | //#define ClearSavedData //zero the saved data, resets, sequence, Mahr 52 | //#define ConfigureFromMemory //Read settings from attached memory 53 | 54 | const byte Output_len_max = 125; //maximum length for built payload 55 | #define CheckTone //comment in to have a calibrate tone at startup, also indicates navigation model 6 set 56 | 57 | //#define DEBUG //if defined, prints additional debug information to terminal 58 | 59 | const int DozeSleepSecs = 180; //how many seconds to spend in doze (very low power mode), mode can only be enabled remotely 60 | 61 | //************************************************************************************************** 62 | // 3) Frequency settings 63 | //************************************************************************************************** 64 | 65 | //Tracker mode 66 | const unsigned long TrackerMode_Frequency = 434400000; 67 | 68 | //Search mode 69 | const unsigned long SearchMode_Frequency = 434300000; 70 | 71 | //Command mode 72 | const unsigned long CommandMode_Frequency = 434500000; 73 | 74 | //Bind mode - Change this with great care !!!!! 75 | const unsigned long BindMode_Frequency = 434100000; 76 | 77 | //this is the LoRa module frequency calibration offset in Hertz 78 | const int CalibrationOffset = 0; 79 | 80 | 81 | //************************************************************************************************** 82 | // 4) LoRa settings 83 | //************************************************************************************************** 84 | 85 | //Tracker mode 86 | #define TrackerMode_Bandwidth BW62500 87 | #define TrackerMode_SpreadingFactor SF8 88 | #define TrackerMode_CodeRate CR45 89 | #define TrackerMode_Power 10 90 | 91 | //Search mode 92 | #define SearchMode_Bandwidth BW62500 93 | #define SearchMode_SpreadingFactor SF12 94 | #define SearchMode_CodeRate CR45 95 | #define SearchMode_Power 10 96 | 97 | //Command mode 98 | #define CommandMode_Bandwidth BW62500 99 | #define CommandMode_SpreadingFactor SF10 100 | #define CommandMode_CodeRate CR45 101 | #define CommandMode_Power 10 102 | 103 | //Bind mode 104 | #define BindMode_Bandwidth BW500000 105 | #define BindMode_SpreadingFactor SF8 106 | #define BindMode_CodeRate CR45 107 | #define BindMode_Power 2 108 | 109 | #define SendBind //at startup tracker transmitter will send a bind packet 110 | //#define LORADEBUG //displays extra debug messages when using LoRa 111 | 112 | const byte Deviation = 0x52; //typical deviation for tones 113 | const byte lora_RXBUFF_Size = 128; 114 | const byte lora_TXBUFF_Size = 128; 115 | 116 | const float RXmA = 11; //LoRa device receive current 117 | const float TXmA = 40; //LoRa device transmit current @ 10dBm 118 | 119 | const int inter_Packet_delay = 500; //allows time for receiver to be ready to see a possible reply, in mS 120 | const byte delayforRelaysecs = 2; //allows time for relay to re-transmit 121 | 122 | const byte Cmd_WaitSecs = 5; //number of seconds to stay in waiting for command mode 123 | const byte Command_Loops = 3; //if one command is received wait for this number of loops to keep control channel open 124 | 125 | //Key Definition 126 | const char key0 = 'L'; //Used to restrict access to some commands 127 | const char key1 = 'o'; 128 | const char key2 = 'R'; 129 | const char key3 = 'a'; 130 | 131 | //************************************************************************************************** 132 | // 5) GPS Options 133 | //************************************************************************************************** 134 | 135 | #define USE_SOFTSERIAL_GPS //need to include this if we are using softserial for GPS 136 | #define GPS_Library "UBLOX_SerialGPS.h" //define the GPS library routines to use here 137 | //#define GPS_Library "UBLOX_I2CGPS.h" 138 | 139 | //#define DEBUGNoGPS //test mode, does not use GPS 140 | //#define Use_Test_Location //to use test location for transmissions include this define 141 | 142 | //#define GPS_ALLOW_GPGSV //define this so that GPGSV senetences are not turned off 143 | 144 | #define GPSBaud 9600 //GPS Baud rate 145 | #define WhenNoGPSFix LeaveOn //What to do with GPS power when there is no fix at ends of wait period (LeaveOn or LeaveOff) 146 | #define WaitGPSFixSeconds 30 //in flight mode time to wait for a new GPS fix 147 | //#define Remove_GPS_Power //Some tracker boards can remove the power from the GPS, if so define this to use it 148 | #define Use_GPS_SoftwareBackup //some GPSs do not support this mode, Ubloxes do, used for GPS Hotfix option 149 | //#define Check_GPS_Navigation_Model_OK //every time the GPS is checked for a fix we can ceck for correct navigation mode on UBLOX 150 | 151 | const unsigned long GPSShutdownTimemS = 1900; //Software backup mode takes around 1.9secs to power down, used in maHr calculation 152 | const unsigned long fixisoldmS = 10000; //if location has not updated in this number of mS, assume GPS has lost fix 153 | const unsigned long GPS_WaitAck_mS = 2000; //number of mS to wait for an ACK response from GPS 154 | const unsigned int GPSFixs = 100; //number of GPS fixes between setting system clock from GPS 155 | const byte GPS_attempts = 3; //number of times the sending of GPS config will be attempted. 156 | const byte GPS_Reply_Size = 12; //size of GPS reply buffer 157 | const float GPSmA = 24; //GPS average (UBLOX) current when aquiring fix 158 | const unsigned int GPS_Clear_DelaymS = 2000; //mS to wait after a GPS Clear command is sent 159 | 160 | //Centre of Cardiff Castle keep 161 | #define TestLatitude 51.48230 162 | #define TestLongitude -3.18136 163 | #define TestAltitude 48 164 | 165 | 166 | /* 167 | Passive GPS station: Swanbridge - C1ST1667 168 | https://www.ordnancesurvey.co.uk/gps/legacy-control-information/C1ST1667 169 | N 51 23'59.105955", W 3 11',47.413031 170 | 51.399751654166664, -3.196503619722222 171 | 172 | #define TestLatitude 51.399752 173 | #define TestLongitude -3.196504 174 | #define TestAltitude 0 175 | */ 176 | 177 | //************************************************************************************************** 178 | // 6) Which Memory to use for storage 179 | //************************************************************************************************** 180 | 181 | #define Memory_Library "EEPROM_Memory.h" //define this file if the internal EEPROM is in use 182 | //#define Memory_Library "I2CFRAM_MB85RC16PNF.h" //define this file if the I2C FRAM is in use 183 | 184 | //************************************************************************************************** 185 | // 8) FSK RTTY Settings 186 | //************************************************************************************************** 187 | 188 | const unsigned int FSKRTTYbaudDelay = 9845; //delay for baud rate for FSK RTTY, 19800 for 50baud, 9845 for 100baud, 4865 for 200baud 189 | const byte FSKRTTYRegshift = 6; //number of frequency steps to use for shift 190 | const byte FSKRTTYpips = 5; //number of FSK lead in pips 191 | const int FSKRTTYleadin = 500; //number of ms for FSK constant lead in tone 192 | const byte sync_chars = 3; //number of extra $ sync characters to send 193 | 194 | 195 | //************************************************************************************************** 196 | // 9) AFSK RTTY Options 197 | //************************************************************************************************** 198 | 199 | const byte delayforAFSKuploadSecs = 4; //allows time for AFSK upload on receiver 200 | 201 | 202 | //**************************************************************************************************** 203 | // 11) Program Default Option settings 204 | // This section determines which options are on or off by default, this is the Default_config1 byte 205 | // Take care here.......... 206 | //************************************************************************************************** 207 | 208 | #define OptionOff 0 209 | #define OptionOn 1 210 | 211 | const char option_SearchEnable = OptionOn; 212 | const char option_TXEnable = OptionOn; 213 | const char option_FSKRTTYEnable = OptionOn; 214 | const char option_CheckFence = OptionOff; 215 | const char option_ShortPayloadEnable = OptionOff; 216 | const char option_RepeatEnable = OptionOff; 217 | const char option_AddressStrip = OptionOn; 218 | const char option_GPSHotFix = OptionOff; 219 | 220 | #define option_SearchEnable_SUM (option_SearchEnable*1) 221 | #define option_TXEnable_SUM (option_TXEnable*2) 222 | #define option_FSKRTTYEnable_SUM (option_FSKRTTYEnable*4) 223 | #define option_CheckFence_SUM (option_CheckFence*8) 224 | #define option_ShortPayloadEnable_SUM (option_ShortPayloadEnable*16) 225 | #define option_RepeatEnable_SUM (option_RepeatEnable*32) 226 | #define option_AddressStrip_SUM (option_AddressStrip*64) 227 | #define option_GPSHotFix_SUM (option_GPSHotFix*128) 228 | 229 | //See Program_Definitions.h in the Tracker library for details, the above options translate into Default_config1 byte of 1 + 2 + 4 + 64 = 71 230 | 231 | const unsigned int Default_config1 = (option_SearchEnable_SUM + option_TXEnable_SUM + option_FSKRTTYEnable_SUM + option_CheckFence_SUM + option_ShortPayloadEnable_SUM + option_RepeatEnable_SUM + option_AddressStrip_SUM + option_GPSHotFix_SUM); 232 | const unsigned int Default_config2 = 0; 233 | const unsigned int Default_config3 = 0; 234 | const unsigned int Default_config4 = 0; 235 | //const unsigned int Default_config1 = 71; //Phew, the default config can always be set manually ............. 236 | 237 | 238 | //************************************************************************************************** 239 | // 12) Miscellaneous program settings 240 | //************************************************************************************************** 241 | 242 | 243 | 244 | 245 | 246 | //************************************************************************************************** 247 | // 13) Unique calibration settings for each Board 248 | // These settings are not part of a bind operation 249 | //************************************************************************************************** 250 | 251 | const float kelvin_offset = 326; //if processor self read of temperature reports high, increase this number 252 | const float temp_conversion_slope = 1.058 ; //defines the rate of change between low and high temperatures 253 | const unsigned long adc_constant = 1146679; //if processor self read of its supply voltage reports high reduce this number 254 | 255 | 256 | //************************************************************************************************** 257 | // 14) HAB2 settings 258 | //************************************************************************************************** 259 | 260 | char Flight_ID[15] = "MyFlight1"; 261 | 262 | const float west_fence = -4; 263 | const float east_fence = 45; 264 | 265 | const unsigned int Loop_Sleepsecs = 25; //sleep time in seconds after each TX loop 266 | const unsigned int outside_fence_Sleep_seconds = 600; //approx 10 minutes 267 | const boolean promiscuous_Mode = true; //if set to True remote control packets from any node accepted 268 | 269 | #define RemoteControlNode 'G' //normally used by tracker transmitter in promiscuous_Mode 270 | #define ControlledNode '1' //normally used by tracker transmitter in promiscuous_Mode 271 | #define ThisNode ControlledNode 272 | -------------------------------------------------------------------------------- /Programs/Tracker_HAB2_Bare_Bones_200518/Tracker_HAB2_Bare_Bones_200518.ino: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // Note: 3 | // 4 | // Make changes to this Program file at your peril 5 | // 6 | // Configuration changes should be made in the HAB2_Settings file not here ! 7 | // 8 | //************************************************************************************************** 9 | 10 | #define programname "Tracker_HAB2_Bare_Bones_200518" 11 | #define aurthorname "Stuart Robinson" 12 | 13 | #include 14 | #include 15 | 16 | #include "Tracker_HAB2_Settings.h" 17 | #include Board_Definition 18 | #include "Program_Definitions.h" 19 | 20 | /* 21 | ************************************************************************************************** 22 | 23 | Tracker Programs for Arduino 24 | 25 | Copyright of the author Stuart Robinson 26 | 27 | 28 | 29 | These programs may be used free of charge for personal, recreational and educational purposes only. 30 | 31 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 32 | the explicit permission of the author Stuart Robinson. 33 | 34 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 35 | free from errors. 36 | 37 | Location payload is constructed thus; 38 | 39 | PayloadID,Sequence,Time,Lat,Lon,Alt,Sats,SupplyVolts,Temperature,Resets,StatusByte,GPSFixTime,Checksum 40 | 0 1 2 3 4 5 6 7 8 9 10 11 12 41 | 42 | To Do: 43 | 44 | Changes: 45 | 46 | 220518 - Develop a version of the HAB2 software reduced to a minium 47 | 220518 - Size with SoftwareSerial GPS 29996/1407, I2C GPS 28402/1290 48 | 220518 - Leave with I2C GPS 49 | 220518 - Remove battery use calculation 27440/1286 50 | 220518 - Remove CPU_VoltageRead option 51 | 220518 - Remove memory storage of config, use system defaults 52 | 220518 - Remove receiver options, fence check 20942/1091 53 | 220518 - Switch to UBLOX_I2CGPS2.h 20388/1009 54 | 220518 - Remove unecessary commands and byte definitions 20050/949 55 | 220518 - Allow removal of detecting GNSS mode, should not be needed for latest TinyGPS++ 19928/905 56 | 57 | ************************************************************************************************** 58 | */ 59 | 60 | byte TRStatus = 0; //used to store current status flag bits 61 | 62 | byte stripvalue; 63 | byte sats; //either sats in view from GPGSV or sats from NMEA fix sentence 64 | int temperature; 65 | 66 | float TRLat; //tracker transmitter co-ordinates 67 | float TRLon; 68 | unsigned int TRAlt; 69 | 70 | byte keypress; 71 | 72 | unsigned long GPSonTime; 73 | unsigned long GPSFixTime; 74 | boolean GPS_Config_Error; 75 | 76 | #include Board_Definition //include previously defined board file 77 | #include Memory_Library //include previously defined Memory Library 78 | 79 | #include 80 | #include //https://github.com/rocketscream/Low-Power 81 | 82 | #include //http://arduiniana.org/libraries/tinygpsplus/ 83 | TinyGPSPlus gps; //create the TinyGPS++ object 84 | 85 | #ifdef Checkfor_GNNS_Mode 86 | TinyGPSCustom GNGGAFIXQ(gps, "GNGGA", 5); //custom sentences used to detect possible switch to GNSS mode 87 | #endif 88 | 89 | 90 | #ifdef USE_SOFTSERIAL_GPS 91 | #include //https://github.com/SlashDevin/NeoSWSerial 92 | NeoSWSerial GPSserial(GPSRX, GPSTX); //this library is more relaible at GPS init than software serial 93 | #endif 94 | 95 | #include GPS_Library //include previously defined GPS Library 96 | 97 | #include "Voltage_Temperature.h" 98 | #include "LoRa3.h" 99 | #include "FSK_RTTY2.h" 100 | #include "Binary2.h" 101 | 102 | 103 | void loop() 104 | { 105 | Serial.println(); 106 | 107 | GPSFixTime = 0; 108 | temperature = (int) read_Temperature(); //read temp just after sleep, when CPU is closest to ambient 109 | GPSonTime = millis(); 110 | 111 | #ifndef DEBUGNoGPS 112 | gpsWaitFix(WaitGPSFixSeconds, SwitchOn, LeaveOn); 113 | #endif 114 | 115 | #ifdef Use_Test_Location 116 | TRLat = TestLatitude; 117 | TRLon = TestLongitude; 118 | TRAlt = TestAltitude; 119 | #endif 120 | 121 | do_Transmissions(); //do the transmissions 122 | 123 | digitalWrite(lora_NSS, HIGH); //take NSS line high, makes sure LoRa device is off 124 | sleepSecs(Loop_Sleepsecs); //this sleep is used to set overall transmission cycle time 125 | 126 | } 127 | 128 | 129 | void do_Transmissions() 130 | { 131 | //this is where all the transmisions get sent 132 | byte index, Count; 133 | 134 | pulseWDI(); 135 | lora_Setup(); //resets then sets up LoRa device 136 | 137 | Setup_TrackerMode(); 138 | 139 | incMemoryULong(addr_SequenceNum); //increment sequence number 140 | Count = buildHABPacket(); 141 | stripvalue = readConfigByte(AddressStrip); 142 | Serial.println(F("HAB Pkt")); 143 | printPayload(Count); 144 | Serial.println(); 145 | digitalWrite(LED1, HIGH); 146 | lora_Send(0, Count, HABPacket, Broadcast, ThisNode, 10, lora_Power, stripvalue); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd 147 | digitalWrite(LED1, LOW); 148 | 149 | sleepSecs(delayforAFSKuploadSecs); //allow time for receiver AFSK upload 150 | 151 | sleepSecs(delayforRelaysecs); //wait for relay to operate 152 | 153 | if (readConfigByte(FSKRTTYEnable)) 154 | { 155 | 156 | Serial.println(F("FSKRTTY")); 157 | 158 | lora_DirectSetup(); //set for direct mode 159 | lora_SetFreq(TrackerMode_Frequency, CalibrationOffset); 160 | Start_FSKRTTY(FSKRTTYRegshift, FSKRTTYleadin, FSKRTTYpips); 161 | 162 | for (index = 1; index <= sync_chars; index++) 163 | { 164 | Send_FSKRTTY('$', FSKRTTYbaudDelay); 165 | } 166 | 167 | for (index = 0; index <= Count; index++) 168 | { 169 | Send_FSKRTTY(lora_TXBUFF[index], FSKRTTYbaudDelay); 170 | } 171 | Send_FSKRTTY(13, FSKRTTYbaudDelay); //finish RTTY with carriage return 172 | Send_FSKRTTY(10, FSKRTTYbaudDelay); //and line feed 173 | digitalWrite(LED1, LOW); //make sure LED off 174 | lora_TXOFF(); //to ensure TXTime updated correctly 175 | } 176 | 177 | if (readConfigByte(SearchEnable)) 178 | { 179 | Setup_LoRaSearchMode(); //setup is here so that any mode can be used to TX binary packet 180 | send_LocationBinary(TRLat, TRLon, TRAlt); 181 | } 182 | } 183 | 184 | 185 | byte buildHABPacket() //expects a char buffer, so this routine will not work without the -permissive setting 186 | { 187 | //build the long tracker payload 188 | unsigned int index, j, CRC, resets; 189 | int volts; 190 | byte Count,len; 191 | char LatArray[12], LonArray[12]; 192 | unsigned long sequence; 193 | 194 | sequence = Memory_ReadULong(addr_SequenceNum); //sequence number is kept in non-volatile memory so it survives resets 195 | resets = Memory_ReadUInt(addr_ResetCount); //reset count is kept in non-volatile memory so it survives resets 196 | 197 | volts = read_SupplyVoltage(); 198 | 199 | if (!readConfigByte(GPSHotFix)) 200 | { 201 | GPSFixTime = 0; //if GPS power save is off (no GPSHotFix), ensure GPS fix time is set to zero 202 | } 203 | 204 | sats = gps.satellites.value(); 205 | dtostrf(TRLat, 7, 5, LatArray); //format is dtostrf(FLOAT,WIDTH,PRECISION,BUFFER); 206 | dtostrf(TRLon, 7, 5, LonArray); //converts float to character array 207 | len = sizeof(lora_TXBUFF); 208 | memset(lora_TXBUFF, 0, len); //clear array to 0s 209 | 210 | Count = snprintf((char*) lora_TXBUFF, 211 | Output_len_max, 212 | "$$$$%s,%lu,%02d:%02d:%02d,%s,%s,%d,%d,%d,%d,%d,%d,%lu", 213 | Flight_ID, 214 | sequence, 215 | gps.time.hour(), 216 | gps.time.minute(), 217 | gps.time.second(), 218 | LatArray, 219 | LonArray, 220 | TRAlt, 221 | sats, 222 | volts, 223 | temperature, 224 | resets, 225 | TRStatus, 226 | GPSFixTime 227 | ); 228 | 229 | CRC = 0xffff; //start value for CRC16 230 | 231 | for (index = 4; index < Count; index++) //element 4 is first character after $$ at start 232 | { 233 | CRC ^= (((unsigned int)lora_TXBUFF[index]) << 8); 234 | for (j = 0; j < 8; j++) 235 | { 236 | if (CRC & 0x8000) 237 | CRC = (CRC << 1) ^ 0x1021; 238 | else 239 | CRC <<= 1; 240 | } 241 | } 242 | 243 | lora_TXBUFF[Count++] = '*'; 244 | lora_TXBUFF[Count++] = Hex((CRC >> 12) & 15); //add the checksum bytes to the end 245 | lora_TXBUFF[Count++] = Hex((CRC >> 8) & 15); 246 | lora_TXBUFF[Count++] = Hex((CRC >> 4) & 15); 247 | lora_TXBUFF[Count] = Hex(CRC & 15); 248 | return Count; 249 | } 250 | 251 | 252 | char Hex(byte lchar) 253 | { 254 | //used in CRC calculation in buildHABPacket 255 | char Table[] = "0123456789ABCDEF"; 256 | return Table[lchar]; 257 | } 258 | 259 | 260 | 261 | void send_LocationBinary(float Lat, float Lon, unsigned int Alt) 262 | { 263 | Write_Float(0, Lat, lora_TXBUFF); 264 | Write_Float(4, Lon, lora_TXBUFF); 265 | Write_Int(8, Alt, lora_TXBUFF); 266 | Write_Byte(10, TRStatus, lora_TXBUFF); 267 | 268 | digitalWrite(LED1, HIGH); 269 | Serial.println(F("Binary Location")); 270 | lora_Send(0, 10, LocationBinaryPacket, Broadcast, ThisNode, 10, lora_Power, 0); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd 271 | digitalWrite(LED1, LOW); 272 | } 273 | 274 | 275 | void printPayload(byte lCount) 276 | { 277 | byte index; 278 | for (index = 0; index <= lCount; index++) 279 | { 280 | Serial.write(lora_TXBUFF[index]); 281 | } 282 | } 283 | 284 | 285 | void sleepSecs(unsigned int LNumberSleeps) 286 | { 287 | unsigned int i; 288 | 289 | Serial.print(F("zz ")); 290 | Serial.println(LNumberSleeps); 291 | Serial.flush(); //let print complete 292 | #ifdef USING_SERIALGPS 293 | GPSserial.end(); //we dont want GPS input interfering with sleep, make sure its off 294 | #endif 295 | digitalWrite(lora_NSS, HIGH); //ensure LoRa Device is off 296 | 297 | for (i = 1; i <= LNumberSleeps; i++) 298 | { 299 | LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); //sleep 1 second 300 | pulseWDI(); 301 | } 302 | 303 | } 304 | 305 | 306 | void incMemoryULong(unsigned int laddress) 307 | { 308 | unsigned long val; 309 | val = Memory_ReadULong(laddress); 310 | val++; 311 | Memory_WriteULong(laddress, val); 312 | } 313 | 314 | 315 | void setStatusByte(byte bitnum, byte bitval) 316 | { 317 | //program the status byte 318 | 319 | if (bitval == 0) 320 | { 321 | bitClear(TRStatus, bitnum); 322 | } 323 | else 324 | { 325 | bitSet(TRStatus, bitnum); 326 | } 327 | 328 | #ifdef DEBUG 329 | if (bitval) 330 | { 331 | Serial.print(F("Set Status Bit ")); 332 | } 333 | else 334 | { 335 | Serial.print(F("Clear Status Bit ")); 336 | } 337 | 338 | Serial.println(bitnum); 339 | #endif 340 | } 341 | 342 | 343 | byte readConfigByte(byte bitnum) 344 | { 345 | return bitRead(Default_config1, bitnum); 346 | } 347 | 348 | 349 | void pulseWDI() 350 | { 351 | //if the watchdog is fitted it needs a regular pulse top prevent reset 352 | //togle the WDI pin twice 353 | digitalWrite(WDI, !digitalRead(WDI)); 354 | delayMicroseconds(1); 355 | digitalWrite(WDI, !digitalRead(WDI)); 356 | } 357 | 358 | 359 | boolean gpsWaitFix(unsigned long waitSecs, byte StartState, byte LeaveState) 360 | { 361 | //waits a specified number of seconds for a fix, returns true for good fix 362 | //StartState when set to 1 will turn GPS on at routine start 363 | //LeaveState when set to 0 will turn GPS off at routine end, used perhaps when there is no fix 364 | 365 | unsigned long endwaitmS, millistowait, currentmillis; 366 | pulseWDI(); 367 | byte GPSByte; 368 | 369 | if (StartState == 1) 370 | { 371 | GPS_On(DoGPSPowerSwitch); 372 | GPSonTime = millis(); 373 | } 374 | else 375 | { 376 | GPS_On(NoGPSPowerSwitch); 377 | } 378 | 379 | #ifdef Check_GPS_Navigation_Model_OK 380 | Serial.println(F("Check GPSNavigation Model")); 381 | if (!GPS_CheckNavigation()) 382 | { 383 | //something wrong with GPS, navigation mode not set so reconfigure the GPS 384 | Serial.println(F("GPS Config Error !!!!")); 385 | GPS_Setup(); 386 | } 387 | #endif 388 | 389 | 390 | Serial.print(F("Wait Fix ")); 391 | Serial.print(waitSecs); 392 | Serial.println(F(" Secs")); 393 | 394 | currentmillis = millis(); 395 | millistowait = waitSecs * 1000; 396 | endwaitmS = currentmillis + millistowait; 397 | 398 | while (millis() < endwaitmS) 399 | { 400 | 401 | do 402 | { 403 | GPSByte = GPS_GetByte(); 404 | if (GPSByte != 0xFF) 405 | { 406 | gps.encode(GPSByte); 407 | } 408 | } 409 | while (GPSByte != 0xFF); 410 | 411 | if (gps.location.isUpdated() && gps.altitude.isUpdated()) 412 | { 413 | Serial.println(F("GPS Fix")); 414 | TRLat = gps.location.lat(); 415 | TRLon = gps.location.lng(); 416 | TRAlt = (unsigned int) gps.altitude.meters(); 417 | 418 | //Altitude is used as an unsigned integer, so that the binary payload is as short as possible. 419 | //However gps.altitude.meters(); can return a negative value which converts to 420 | //65535 - Altitude, which we dont want. So we will assume any value over 60,000M is zero 421 | 422 | if (TRAlt > 60000) 423 | { 424 | TRAlt = 0; 425 | } 426 | 427 | if (readConfigByte(GPSHotFix)) 428 | { 429 | GPS_Off(DoGPSPowerSwitch); 430 | GPSFixTime = (millis() - GPSonTime); 431 | Serial.print(F("FixTime ")); 432 | Serial.print(GPSFixTime); 433 | Serial.println(F("mS")); 434 | } 435 | else 436 | { 437 | GPS_Off(NoGPSPowerSwitch); 438 | } 439 | 440 | setStatusByte(GPSFix, 1); 441 | pulseWDI(); 442 | return true; 443 | } 444 | 445 | #ifdef UBLOX 446 | #ifdef Checkfor_GNNS_Mode 447 | if (GNGGAFIXQ.age() < 2000) //check to see if GNSS mode has gone active 448 | { 449 | Serial.println(F("GNSS !")); 450 | setStatusByte(GLONASSisoutput, 1); 451 | GPS_SetGPMode(); 452 | GPS_SetCyclicMode(); 453 | sleepSecs(1); 454 | } 455 | else 456 | { 457 | setStatusByte(GLONASSisoutput, 0); //GNSS mode not detected 458 | } 459 | #endif 460 | #endif 461 | 462 | 463 | 464 | } 465 | 466 | //if here then there has been no fix and a timeout 467 | setStatusByte(GPSFix, 0); //set status bit to flag no fix 468 | Serial.println(F("No Fix")); 469 | 470 | if (LeaveState == 0) 471 | { 472 | //no fix and gpsWaitFix called with gpspower to be turned off on exit 473 | GPS_Off(DoGPSPowerSwitch); 474 | } 475 | else 476 | { 477 | //no fix but gpsWaitFix called with gpspower to be left on at exit 478 | GPS_Off(NoGPSPowerSwitch); 479 | } 480 | 481 | pulseWDI(); 482 | return false; 483 | } 484 | 485 | 486 | 487 | void printNodes() 488 | { 489 | Serial.print(F("ThisNode ")); 490 | Serial.print(ThisNode); 491 | Serial.println(); 492 | } 493 | 494 | 495 | void Setup_TrackerMode() 496 | { 497 | lora_SetFreq(TrackerMode_Frequency, CalibrationOffset); 498 | lora_SetModem2(TrackerMode_Bandwidth, TrackerMode_SpreadingFactor, TrackerMode_CodeRate, Explicit); //Setup the LoRa modem parameters for tracker mode 499 | lora_Power = TrackerMode_Power; 500 | } 501 | 502 | 503 | void Setup_LoRaSearchMode() 504 | { 505 | lora_SetFreq(SearchMode_Frequency, CalibrationOffset); 506 | lora_SetModem2(SearchMode_Bandwidth, SearchMode_SpreadingFactor, SearchMode_CodeRate, Explicit); //Setup the LoRa modem parameters for search mode 507 | lora_Power = SearchMode_Power; 508 | } 509 | 510 | 511 | void send_Command(char cmd) 512 | { 513 | unsigned int volts; 514 | volts = read_SupplyVoltage(); 515 | Serial.print(F("Send Cmd ")); 516 | Serial.write(cmd); 517 | Serial.println(); 518 | Write_Byte(0, lora_PacketSNR, lora_TXBUFF); //so that receiver alwsys knows last received SNR 519 | Write_Byte(1, lora_PacketRSSI, lora_TXBUFF); //so that receiver alwsys knows last received RSSI 520 | Write_UInt(2, volts, lora_TXBUFF); 521 | Write_Byte(4, TRStatus, lora_TXBUFF); 522 | digitalWrite(LED1, HIGH); 523 | lora_Send(0, 4, cmd, Broadcast, ThisNode, 10, lora_Power, 0); 524 | digitalWrite(LED1, LOW); 525 | } 526 | 527 | 528 | void display_current_frequency() 529 | { 530 | float freq_temp = lora_GetFreq(); 531 | Serial.print(F("Frequency ")); 532 | Serial.print(freq_temp, 3); 533 | Serial.println(F("MHz")); 534 | } 535 | 536 | 537 | void led_Flash(unsigned int flashes, unsigned int delaymS) 538 | { 539 | //flash LED to show tracker is alive 540 | unsigned int index; 541 | 542 | for (index = 1; index <= flashes; index++) 543 | { 544 | digitalWrite(LED1, HIGH); 545 | delay(delaymS); 546 | digitalWrite(LED1, LOW); 547 | delay(delaymS); 548 | } 549 | } 550 | 551 | 552 | void Clear_All_Memory() 553 | { 554 | //clears the whole of memory, normally 1kbyte 555 | Serial.println(F("Clear Memory")); 556 | Memory_Set(addr_StartMemory, addr_EndMemory, 0); 557 | } 558 | 559 | 560 | void setup() 561 | { 562 | unsigned long int i; 563 | unsigned int j; 564 | 565 | pinMode(LED1, OUTPUT); //for PCB LED 566 | pinMode(WDI, OUTPUT); //for Watchdog pulse input 567 | 568 | led_Flash(2, 500); 569 | 570 | Serial.begin(38400); //Setup Serial console ouput 571 | 572 | Memory_Start(); 573 | 574 | #ifdef ClearAllMemory 575 | Clear_All_Memory(); 576 | #endif 577 | 578 | Serial.println(F(programname)); 579 | Serial.println(F(aurthorname)); 580 | 581 | pinMode(GPSPOWER, OUTPUT); //in case power switching components are fitted 582 | GPS_On(DoGPSPowerSwitch); //this will power the GPSon 583 | GPSonTime = millis(); 584 | 585 | #ifdef USING_SERIALGPS 586 | GPSserial.end(); //but we dont want soft serial running for now, it interferes with the LoRa device 587 | #endif 588 | 589 | pinMode(lora_NReset, OUTPUT); //LoRa device reset line 590 | digitalWrite(lora_NReset, HIGH); 591 | 592 | pinMode (lora_NSS, OUTPUT); //set the slave select pin as an output: 593 | digitalWrite(lora_NSS, HIGH); 594 | 595 | SPI.begin(); //initialize SPI 596 | SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 597 | 598 | 599 | #ifdef ClearSavedData 600 | do_ClearSavedData(); 601 | #endif 602 | 603 | Serial.print(F("Default_Config1 ")); 604 | Serial.println(Default_config1, BIN); 605 | 606 | j = Memory_ReadUInt(addr_ResetCount); 607 | j++; 608 | Memory_WriteUInt(addr_ResetCount, j); 609 | Serial.print(F("Resets ")); 610 | Serial.println(j); 611 | Serial.print(F("Sequence ")); 612 | i = Memory_ReadULong(addr_SequenceNum); 613 | Serial.println(i); 614 | 615 | #ifdef DEBUG 616 | printNodes(); 617 | #endif 618 | 619 | lora_Setup(); 620 | 621 | if (!lora_CheckDevice()) 622 | { 623 | led_Flash(100, 50); //long medium speed flash for Lora device error 624 | Serial.println(F("LoRa Error!")); 625 | } 626 | 627 | #ifdef DEBUG 628 | display_current_frequency(); 629 | #endif 630 | 631 | Serial.print(F("Cal Offset ")); 632 | Serial.println(CalibrationOffset); 633 | 634 | #ifdef DEBUG 635 | lora_Print(); 636 | #endif 637 | 638 | Serial.println(); 639 | print_SupplyVoltage(); 640 | print_Temperature(); 641 | Serial.println(); 642 | 643 | j = read_SupplyVoltage(); //get supply mV 644 | 645 | Setup_TrackerMode(); 646 | send_Command(PowerUp); //send power up command, includes supply mV and config, on tracker settings 647 | sleepSecs(1); 648 | 649 | Setup_TrackerMode(); //so that check tone is at correct frequency 650 | 651 | GPS_Config_Error = false; //make sure GPS error flag is cleared 652 | 653 | #ifndef DEBUGNoGPS 654 | GPS_On(DoGPSPowerSwitch); //GPS should have been on for a while by now, so this is just to start soft serial 655 | GPSonTime = millis(); 656 | GPS_Setup(); //GPS should have had plenty of time to initialise by now 657 | 658 | #ifdef UBLOX 659 | if (!GPS_CheckNavigation()) //Check that UBLOX GPS is in Navigation model 6 660 | { 661 | Serial.println(); 662 | GPS_Config_Error = true; 663 | setStatusByte(GPSError, 1); 664 | setStatusByte(UBLOXDynamicModel6Set, 0); 665 | } 666 | else 667 | { 668 | setStatusByte(UBLOXDynamicModel6Set, 1); 669 | } 670 | #endif 671 | 672 | if (GPS_Config_Error) 673 | { 674 | Serial.println(F("GPS Error !")); 675 | Serial.println(); 676 | send_Command(NoGPS); //make sure receiver knows about GPS error 677 | led_Flash(100, 25); //long very rapid flash for GPS error 678 | } 679 | else 680 | { 681 | 682 | #ifdef CheckTone 683 | digitalWrite(LED1, HIGH); 684 | Serial.println(F("Check Tone")); //check tone indicates navigation model 6 set (if checktone enabled!) 685 | lora_Tone(1000, 3000, 2); //Transmit an FM tone, 1000hz, 3000ms, 2dBm 686 | digitalWrite(LED1, LOW); 687 | #endif 688 | } 689 | 690 | 691 | setStatusByte(NoGPSTestMode, 0); 692 | GPSonTime = millis(); 693 | while (!gpsWaitFix(5, DontSwitch, LeaveOn)) //wait for the initial GPS fix, this could take a while, leave GPS powered on 694 | { 695 | 696 | led_Flash(2, 50); //two short LED flashes to indicate GPS waiting for fix 697 | 698 | #ifdef DEBUG 699 | i = (millis() - GPSonTime) / 1000; 700 | Serial.print(F("GPS OnTime ")); 701 | Serial.print(i); 702 | Serial.println(F(" Secs")); 703 | #endif 704 | } 705 | 706 | #endif 707 | 708 | #ifndef DEBUGNoGPS 709 | GPS_On(DoGPSPowerSwitch); 710 | GPS_SetCyclicMode(); //set this regardless of whether hot fix mode is enabled 711 | #endif 712 | 713 | lora_Tone(500, 500, 2); //Transmit an FM tone, 500hz, 500ms, 2dBm 714 | digitalWrite(LED1, LOW); 715 | sleepSecs(2); //wait for GPS to shut down 716 | 717 | #ifdef DEBUGNoGPS 718 | setStatusByte(NoGPSTestMode, 1); 719 | #endif 720 | 721 | } 722 | 723 | -------------------------------------------------------------------------------- /Programs/Tracker_HAB2_FSKRTTYONLY_101017/Tracker_HAB2_FSKRTTYONLY_101017.ino: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // Note: 3 | // 4 | // Make changes to this Program file at your peril 5 | // 6 | // Configuration changes should be made in the HAB2_Settings file not here ! 7 | // 8 | //************************************************************************************************** 9 | 10 | #define programname "Tracker_HAB2_FSKRTTYONLY_101017" 11 | #define aurthorname "Stuart Robinson" 12 | 13 | #include 14 | #include 15 | 16 | #include "Tracker_HAB2_FSKRTTYONLY_Settings.h" 17 | #include Board_Definition 18 | #include "Program_Definitions.h" 19 | 20 | /* 21 | ************************************************************************************************** 22 | 23 | Tracker Programs for Arduino 24 | 25 | Copyright of the author Stuart Robinson 26 | 27 | 28 | 29 | These programs may be used free of charge for personal, recreational and educational purposes only. 30 | 31 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 32 | the explicit permission of the author Stuart Robinson. 33 | 34 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 35 | free from errors. 36 | 37 | Location payload is constructed thus; 38 | 39 | PayloadID,Sequence,Time,Lat,Lon,Alt,Sats,SupplyVolts,Temperature,Resets,Config0byte,StatusByte,RunmAhr,hertzoffset,GPSFixTime,Checksum 40 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 41 | 42 | To Do: 43 | 44 | Changes: 45 | 46 | ************************************************************************************************** 47 | */ 48 | 49 | char ramc_RemoteControlNode; 50 | char ramc_ThisNode; 51 | 52 | int ramc_CalibrationOffset; 53 | 54 | unsigned long ramc_TrackerMode_Frequency; //frequencies, and other parameters, are copied from memory into RAM. 55 | byte ramc_TrackerMode_Power; 56 | byte TRStatus = 0; //used to store current status flag bits 57 | 58 | 59 | byte ramc_Current_TXconfig1; //sets the config of whats transmitted etc 60 | byte stripvalue; 61 | byte sats; //either sats in view from GPGSV or sats from NMEA fix sentence 62 | int internal_temperature; 63 | 64 | 65 | unsigned int ramc_Sleepsecs; //seconds for sleep at end of TX routine 66 | unsigned int ramc_WaitGPSFixSeconds; //in flight mode, default time to wait for a fix 67 | unsigned int ramc_FSKRTTYbaudDelay; //dealy used in FSKRTTY routine to give chosen baud rate 68 | 69 | 70 | float Fence_Check_Lon; //used for fence check 71 | 72 | float TRLat; //tracker transmitter co-ordinates 73 | float TRLon; 74 | unsigned int TRAlt; 75 | 76 | byte ramc_FSKRTTYRegshift; 77 | byte ramc_FSKRTTYpips; 78 | unsigned int ramc_FSKRTTYleadin; 79 | byte ramc_key0; 80 | byte ramc_key1; 81 | byte ramc_key2; 82 | byte ramc_key3; 83 | byte keypress; 84 | 85 | unsigned long GPSonTime; 86 | unsigned long GPSFixTime; 87 | boolean GPS_Config_Error; 88 | 89 | 90 | #include Board_Definition //include previously defined board file 91 | #include Memory_Library //include previously defined Memory Library 92 | 93 | #include 94 | #include //https://github.com/rocketscream/Low-Power 95 | 96 | #include //http://arduiniana.org/libraries/tinygpsplus/ 97 | TinyGPSPlus gps; //create the TinyGPS++ object 98 | TinyGPSCustom GNGGAFIXQ(gps, "GNGGA", 5); //custom sentences used to detect possible switch to GLONASS mode 99 | 100 | #ifdef USE_SOFTSERIAL_GPS 101 | #include //https://github.com/SlashDevin/NeoSWSerial 102 | NeoSWSerial GPSserial(GPSRX, GPSTX); //this library is more relaible at GPS init than software serial 103 | #endif 104 | 105 | #include GPS_Library //include previously defined GPS Library 106 | 107 | #include "Voltage_Temperature.h" 108 | #include "LoRa3.h" 109 | #include "FSK_RTTY3.h" //this version of FSK_RTTY has inverted pips. 110 | #include "Binary2.h" 111 | 112 | 113 | 114 | void loop() 115 | { 116 | Serial.println(); 117 | Serial.println(); 118 | GPSFixTime = 0; 119 | internal_temperature = (int) read_Temperature(); //read temp just after sleep, when CPU is closest to ambient 120 | 121 | GPSonTime = millis(); 122 | gpsWaitFix(ramc_WaitGPSFixSeconds, SwitchOn, LeaveOn); 123 | 124 | #ifdef Use_Test_Location 125 | TRLat = TestLatitude; 126 | TRLon = TestLongitude; 127 | TRAlt = TestAltitude; 128 | #endif 129 | 130 | if (readConfigByte(CheckFence) && (!doFenceCheck())) //if fence check is enabled and tracker is outside fence 131 | { 132 | action_outside_fence(); 133 | } 134 | else //either fence check is disabled or tracker is within it 135 | { 136 | if (readConfigByte(TXEnable)) //is TX enabled ? 137 | { 138 | do_Transmissions(); //yes, so do transmissions 139 | } 140 | else 141 | { 142 | Serial.println(F("TX off")); 143 | inside_fence_no_transmit(); //no, TX is disabled 144 | } 145 | } 146 | 147 | sleepSecs(ramc_Sleepsecs); //this sleep is used to set overall transmission cycle time 148 | 149 | } 150 | 151 | 152 | 153 | 154 | void do_Transmissions() 155 | { 156 | //this is where all the transmisions get sent 157 | byte index, Count; 158 | 159 | pulseWDI(); 160 | lora_Setup(); //resets then sets up LoRa device 161 | 162 | Setup_TrackerMode(); 163 | 164 | incMemoryULong(addr_SequenceNum); //increment sequence number 165 | Count = buildHABPacket(); 166 | stripvalue = readConfigByte(AddressStrip); 167 | 168 | 169 | if (readConfigByte(FSKRTTYEnable)) 170 | { 171 | 172 | Serial.println(F("Send FSKRTTY")); 173 | 174 | lora_DirectSetup(); //set for direct mode 175 | lora_SetFreq(ramc_TrackerMode_Frequency, ramc_CalibrationOffset); 176 | Start_FSKRTTY(FSKRTTYRegshift, FSKRTTYleadin, FSKRTTYpips); 177 | 178 | for (index = 1; index <= sync_chars; index++) 179 | { 180 | Send_FSKRTTY('$', FSKRTTYbaudDelay); 181 | } 182 | 183 | for (index = 0; index <= Count; index++) 184 | { 185 | Send_FSKRTTY(lora_TXBUFF[index], FSKRTTYbaudDelay); 186 | } 187 | Send_FSKRTTY(13, FSKRTTYbaudDelay); //finish RTTY with carriage return 188 | Send_FSKRTTY(10, FSKRTTYbaudDelay); //and line feed 189 | digitalWrite(LED1, LOW); //make sure LED off 190 | 191 | #ifndef ConstantTX 192 | lora_TXOFF(); //turns off transmit 193 | #endif 194 | 195 | } 196 | } 197 | 198 | 199 | byte buildHABPacket() //expects a char buffer, so this routine will not work without the -permissive setting 200 | { 201 | //build the long tracker payload 202 | unsigned int index, j, CRC, resets, runmAhr; 203 | int volts; 204 | byte Count,len; 205 | char LatArray[12], LonArray[12]; 206 | 207 | //unsigned long fixtime; 208 | unsigned long sequence; 209 | 210 | sequence = Memory_ReadULong(addr_SequenceNum); //sequence number is kept in non-volatile memory so it survives resets 211 | resets = Memory_ReadUInt(addr_ResetCount); //reset count is kept in non-volatile memory so it survives resets 212 | 213 | Serial.print("Resets "); 214 | Serial.println(resets); 215 | Serial.print("Temperature "); 216 | Serial.println(internal_temperature); 217 | 218 | runmAhr = 0; 219 | 220 | volts = read_SupplyVoltage(); 221 | 222 | if (!readConfigByte(GPSHotFix)) 223 | { 224 | GPSFixTime = 0; //if GPS power save is off (no GPSHotFix), ensure GPS fix time is set to zero 225 | Serial.println("GPSFixTime set to 0"); 226 | } 227 | 228 | sats = gps.satellites.value(); 229 | dtostrf(TRLat, 7, 5, LatArray); //format is dtostrf(FLOAT,WIDTH,PRECISION,BUFFER); 230 | dtostrf(TRLon, 7, 5, LonArray); //converts float to character array 231 | len = sizeof(lora_TXBUFF); 232 | memset(lora_TXBUFF, 0, len); //clear array to 0s 233 | 234 | Count = snprintf((char*) lora_TXBUFF, 235 | Output_len_max, 236 | "$$$$%s,%lu,%02d:%02d:%02d,%s,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%lu", 237 | Flight_ID, 238 | sequence, 239 | gps.time.hour(), 240 | gps.time.minute(), 241 | gps.time.second(), 242 | LatArray, 243 | LonArray, 244 | TRAlt, 245 | sats, 246 | volts, 247 | internal_temperature, 248 | resets, 249 | ramc_Current_TXconfig1, 250 | TRStatus, 251 | runmAhr, 252 | ramc_CalibrationOffset, 253 | GPSFixTime 254 | ); 255 | 256 | //Count = strlen(lora_TXBUFF); //how long is the array ? 257 | 258 | CRC = 0xffff; //start value for CRC16 259 | 260 | for (index = 4; index < Count; index++) //element 4 is first character after $$ at start 261 | { 262 | CRC ^= (((unsigned int)lora_TXBUFF[index]) << 8); 263 | for (j = 0; j < 8; j++) 264 | { 265 | if (CRC & 0x8000) 266 | CRC = (CRC << 1) ^ 0x1021; 267 | else 268 | CRC <<= 1; 269 | } 270 | } 271 | 272 | lora_TXBUFF[Count++] = '*'; 273 | lora_TXBUFF[Count++] = Hex((CRC >> 12) & 15); //add the checksum bytes to the end 274 | lora_TXBUFF[Count++] = Hex((CRC >> 8) & 15); 275 | lora_TXBUFF[Count++] = Hex((CRC >> 4) & 15); 276 | lora_TXBUFF[Count] = Hex(CRC & 15); 277 | return Count; 278 | } 279 | 280 | 281 | char Hex(byte lchar) 282 | { 283 | //used in CRC calculation in buildHABPacket 284 | char Table[] = "0123456789ABCDEF"; 285 | return Table[lchar]; 286 | } 287 | 288 | 289 | void inside_fence_no_transmit() 290 | { 291 | //null nothing to do 292 | } 293 | 294 | 295 | void action_outside_fence() 296 | { 297 | sleepSecs(outside_fence_Sleep_seconds); //goto sleep for a long time 298 | 299 | } 300 | 301 | 302 | byte doFenceCheck() //checks to see if GPS location is within an Western and Eastern limit 303 | { 304 | //there has been a fix, so check fence limits 305 | Fence_Check_Lon = gps.location.lng(); 306 | 307 | #ifdef DEBUGNoGPS 308 | Fence_Check_Lon = TestLongitude; 309 | #endif 310 | 311 | #ifdef DEBUG 312 | Serial.print(Fence_Check_Lon, 6); 313 | Serial.print(F(" ")); 314 | #endif 315 | 316 | if ((Fence_Check_Lon > west_fence) && (Fence_Check_Lon < east_fence)) //approximate to the limits for region 1 ISM band 317 | { 318 | Serial.println(F("Inside Fence")); 319 | return 1; //within the fence 320 | } 321 | else 322 | { 323 | Serial.println(F("Outside Fence")); 324 | return 0; 325 | } 326 | //outside the fence 327 | } 328 | 329 | 330 | void printPayload(byte lCount) 331 | { 332 | byte index; 333 | for (index = 0; index <= lCount; index++) 334 | { 335 | Serial.write(lora_TXBUFF[index]); 336 | } 337 | } 338 | 339 | 340 | 341 | void printMemoryFrequencies() 342 | { 343 | //a useful check to see if memory is configured correctly 344 | unsigned long tempULong; 345 | tempULong = Memory_ReadULong(addr_TrackerMode_Frequency); 346 | Serial.print(F("Memory Tracker Frequency ")); 347 | Serial.println(tempULong); 348 | 349 | } 350 | 351 | 352 | void printRAMFrequencies() 353 | { 354 | Serial.print(F("RAM Tracker Frequency ")); 355 | Serial.println(ramc_TrackerMode_Frequency); 356 | 357 | Serial.print(F("RAM Calibration Offset ")); 358 | Serial.println(ramc_CalibrationOffset); 359 | } 360 | 361 | 362 | 363 | void sleepSecs(unsigned int LNumberSleeps) 364 | { 365 | unsigned int i; 366 | 367 | Serial.print(F("zz ")); 368 | Serial.println(LNumberSleeps); 369 | Serial.flush(); //let print complete 370 | 371 | #ifdef USING_SERIALGPS 372 | GPSserial.end(); //we dont want GPS input interfering with sleep 373 | #endif 374 | 375 | digitalWrite(lora_NSS, HIGH); //ensure LoRa Device is off 376 | 377 | for (i = 1; i <= LNumberSleeps; i++) 378 | { 379 | LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); //sleep 1 second 380 | pulseWDI(); 381 | } 382 | 383 | } 384 | 385 | 386 | void incMemoryULong(unsigned int laddress) 387 | { 388 | unsigned long val; 389 | val = Memory_ReadULong(laddress); 390 | val++; 391 | Memory_WriteULong(laddress, val); 392 | } 393 | 394 | 395 | byte readConfigByte(byte bitnum) 396 | { 397 | return bitRead(ramc_Current_TXconfig1, bitnum); 398 | } 399 | 400 | 401 | 402 | void setStatusByte(byte bitnum, byte bitval) 403 | { 404 | //program the status byte 405 | 406 | if (bitval == 0) 407 | { 408 | bitClear(TRStatus, bitnum); 409 | } 410 | else 411 | { 412 | bitSet(TRStatus, bitnum); 413 | } 414 | 415 | #ifdef DEBUG 416 | if (bitval) 417 | { 418 | Serial.print(F("Set Status Bit ")); 419 | } 420 | else 421 | { 422 | Serial.print(F("Clear Status Bit ")); 423 | } 424 | 425 | Serial.println(bitnum); 426 | #endif 427 | } 428 | 429 | 430 | void pulseWDI() 431 | { 432 | //if the watchdog is fitted it needs a regular pulse top prevent reset 433 | //togle the WDI pin twice 434 | digitalWrite(WDI, !digitalRead(WDI)); 435 | delayMicroseconds(1); 436 | digitalWrite(WDI, !digitalRead(WDI)); 437 | } 438 | 439 | 440 | boolean gpsWaitFix(unsigned long waitSecs, byte StartState, byte LeaveState) 441 | { 442 | //waits a specified number of seconds for a fix, returns true for good fix 443 | //StartState when set to 1 will turn GPS on at routine start 444 | //LeaveState when set to 0 will turn GPS off at routine end, used perhaps when there is no fix 445 | 446 | unsigned long endwaitmS, millistowait, currentmillis; 447 | pulseWDI(); 448 | byte GPSByte; 449 | 450 | 451 | if (StartState == 1) 452 | { 453 | GPS_On(DoGPSPowerSwitch); 454 | GPSonTime = millis(); 455 | } 456 | else 457 | { 458 | GPS_On(NoGPSPowerSwitch); 459 | } 460 | 461 | #ifdef Check_GPS_Navigation_Model_OK 462 | Serial.println(F("Checking Navigation Model")); 463 | if (!GPS_CheckNavigation()) 464 | { 465 | //something wrong with GPS, navigation mode not set so reconfigure the GPS 466 | Serial.println(F("GPS Configuration Error !!!!")); 467 | GPS_Setup(); 468 | } 469 | #endif 470 | 471 | 472 | Serial.print(F("Wait Fix ")); 473 | Serial.print(waitSecs); 474 | Serial.println(F(" Secs")); 475 | 476 | currentmillis = millis(); 477 | millistowait = waitSecs * 1000; 478 | endwaitmS = currentmillis + millistowait; 479 | 480 | while (millis() < endwaitmS) 481 | { 482 | 483 | do 484 | { 485 | GPSByte = GPS_GetByte(); 486 | if (GPSByte != 0xFF) 487 | { 488 | gps.encode(GPSByte); 489 | } 490 | } 491 | while (GPSByte != 0xFF); 492 | 493 | if (gps.location.isUpdated() && gps.altitude.isUpdated()) 494 | { 495 | Serial.println(F("GPS Fix")); 496 | TRLat = gps.location.lat(); 497 | TRLon = gps.location.lng(); 498 | TRAlt = (unsigned int) gps.altitude.meters(); 499 | 500 | //Altitude is used as an unsigned integer, so that the binary payload is as short as possible. 501 | //However gps.altitude.meters(); can return a negative value which converts to 502 | //65535 - Altitude, which we dont want. So we will assume any value over 60,000M is zero 503 | 504 | if (TRAlt > 60000) 505 | { 506 | TRAlt = 0; 507 | } 508 | 509 | if (readConfigByte(GPSHotFix)) 510 | { 511 | GPS_Off(DoGPSPowerSwitch); 512 | GPSFixTime = (millis() - GPSonTime); 513 | Serial.print(F("GPS Fix Time ")); 514 | Serial.print(GPSFixTime); 515 | Serial.println(F("mS")); 516 | } 517 | else 518 | { 519 | GPS_Off(NoGPSPowerSwitch); 520 | } 521 | 522 | setStatusByte(GPSFix, 1); 523 | pulseWDI(); 524 | return true; 525 | } 526 | 527 | #ifdef UBLOX 528 | if (GNGGAFIXQ.age() < 2000) //check to see if GLONASS has gone active 529 | { 530 | Serial.println(F("GLONASS !")); 531 | setStatusByte(GLONASSisoutput, 1); 532 | GPS_SetGPMode(); 533 | //GPS_SetCyclicMode(); 534 | sleepSecs(1); 535 | } 536 | else 537 | { 538 | setStatusByte(GLONASSisoutput, 0); //GLONASS not detected 539 | } 540 | #endif 541 | 542 | 543 | 544 | } 545 | 546 | //if here then there has been no fix and a timeout 547 | setStatusByte(GPSFix, 0); //set status bit to flag no fix 548 | Serial.println(F("No Fix")); 549 | 550 | if (LeaveState == 0) 551 | { 552 | //no fix and gpsWaitFix called with gpspower to be turned off on exit 553 | GPS_Off(DoGPSPowerSwitch); 554 | } 555 | else 556 | { 557 | //no fix but gpsWaitFix called with gpspower to be left on at exit 558 | GPS_Off(NoGPSPowerSwitch); 559 | } 560 | 561 | pulseWDI(); 562 | return false; 563 | } 564 | 565 | 566 | void readSettingsDefaults() 567 | { 568 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 569 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) in the same way as the transmitter. 570 | //There are some exceptions, where the local programs need to use a setting unique to the particular 571 | //receiver. 572 | Serial.println(F("Config Defaults")); 573 | ramc_TrackerMode_Frequency = TrackerMode_Frequency; 574 | ramc_TrackerMode_Power = TrackerMode_Power; 575 | 576 | ramc_ThisNode = ThisNode; 577 | 578 | ramc_Current_TXconfig1 = Default_config1; 579 | ramc_WaitGPSFixSeconds = WaitGPSFixSeconds; 580 | ramc_Sleepsecs = Loop_Sleepsecs; 581 | 582 | ramc_FSKRTTYbaudDelay = FSKRTTYbaudDelay; 583 | ramc_FSKRTTYRegshift = FSKRTTYRegshift; 584 | ramc_FSKRTTYpips = FSKRTTYpips; 585 | ramc_FSKRTTYleadin = FSKRTTYleadin; 586 | 587 | ramc_CalibrationOffset = CalibrationOffset; 588 | } 589 | 590 | 591 | void readSettingsMemory() 592 | { 593 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 594 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) in the same way as the transmitter. 595 | //There are some exceptions, where the local programs need to use a setting unique to the particular 596 | //receiver. 597 | Serial.println(F("Config from Memory")); 598 | 599 | ramc_TrackerMode_Frequency = Memory_ReadULong(addr_TrackerMode_Frequency); 600 | ramc_TrackerMode_Power = Memory_ReadByte(addr_TrackerMode_Power); 601 | 602 | ramc_ThisNode = Memory_ReadByte(addr_ThisNode);; 603 | 604 | ramc_Current_TXconfig1 = Memory_ReadByte(addr_Default_config1); 605 | ramc_WaitGPSFixSeconds = Memory_ReadUInt(addr_WaitGPSFixSeconds); 606 | ramc_Sleepsecs = Memory_ReadUInt(addr_Sleepsecs); 607 | 608 | ramc_FSKRTTYbaudDelay = Memory_ReadUInt(addr_FSKRTTYbaudDelay); 609 | ramc_FSKRTTYRegshift = Memory_ReadByte(addr_FSKRTTYRegshift); 610 | ramc_FSKRTTYpips = Memory_ReadByte(addr_FSKRTTYpips); 611 | ramc_FSKRTTYleadin = Memory_ReadUInt(addr_FSKRTTYleadin); 612 | ramc_key0 = Memory_ReadByte(addr_key0); 613 | ramc_key1 = Memory_ReadByte(addr_key1); 614 | ramc_key2 = Memory_ReadByte(addr_key2); 615 | ramc_key3 = Memory_ReadByte(addr_key3); 616 | 617 | ramc_CalibrationOffset = Memory_ReadInt(addr_CalibrationOffset); 618 | 619 | readIDMemory(); 620 | } 621 | 622 | 623 | void writeSettingsMemory() 624 | { 625 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 626 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) 627 | 628 | Serial.println(F("Writing RAM Settings to Memory")); 629 | 630 | Memory_Set(addr_StartConfigData, addr_EndConfigData, 0); //fill config area with 0 631 | writeIDMemory(); 632 | 633 | Memory_WriteULong(addr_TrackerMode_Frequency, ramc_TrackerMode_Frequency); 634 | Memory_WriteByte(addr_TrackerMode_Power, ramc_TrackerMode_Power); 635 | 636 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 637 | 638 | Memory_WriteByte(addr_ThisNode, ramc_ThisNode); 639 | 640 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 641 | Memory_WriteUInt(addr_WaitGPSFixSeconds, ramc_WaitGPSFixSeconds); 642 | Memory_WriteUInt(addr_Sleepsecs, ramc_Sleepsecs); 643 | 644 | Memory_WriteUInt(addr_FSKRTTYbaudDelay, ramc_FSKRTTYbaudDelay); 645 | Memory_WriteByte(addr_FSKRTTYRegshift, ramc_FSKRTTYRegshift); 646 | Memory_WriteByte(addr_FSKRTTYpips, ramc_FSKRTTYpips); 647 | Memory_WriteUInt(addr_FSKRTTYleadin, ramc_FSKRTTYleadin); 648 | Memory_WriteByte(addr_key0, ramc_key0); 649 | Memory_WriteByte(addr_key1, ramc_key1); 650 | Memory_WriteByte(addr_key2, ramc_key2); 651 | Memory_WriteByte(addr_key3, ramc_key3); 652 | 653 | Memory_WriteInt(addr_CalibrationOffset, ramc_CalibrationOffset); 654 | } 655 | 656 | 657 | void writeIDMemory() 658 | { 659 | unsigned int i, addr; 660 | byte j; 661 | j = sizeof(Flight_ID); 662 | j--; 663 | addr = addr_FlightID; 664 | for (i = 0; i <= j; i++) 665 | { 666 | Memory_WriteByte(addr, Flight_ID[i]); 667 | addr++; 668 | } 669 | } 670 | 671 | void readIDMemory() 672 | { 673 | unsigned int addr; 674 | byte i; 675 | byte j = 0; 676 | 677 | addr = addr_FlightID; 678 | do 679 | { 680 | i = Memory_ReadByte(addr); 681 | Flight_ID[j++] = i; 682 | addr++; 683 | } 684 | while (i != 0) ; 685 | } 686 | 687 | 688 | void printNodes() 689 | { 690 | Serial.print(F("ThisNode ")); 691 | Serial.print(ramc_ThisNode); 692 | Serial.println(); 693 | } 694 | 695 | 696 | void Setup_TrackerMode() 697 | { 698 | lora_SetFreq(ramc_TrackerMode_Frequency, ramc_CalibrationOffset); 699 | lora_Power = ramc_TrackerMode_Power; 700 | } 701 | 702 | 703 | void display_current_frequency() 704 | { 705 | float freq_temp; 706 | freq_temp = lora_GetFreq(); 707 | Serial.print(F("Frequency ")); 708 | Serial.print(freq_temp, 3); 709 | Serial.println(F("MHz")); 710 | } 711 | 712 | 713 | void led_Flash(unsigned int flashes, unsigned int delaymS) 714 | { 715 | //flash LED to show tracker is alive 716 | unsigned int index; 717 | 718 | for (index = 1; index <= flashes; index++) 719 | { 720 | digitalWrite(LED1, HIGH); 721 | delay(delaymS); 722 | digitalWrite(LED1, LOW); 723 | delay(delaymS); 724 | } 725 | } 726 | 727 | 728 | //******************************************************************************************************* 729 | // Memory Routines 730 | //******************************************************************************************************* 731 | 732 | void do_ClearSavedData() 733 | { 734 | //clears the whole of memory, normally 1kbyte 735 | Serial.println(F("Clear Saved Memory")); 736 | Memory_Set(addr_StartMemory, addr_EndMemory, 0); 737 | } 738 | 739 | 740 | void Clear_All_Memory() 741 | { 742 | //clears the whole of memory, normally 1kbyte 743 | Serial.println(F("Clear All Memory")); 744 | Memory_Set(addr_StartMemory, addr_EndMemory, 0); 745 | } 746 | 747 | 748 | void Print_Config_Memory() 749 | { 750 | //prints the memory used for storing configuration settings 751 | byte memory_LLoopv1; 752 | byte memory_LLoopv2; 753 | unsigned int memory_Laddr = 0; 754 | byte memory_Ldata; 755 | //unsigned int CRC; 756 | Serial.println(F("Config Memory")); 757 | Serial.print(F("Lcn 0 1 2 3 4 5 6 7 8 9 A B C D E F")); 758 | Serial.println(); 759 | 760 | for (memory_LLoopv1 = 0; memory_LLoopv1 <= 15; memory_LLoopv1++) 761 | { 762 | Serial.print(F("0x")); 763 | Serial.print(memory_LLoopv1, HEX); //print the register number 764 | Serial.print(F("0 ")); 765 | for (memory_LLoopv2 = 0; memory_LLoopv2 <= 15; memory_LLoopv2++) 766 | { 767 | memory_Ldata = Memory_ReadByte(memory_Laddr); 768 | if (memory_Ldata < 0x10) { 769 | Serial.print(F("0")); 770 | } 771 | Serial.print(memory_Ldata, HEX); //print the register number 772 | Serial.print(F(" ")); 773 | memory_Laddr++; 774 | } 775 | Serial.println(); 776 | } 777 | } 778 | 779 | 780 | void Print_CRC_Config_Memory() 781 | { 782 | unsigned int returnedCRC = Memory_CRC(addr_StartConfigData, addr_EndConfigData); 783 | Serial.print(F("CRC Config ")); 784 | Serial.println(returnedCRC, HEX); 785 | } 786 | 787 | 788 | unsigned int Print_CRC_Bind_Memory() 789 | { 790 | unsigned int returnedCRC = Memory_CRC(addr_StartBindData, addr_EndBindData); 791 | Serial.print(F("Local Bind CRC ")); 792 | Serial.println(returnedCRC, HEX); 793 | return returnedCRC; 794 | } 795 | 796 | 797 | 798 | //******************************************************************************************************* 799 | 800 | 801 | void setup() 802 | { 803 | unsigned long int i; 804 | unsigned int j; 805 | 806 | pinMode(LED1, OUTPUT); //for PCB LED 807 | pinMode(WDI, OUTPUT); //for Watchdog pulse input 808 | 809 | led_Flash(2, 500); 810 | 811 | Serial.begin(38400); //Setup Serial console ouput 812 | 813 | Memory_Start(); 814 | 815 | #ifdef ClearAllMemory 816 | Clear_All_Memory(); 817 | #endif 818 | 819 | 820 | Serial.println(F(programname)); 821 | Serial.println(F(aurthorname)); 822 | 823 | pinMode(GPSPOWER, OUTPUT); //in case power switching components are fitted 824 | GPS_On(DoGPSPowerSwitch); //this will power the GPSon 825 | GPSonTime = millis(); 826 | 827 | #ifdef USING_SERIALGPS 828 | GPSserial.end(); //but we dont want soft serial running for now, it interferes with the LoRa device 829 | #endif 830 | 831 | pinMode(lora_NReset, OUTPUT); //LoRa device reset line 832 | digitalWrite(lora_NReset, HIGH); 833 | 834 | pinMode (lora_NSS, OUTPUT); //set the slave select pin as an output: 835 | digitalWrite(lora_NSS, HIGH); 836 | 837 | SPI.begin(); //initialize SPI 838 | SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 839 | 840 | 841 | #ifdef ClearSavedData 842 | do_ClearSavedData(); 843 | #endif 844 | 845 | Serial.print(F("Config1 ")); 846 | Serial.println(Default_config1, BIN); 847 | 848 | j = Memory_ReadUInt(addr_ResetCount); 849 | j++; 850 | Memory_WriteUInt(addr_ResetCount, j); 851 | Serial.print(F("Resets ")); 852 | Serial.println(j); 853 | Serial.print(F("Sequence ")); 854 | i = Memory_ReadULong(addr_SequenceNum); 855 | Serial.println(i); 856 | 857 | 858 | #ifdef ConfigureDefaults 859 | readSettingsDefaults(); 860 | writeSettingsMemory(); 861 | #endif 862 | 863 | 864 | #ifdef ConfigureFromMemory 865 | readSettingsMemory(); 866 | #endif 867 | 868 | Print_CRC_Config_Memory(); 869 | 870 | ramc_ThisNode = ThisNode; 871 | 872 | #ifdef DEBUG 873 | printNodes(); 874 | #endif 875 | 876 | lora_Setup(); 877 | 878 | if (!lora_CheckDevice()) 879 | { 880 | led_Flash(100, 50); //long medium speed flash for Lora device error 881 | Serial.println(F("LoRa Error!")); 882 | } 883 | 884 | #ifdef DEBUG 885 | display_current_frequency(); 886 | #endif 887 | 888 | ramc_CalibrationOffset = Memory_ReadInt(addr_CalibrationOffset); //get calibration offset for this tracker 889 | Serial.print(F("Cal Offset ")); 890 | Serial.println(ramc_CalibrationOffset); 891 | 892 | #ifdef DEBUG 893 | lora_Print(); 894 | #endif 895 | 896 | Serial.println(); 897 | print_SupplyVoltage(); 898 | print_Temperature(); 899 | Serial.println(); 900 | 901 | j = read_SupplyVoltage(); //get supply mV 902 | Write_Int(0, j, lora_TXBUFF); //write to first two bytes of buffer 903 | Write_Byte(2, ramc_Current_TXconfig1, lora_TXBUFF); //add the current config byte 904 | 905 | Setup_TrackerMode(); 906 | sleepSecs(1); 907 | 908 | Setup_TrackerMode(); //so that check tone is at correct frequency 909 | 910 | GPS_Config_Error = false; //make sure GPS error flag is cleared 911 | 912 | #ifndef DEBUGNoGPS 913 | GPS_On(DoGPSPowerSwitch); //GPS should have been on for a while by now, so this is just to start soft serial 914 | GPSonTime = millis(); 915 | GPS_Setup(); //GPS should have had plenty of time to initialise by now 916 | 917 | #ifdef UBLOX 918 | if (!GPS_CheckNavigation()) //Check that UBLOX GPS is in Navigation model 6 919 | { 920 | Serial.println(); 921 | GPS_Config_Error = true; 922 | setStatusByte(GPSError, 1); 923 | setStatusByte(UBLOXDynamicModel6Set, 0); 924 | } 925 | else 926 | { 927 | setStatusByte(UBLOXDynamicModel6Set, 1); 928 | } 929 | #endif 930 | 931 | if (GPS_Config_Error) 932 | { 933 | Serial.println(F("Warning GPS Error !")); 934 | Serial.println(); 935 | led_Flash(100, 25); //long very rapid flash for GPS error 936 | } 937 | else 938 | { 939 | #ifdef CheckTone 940 | if (readConfigByte(TXEnable)) //is TX enabled - needed because of fence limits 941 | { 942 | Serial.println(F("Check Tone")); //check tone indicates navigation model 6 set (if checktone enabled!) 943 | lora_Tone(1000, 3000, 5); //Transmit an FM tone, 1000hz, 3000ms, 5dBm 944 | } 945 | #endif 946 | } 947 | 948 | digitalWrite(LED1, HIGH); 949 | setStatusByte(NoGPSTestMode, 0); 950 | GPSonTime = millis(); 951 | while (!gpsWaitFix(5, DontSwitch, LeaveOn)) //while there is no fix 952 | { 953 | 954 | led_Flash(2, 50); //two short LED flashes to indicate GPS waiting for fix 955 | 956 | #ifdef DEBUG 957 | i = (millis() - GPSonTime) / 1000; 958 | Serial.print(F("GPS On Time ")); 959 | Serial.print(i); 960 | Serial.println(F(" Secs")); 961 | #endif 962 | } 963 | 964 | #endif 965 | 966 | #ifndef DEBUGNoGPS 967 | GPS_On(DoGPSPowerSwitch); 968 | GPS_SetCyclicMode(); //set this regardless of whether hot fix mode is enabled 969 | #endif 970 | 971 | 972 | lora_Tone(500, 500, 2); //Transmit an FM tone, 500hz, 500ms, 2dBm 973 | digitalWrite(LED1, LOW); 974 | sleepSecs(2); //wait for GPS to shut down 975 | 976 | #ifdef DEBUGNoGPS 977 | setStatusByte(NoGPSTestMode, 1); 978 | #endif 979 | 980 | } 981 | 982 | 983 | 984 | 985 | 986 | 987 | -------------------------------------------------------------------------------- /Programs/Tracker_GPSBeacon_Beta_101017/Tracker_GPSBeacon_Beta_101017.ino: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // Note: 3 | // 4 | // Make changes to this Program file at your peril 5 | // 6 | // Configuration changes should be made in the HAB2_Settings file not here ! 7 | // 8 | //************************************************************************************************** 9 | 10 | #define programname "Tracker_GPSBeacon_Beta_101017" 11 | #define aurthorname "Stuart Robinson" 12 | 13 | #include 14 | #include 15 | 16 | #include "Tracker_GPSBeacon_Settings.h" 17 | #include Board_Definition 18 | #include "Program_Definitions.h" 19 | 20 | /* 21 | ************************************************************************************************** 22 | 23 | Tracker Programs for Arduino 24 | 25 | Copyright of the author Stuart Robinson 26 | 27 | 28 | 29 | These programs may be used free of charge for personal, recreational and educational purposes only. 30 | 31 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 32 | the explicit permission of the author Stuart Robinson. 33 | 34 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 35 | free from errors. 36 | 37 | This is a simple GPS locator beacon, the GPS is read and the current location sent the specified period. The beacon can 38 | optionally transmit a ready to send command packet, so it would be possible the remote control the beacon. 39 | 40 | Changes: 41 | 42 | ************************************************************************************************** 43 | */ 44 | 45 | char ramc_RemoteControlNode; 46 | char ramc_ThisNode; 47 | 48 | int ramc_CalibrationOffset; 49 | 50 | unsigned long ramc_TrackerMode_Frequency; //frequencies, and other parameters, are copied from memory into RAM. 51 | unsigned long ramc_CommandMode_Frequency; //copied into memory so that they survive reset. 52 | 53 | uint8_t ramc_TrackerMode_Bandwidth; 54 | uint8_t ramc_TrackerMode_SpreadingFactor; 55 | uint8_t ramc_TrackerMode_CodeRate; 56 | uint8_t ramc_TrackerMode_Power; 57 | uint8_t TRStatus = 0; //used to store current status flag bits 58 | 59 | uint8_t ramc_CommandMode_Bandwidth; 60 | uint8_t ramc_CommandMode_SpreadingFactor; 61 | uint8_t ramc_CommandMode_CodeRate; 62 | uint8_t ramc_CommandMode_Power; 63 | 64 | uint8_t ramc_Current_TXconfig1; //sets the config of whats transmitted etc 65 | uint8_t ramc_Cmd_WaitSecs; 66 | uint8_t stripvalue; 67 | uint8_t sats; //either sats in view from GPGSV or sats from NMEA fix sentence 68 | int internal_temperature; 69 | 70 | boolean GPS_Config_Error; 71 | uint16_t ramc_Sleepsecs; //seconds for sleep at end of TX routine 72 | uint16_t ramc_WaitGPSFixSeconds; //in flight mode, default time to wait for a fix 73 | 74 | float TRLat; //tracker transmitter co-ordinates 75 | float TRLon; 76 | uint16_t TRAlt; 77 | 78 | uint8_t ramc_promiscuous_Mode; 79 | uint8_t ramc_key0; 80 | uint8_t ramc_key1; 81 | uint8_t ramc_key2; 82 | uint8_t ramc_key3; 83 | uint8_t keypress; 84 | 85 | 86 | #include Board_Definition //include previously defined board file 87 | #include Memory_Library //include previously defined Memory Library 88 | 89 | #include 90 | #include //https://github.com/rocketscream/Low-Power 91 | 92 | #include //http://arduiniana.org/libraries/tinygpsplus/ 93 | TinyGPSPlus gps; //create the TinyGPS++ object 94 | TinyGPSCustom GNGGAFIXQ(gps, "GNGGA", 5); //custom sentences used to detect possible switch to GLONASS mode 95 | 96 | #ifdef USE_SOFTSERIAL_GPS 97 | #include //https://github.com/SlashDevin/NeoSWSerial 98 | NeoSWSerial GPSserial(GPSRX, GPSTX); //this library is more relaible at GPS init than software serial 99 | #endif 100 | 101 | #include GPS_Library //include previously defined GPS Library 102 | 103 | #include "Voltage_Temperature.h" 104 | #include "LoRa4.h" 105 | #include "Binary2.h" 106 | 107 | 108 | 109 | void loop() 110 | { 111 | Serial.println(); 112 | Serial.println(); 113 | 114 | 115 | #ifndef DEBUGNoGPS 116 | gpsWaitFix(ramc_WaitGPSFixSeconds, SwitchOn, LeaveOn); 117 | #endif 118 | 119 | #ifdef Use_Test_Location 120 | TRLat = TestLatitude; 121 | TRLon = TestLongitude; 122 | TRAlt = TestAltitude; 123 | #endif 124 | 125 | do_Transmissions(); 126 | 127 | sleepSecs(1); 128 | 129 | #ifdef Accept_Commands 130 | wait_Command(); //wait for incoming command 131 | #endif 132 | 133 | digitalWrite(lora_NSS, HIGH); //take NSS line high, makes sure LoRa device is off 134 | sleepSecs(ramc_Sleepsecs); //this sleep is used to set overall transmission cycle time 135 | } 136 | 137 | 138 | void wait_Command() 139 | { 140 | uint8_t index; 141 | pulseWDI(); 142 | lora_Setup(); //resets then sets up LoRa device 143 | Setup_LoRaCommandMode(); //commands can be sent in any mode, make sure this is sent using the right frequency etc 144 | send_Command(ClearToSendCommand); //indicate ready for command 145 | 146 | lora_RXPacketType = 0; //use as flag to tell if anything received during listen 147 | Listen(Cmd_WaitSecs); //wait for command packet 148 | 149 | if (lora_RXPacketType > 0) 150 | { 151 | do 152 | { 153 | //there was activity during previous listen 154 | lora_RXPacketType = 0; 155 | 156 | for (index = 1; index <= Command_Loops; index++) 157 | { 158 | Setup_LoRaCommandMode(); //commands can be sent in any mode, make sure this is sent using the right frequency etc 159 | send_Command(ClearToSendCommand); 160 | Listen(Cmd_WaitSecs); 161 | } 162 | 163 | } while (lora_RXPacketType > 0); //wait until the extended listen exits with no packet received 164 | 165 | } 166 | else 167 | { 168 | Serial.println(F("No RX")); 169 | } 170 | } 171 | 172 | 173 | void do_Transmissions() 174 | { 175 | //this is where all the transmisions get sent 176 | 177 | pulseWDI(); 178 | lora_Setup(); //resets then sets up LoRa device 179 | Setup_TrackerMode(); 180 | send_LocationBinary(TRLat, TRLon, TRAlt); 181 | } 182 | 183 | 184 | void send_LocationBinary(float Lat, float Lon, uint16_t Alt) 185 | { 186 | Write_Float(0, Lat, lora_TXBUFF); 187 | Write_Float(4, Lon, lora_TXBUFF); 188 | Write_Int(8, Alt, lora_TXBUFF); 189 | Write_Byte(10, TRStatus, lora_TXBUFF); 190 | 191 | digitalWrite(LED1, HIGH); 192 | Serial.println(F("Send Binary Location")); 193 | lora_Send(0, 10, LocationBinaryPacket, Broadcast, ramc_ThisNode, 10, lora_Power, 0); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd 194 | digitalWrite(LED1, LOW); 195 | } 196 | 197 | 198 | 199 | void Listen(uint16_t seconds) 200 | { 201 | //listen (in seconds) for an incoming packet using the current frequency and LoRa modem settings 202 | unsigned long tilltime; 203 | tilltime = (millis() + (seconds * 1000)); 204 | Serial.print(F("Listen ")); 205 | Serial.println(seconds); 206 | 207 | lora_RXONLoRa(); 208 | 209 | while (millis() < tilltime) 210 | { 211 | checkForPacket(); 212 | } 213 | lora_RXOFF(); //as we have finished listening 214 | } 215 | 216 | 217 | void checkForPacket() 218 | { 219 | //check LoRa device to see if a command packet has arrived 220 | uint8_t lora_Ltemp; 221 | 222 | lora_Ltemp = lora_readRXready(); 223 | 224 | if (lora_Ltemp > 0) 225 | { 226 | 227 | Serial.print(F("RX ")); 228 | 229 | if (lora_Ltemp == 64) 230 | { 231 | //packet has arrived 232 | lora_ReadPacket(); 233 | 234 | Serial.write(lora_RXPacketType); 235 | Serial.write(lora_RXDestination); 236 | Serial.write(lora_RXSource); 237 | Serial.println(); 238 | } 239 | else 240 | { 241 | //packet arrived with error 242 | Serial.println(F("Error")); 243 | lora_RXOFF(); 244 | lora_RXONLoRa(); 245 | } 246 | 247 | if (promiscuous_Mode) //can we accept packet from any source 248 | { 249 | processPacket(); 250 | lora_RXONLoRa(); 251 | } 252 | 253 | if (!promiscuous_Mode) //can we only accepts packet from known node 254 | { 255 | if (lora_RXSource == ramc_RemoteControlNode) 256 | { 257 | processPacket(); 258 | lora_RXONLoRa(); //ready for next and clear flags 259 | } 260 | else 261 | { 262 | Serial.println(F("Rejected")); 263 | lora_RXOFF(); 264 | Setup_LoRaCommandMode(); 265 | send_Command(NACK); 266 | lora_RXONLoRa(); 267 | } 268 | } 269 | } 270 | } 271 | 272 | 273 | void processPacket() 274 | { 275 | //we have a packet so lets decide what to do with it 276 | uint8_t i, j; 277 | 278 | if (lora_RXPacketType == Test) 279 | { 280 | if (lora_RXBUFF[0] == '0') 281 | { 282 | Serial.println(F("Pkt Test")); 283 | delay(inter_Packet_delay); 284 | Setup_LoRaCommandMode(); 285 | send_Command(ACK); 286 | delay(inter_Packet_delay); 287 | sendTest(); 288 | } 289 | } 290 | 291 | if (lora_RXPacketType == LinkReport) 292 | { 293 | send_Command(ACK); 294 | delay(inter_Packet_delay); 295 | Serial.println(F("Link Report")); 296 | delay(inter_Packet_delay); 297 | Setup_LoRaCommandMode(); 298 | send_Command(Info); 299 | } 300 | 301 | 302 | if (lora_RXPacketType == Config0) //is it a change config uint8_t request ? 303 | { 304 | Serial.println(F("Prog Cfgbyte")); 305 | 306 | i = ((lora_RXBUFF[0] - 48)); //config uint8_t requests come in as ASCCI, '1' for 1 etc 307 | j = ((lora_RXBUFF[1] - 48)); 308 | setConfigByte(i, j); 309 | lora_RXBuffPrint(0); //print packet contents as ASCII 310 | Serial.println(); 311 | delay(inter_Packet_delay); 312 | Setup_LoRaCommandMode(); 313 | send_Command(ACK); //send the ack 314 | 315 | } 316 | 317 | if (lora_RXPacketType == ResetTracker) //is it a reset ? 318 | { 319 | Serial.println(F("Reset ?")); 320 | lora_RXBuffPrint(0); //print packet contents as ASCII 321 | Serial.println(); 322 | 323 | if ( isKeyValid() ) 324 | { 325 | Serial.println(F("Valid")); 326 | delay(inter_Packet_delay); 327 | Setup_LoRaCommandMode(); 328 | send_Command(ACK); 329 | Serial.flush(); 330 | sleepSecs(2); 331 | softReset(); 332 | } 333 | else 334 | { 335 | Serial.println(F("Invalid")); 336 | delay(inter_Packet_delay); 337 | Setup_LoRaCommandMode(); 338 | send_Command(NACK); 339 | } 340 | } 341 | 342 | if (lora_RXPacketType == WritePacketMemory) 343 | { 344 | Serial.println(F("Write Memory")); 345 | writePacketMemory(); 346 | delay(inter_Packet_delay); 347 | Setup_LoRaCommandMode(); 348 | send_Command(ACK); 349 | } 350 | 351 | if (lora_RXPacketType == INCFreq) 352 | { 353 | Serial.println(F("IncOffset 1KHZ")); 354 | ramc_CalibrationOffset = ramc_CalibrationOffset + 1000; 355 | delay(inter_Packet_delay); 356 | Setup_LoRaCommandMode(); 357 | send_Command(ACK); 358 | Memory_WriteInt(addr_CalibrationOffset, ramc_CalibrationOffset); 359 | } 360 | 361 | if (lora_RXPacketType == DECFreq) 362 | { 363 | Serial.println(F("DecOffset 1KHZ")); 364 | ramc_CalibrationOffset = ramc_CalibrationOffset - 1000; 365 | delay(inter_Packet_delay); 366 | Setup_LoRaCommandMode(); 367 | send_Command(ACK); 368 | Memory_WriteInt(addr_CalibrationOffset, ramc_CalibrationOffset); 369 | } 370 | 371 | } 372 | 373 | 374 | 375 | 376 | void printMemoryFrequencies() 377 | { 378 | //a useful check to see if memory is configured correctly 379 | unsigned long tempULong; 380 | tempULong = Memory_ReadULong(addr_TrackerMode_Frequency); 381 | Serial.print(F("Memory Tracker Freq ")); 382 | Serial.println(tempULong); 383 | 384 | tempULong = Memory_ReadULong(addr_CommandMode_Frequency); 385 | Serial.print(F("Memory Command Freq ")); 386 | Serial.println(tempULong); 387 | } 388 | 389 | 390 | boolean isKeyValid() 391 | { 392 | if ( (lora_RXBUFF[0] == key0) && (lora_RXBUFF[1] == key1) && (lora_RXBUFF[2] == key2) && (lora_RXBUFF[3] == key3) ) 393 | { 394 | return true; 395 | } 396 | else 397 | { 398 | return false; 399 | } 400 | } 401 | 402 | 403 | void softReset() 404 | { 405 | asm volatile (" jmp 0"); 406 | } 407 | 408 | 409 | void send_Command(char cmd) 410 | { 411 | uint16_t volts; 412 | volts = read_SupplyVoltage(); 413 | Serial.print(F("Send Cmd ")); 414 | Serial.write(cmd); 415 | Serial.println(); 416 | Write_Byte(0, lora_PacketSNR, lora_TXBUFF); //so that receiver alwsys knows last received SNR 417 | Write_Byte(1, lora_PacketRSSI, lora_TXBUFF); //so that receiver alwsys knows last received RSSI 418 | Write_UInt(2, volts, lora_TXBUFF); 419 | Write_Byte(4, TRStatus, lora_TXBUFF); 420 | digitalWrite(LED1, HIGH); 421 | lora_Send(0, 4, cmd, Broadcast, ramc_ThisNode, 10, lora_Power, 0); 422 | digitalWrite(LED1, LOW); 423 | } 424 | 425 | 426 | void sendTest() 427 | { 428 | uint8_t power; 429 | for (power = 10; power >= 2; power--) 430 | { 431 | Setup_TrackerMode(); 432 | lora_TXBUFF[0] = '0'; 433 | lora_TXBUFF[1] = power + 48; 434 | lora_TXEnd = 1; 435 | 436 | if (power == 10) 437 | { 438 | lora_TXBUFF[0] = '1'; 439 | lora_TXBUFF[1] = '0'; 440 | lora_TXEnd = 2; 441 | } 442 | 443 | Serial.print(F("Send ")); 444 | Serial.print(power); 445 | Serial.println(F("dBm")); 446 | 447 | lora_Send(0, 1, Test, Broadcast, ramc_ThisNode, 10, power, 0); //send the test packet 448 | sleepSecs(2); 449 | } 450 | } 451 | 452 | void sleepSecs(uint16_t LNumberSleeps) 453 | { 454 | uint16_t i; 455 | 456 | Serial.print(F("zz ")); 457 | Serial.println(LNumberSleeps); 458 | Serial.flush(); //let print complete 459 | #ifdef USING_SERIALGPS 460 | GPSserial.end(); //we dont want GPS input interfering with sleep, make sure its off 461 | #endif 462 | digitalWrite(lora_NSS, HIGH); //ensure LoRa Device is off 463 | 464 | for (i = 1; i <= LNumberSleeps; i++) 465 | { 466 | LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); //sleep 1 second 467 | pulseWDI(); 468 | } 469 | } 470 | 471 | 472 | void incMemoryULong(uint16_t laddress) 473 | { 474 | unsigned long val; 475 | val = Memory_ReadULong(laddress); 476 | val++; 477 | Memory_WriteULong(laddress, val); 478 | } 479 | 480 | 481 | uint8_t readConfigByte(uint8_t bitnum) 482 | { 483 | return bitRead(ramc_Current_TXconfig1, bitnum); 484 | } 485 | 486 | 487 | void setConfigByte(uint8_t bitnum, uint8_t bitval) 488 | { 489 | //program the config byte 490 | 491 | if (bitval == 0) 492 | { 493 | bitClear(ramc_Current_TXconfig1, bitnum); 494 | } 495 | else 496 | { 497 | bitSet(ramc_Current_TXconfig1, bitnum); 498 | } 499 | 500 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 501 | 502 | } 503 | 504 | 505 | void setStatusByte(uint8_t bitnum, uint8_t bitval) 506 | { 507 | //program the status byte 508 | 509 | if (bitval == 0) 510 | { 511 | bitClear(TRStatus, bitnum); 512 | } 513 | else 514 | { 515 | bitSet(TRStatus, bitnum); 516 | } 517 | 518 | } 519 | 520 | 521 | void pulseWDI() 522 | { 523 | //if the watchdog is fitted it needs a regular pulse top prevent reset 524 | //togle the WDI pin twice 525 | digitalWrite(WDI, !digitalRead(WDI)); 526 | delayMicroseconds(1); 527 | digitalWrite(WDI, !digitalRead(WDI)); 528 | } 529 | 530 | 531 | boolean gpsWaitFix(unsigned long waitSecs, uint8_t StartState, uint8_t LeaveState) 532 | { 533 | //waits a specified number of seconds for a fix, returns true for good fix 534 | //StartState when set to 1 will turn GPS on at routine start 535 | //LeaveState when set to 0 will turn GPS off at routine end, used perhaps when there is no fix 536 | 537 | uint32_t endwaitmS, millistowait, currentmillis; 538 | pulseWDI(); 539 | uint8_t GPSByte; 540 | //ong temp; 541 | 542 | if (StartState == 1) 543 | { 544 | GPS_On(DoGPSPowerSwitch); 545 | } 546 | else 547 | { 548 | GPS_On(NoGPSPowerSwitch); 549 | } 550 | 551 | Serial.print(F("Wait Fix ")); 552 | Serial.print(waitSecs); 553 | Serial.println(F(" Secs")); 554 | 555 | currentmillis = millis(); 556 | millistowait = waitSecs * 1000; 557 | endwaitmS = currentmillis + millistowait; 558 | 559 | while (millis() < endwaitmS) 560 | { 561 | 562 | do 563 | { 564 | GPSByte = GPS_GetByte(); 565 | if (GPSByte != 0xFF) 566 | { 567 | gps.encode(GPSByte); 568 | } 569 | } 570 | while (GPSByte != 0xFF); 571 | 572 | if (gps.location.isUpdated() && gps.altitude.isUpdated()) 573 | { 574 | Serial.println(F("GPS Fix")); 575 | TRLat = gps.location.lat(); 576 | TRLon = gps.location.lng(); 577 | TRAlt = (uint16_t) gps.altitude.meters(); 578 | 579 | //Altitude is used as an unsigned integer, so that the binary payload is as short as possible. 580 | //However gps.altitude.meters(); can return a negative value which converts to 581 | //65535 - Altitude, which we dont want. So we will assume any value over 60,000M is zero 582 | 583 | if (TRAlt > 60000) 584 | { 585 | TRAlt = 0; 586 | } 587 | 588 | if (readConfigByte(GPSHotFix)) 589 | { 590 | GPS_Off(DoGPSPowerSwitch); 591 | } 592 | else 593 | { 594 | GPS_Off(NoGPSPowerSwitch); 595 | } 596 | 597 | setStatusByte(GPSFix, 1); 598 | pulseWDI(); 599 | return true; 600 | } 601 | 602 | #ifdef UBLOX 603 | if (GNGGAFIXQ.age() < 2000) //check to see if GLONASS has gone active 604 | { 605 | Serial.println(F("GLONASS !")); 606 | setStatusByte(GLONASSisoutput, 1); 607 | GPS_SetGPMode(); 608 | GPS_SetCyclicMode(); 609 | sleepSecs(1); 610 | } 611 | else 612 | { 613 | setStatusByte(GLONASSisoutput, 0); //GLONASS not detected 614 | } 615 | #endif 616 | 617 | 618 | 619 | } 620 | 621 | //if here then there has been no fix and a timeout 622 | setStatusByte(GPSFix, 0); //set status bit to flag no fix 623 | Serial.println(F("No Fix")); 624 | 625 | if (LeaveState == 0) 626 | { 627 | //no fix and gpsWaitFix called with gpspower to be turned off on exit 628 | GPS_Off(DoGPSPowerSwitch); 629 | } 630 | else 631 | { 632 | //no fix but gpsWaitFix called with gpspower to be left on at exit 633 | GPS_Off(NoGPSPowerSwitch); 634 | } 635 | 636 | pulseWDI(); 637 | return false; 638 | } 639 | 640 | 641 | void readSettingsDefaults() 642 | { 643 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 644 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) in the same way as the transmitter. 645 | //There are some exceptions, where the local programs need to use a setting unique to the particular 646 | //receiver. 647 | Serial.println(F("Config Defaults")); 648 | ramc_TrackerMode_Frequency = TrackerMode_Frequency; 649 | ramc_TrackerMode_Bandwidth = TrackerMode_Bandwidth; 650 | ramc_TrackerMode_SpreadingFactor = TrackerMode_SpreadingFactor; 651 | ramc_TrackerMode_CodeRate = TrackerMode_CodeRate; 652 | ramc_TrackerMode_Power = TrackerMode_Power; 653 | 654 | ramc_CommandMode_Frequency = CommandMode_Frequency; 655 | ramc_CommandMode_Bandwidth = CommandMode_Bandwidth; 656 | ramc_CommandMode_SpreadingFactor = CommandMode_SpreadingFactor; 657 | ramc_CommandMode_CodeRate = CommandMode_CodeRate; 658 | ramc_CommandMode_Power = CommandMode_Power; 659 | 660 | ramc_ThisNode = ThisNode; 661 | ramc_RemoteControlNode = RemoteControlNode; 662 | 663 | ramc_Current_TXconfig1 = Default_config1; 664 | ramc_Cmd_WaitSecs = Cmd_WaitSecs; 665 | ramc_WaitGPSFixSeconds = WaitGPSFixSeconds; 666 | ramc_Sleepsecs = Loop_Sleepsecs; 667 | ramc_promiscuous_Mode = promiscuous_Mode; 668 | 669 | ramc_key0 = key0; 670 | ramc_key1 = key1; 671 | ramc_key2 = key2; 672 | ramc_key3 = key3; 673 | 674 | ramc_CalibrationOffset = CalibrationOffset; 675 | } 676 | 677 | 678 | void readSettingsMemory() 679 | { 680 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 681 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) in the same way as the transmitter. 682 | //There are some exceptions, where the local programs need to use a setting unique to the particular 683 | //receiver. 684 | Serial.println(F("Config from Memory")); 685 | 686 | ramc_TrackerMode_Frequency = Memory_ReadULong(addr_TrackerMode_Frequency); 687 | ramc_TrackerMode_Bandwidth = Memory_ReadByte(addr_TrackerMode_Bandwidth); 688 | ramc_TrackerMode_SpreadingFactor = Memory_ReadByte(addr_TrackerMode_SpreadingFactor); 689 | ramc_TrackerMode_CodeRate = Memory_ReadByte(addr_TrackerMode_CodeRate); 690 | ramc_TrackerMode_Power = Memory_ReadByte(addr_TrackerMode_Power); 691 | 692 | ramc_CommandMode_Frequency = Memory_ReadULong(addr_CommandMode_Frequency); 693 | ramc_CommandMode_Bandwidth = Memory_ReadByte(addr_CommandMode_Bandwidth); 694 | ramc_CommandMode_SpreadingFactor = Memory_ReadByte(addr_CommandMode_SpreadingFactor); 695 | ramc_CommandMode_CodeRate = Memory_ReadByte(addr_CommandMode_CodeRate); 696 | ramc_CommandMode_Power = Memory_ReadByte(addr_CommandMode_Power); 697 | 698 | ramc_ThisNode = Memory_ReadByte(addr_ThisNode);; 699 | ramc_RemoteControlNode = Memory_ReadByte(addr_RemoteControlNode);; 700 | 701 | ramc_Current_TXconfig1 = Memory_ReadByte(addr_Default_config1); 702 | ramc_Cmd_WaitSecs = Memory_ReadByte(addr_Cmd_WaitSecs); 703 | ramc_WaitGPSFixSeconds = Memory_ReadUInt(addr_WaitGPSFixSeconds); 704 | ramc_Sleepsecs = Memory_ReadUInt(addr_Sleepsecs); 705 | ramc_promiscuous_Mode = Memory_ReadByte(addr_promiscuous_Mode); 706 | 707 | ramc_key0 = Memory_ReadByte(addr_key0); 708 | ramc_key1 = Memory_ReadByte(addr_key1); 709 | ramc_key2 = Memory_ReadByte(addr_key2); 710 | ramc_key3 = Memory_ReadByte(addr_key3); 711 | 712 | ramc_CalibrationOffset = Memory_ReadInt(addr_CalibrationOffset); 713 | 714 | } 715 | 716 | 717 | void writeSettingsMemory() 718 | { 719 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 720 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) 721 | 722 | Serial.println(F("Write RAM Settings to Memory")); 723 | 724 | Memory_Set(addr_StartConfigData, addr_EndConfigData, 0); //fill config area with 0 725 | 726 | Memory_WriteULong(addr_TrackerMode_Frequency, ramc_TrackerMode_Frequency); 727 | Memory_WriteByte(addr_TrackerMode_Bandwidth, ramc_TrackerMode_Bandwidth); 728 | Memory_WriteByte(addr_TrackerMode_SpreadingFactor, ramc_TrackerMode_SpreadingFactor); 729 | Memory_WriteByte(addr_TrackerMode_CodeRate, ramc_TrackerMode_CodeRate); 730 | Memory_WriteByte(addr_TrackerMode_Power, ramc_TrackerMode_Power); 731 | 732 | Memory_WriteULong(addr_CommandMode_Frequency, ramc_CommandMode_Frequency); 733 | Memory_WriteByte(addr_CommandMode_Bandwidth, ramc_CommandMode_Bandwidth); 734 | Memory_WriteByte(addr_CommandMode_SpreadingFactor, ramc_CommandMode_SpreadingFactor); 735 | Memory_WriteByte(addr_CommandMode_CodeRate, ramc_CommandMode_CodeRate); 736 | Memory_WriteByte(addr_CommandMode_Power, ramc_CommandMode_Power); 737 | 738 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 739 | Memory_WriteByte(addr_RemoteControlNode, ramc_RemoteControlNode); 740 | 741 | Memory_WriteByte(addr_ThisNode, ramc_ThisNode); 742 | Memory_WriteByte(addr_RemoteControlNode, ramc_RemoteControlNode); 743 | 744 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 745 | Memory_WriteByte(addr_Cmd_WaitSecs, ramc_Cmd_WaitSecs); 746 | Memory_WriteUInt(addr_WaitGPSFixSeconds, ramc_WaitGPSFixSeconds); 747 | Memory_WriteUInt(addr_Sleepsecs, ramc_Sleepsecs); 748 | Memory_WriteByte(addr_promiscuous_Mode, ramc_promiscuous_Mode); 749 | 750 | Memory_WriteByte(addr_key0, ramc_key0); 751 | Memory_WriteByte(addr_key1, ramc_key1); 752 | Memory_WriteByte(addr_key2, ramc_key2); 753 | Memory_WriteByte(addr_key3, ramc_key3); 754 | 755 | Memory_WriteInt(addr_CalibrationOffset, ramc_CalibrationOffset); 756 | } 757 | 758 | 759 | void saveKeyin_buffer() 760 | { 761 | lora_TXBUFF[0] = key0; //key used in sme packets to reduce chances of a change being applied by accident 762 | lora_TXBUFF[1] = key1; 763 | lora_TXBUFF[2] = key2; 764 | lora_TXBUFF[3] = key3; 765 | } 766 | 767 | 768 | void printMemoryChange(uint8_t number) 769 | { 770 | uint8_t index, j; 771 | Serial.print(F("Memory Change")); 772 | for (index = 0; index <= number; index++) 773 | { 774 | j = lora_RXBUFF[index]; 775 | Serial.print(F(" ")); 776 | Serial.print(j, HEX); 777 | } 778 | Serial.println(); 779 | } 780 | 781 | 782 | void writePacketMemory() 783 | { 784 | //there is an incoming packet which is a request to write bytes to Memory. 785 | //the effect is to change stored program definitions and constants 786 | uint8_t i, j, k, ptr; 787 | //uint8_t i, j, k, ptr, low, high; 788 | uint16_t addr_Memory; 789 | //float tempfloat; 790 | 791 | //packet format is key0, key1, key2, key3, number of bytes to write, address to write to, bytes to write 792 | //terminate list with 0 bytes to write. 793 | 794 | if (isKeyValid()) 795 | { 796 | Serial.print(F("Not Valid")); 797 | return; 798 | } 799 | 800 | i = lora_RXPacketL - 4; //end of packet will be length - 1 for 0 offset and -3 for adddress bytes 801 | 802 | printMemoryChange(i); 803 | 804 | ptr = 4; 805 | 806 | j = lora_RXBUFF[ptr++]; 807 | 808 | addr_Memory = Read_Int(5, lora_RXBUFF); //read address for frequency offset into buffer 809 | 810 | ptr++; 811 | ptr++; 812 | 813 | Serial.println(F("Write memory ")); 814 | 815 | for (i = 1; i <= j; i++) 816 | { 817 | Memory_WriteByte(addr_Memory, lora_RXBUFF[ptr]); 818 | k = lora_RXBUFF[ptr]; 819 | Serial.print(k, HEX); 820 | Serial.print(F(" ")); 821 | addr_Memory++; 822 | ptr++; 823 | } 824 | readSettingsMemory(); 825 | Setup_TrackerMode(); //dummy change so we can see if offset chnages 826 | } 827 | 828 | 829 | 830 | void sendTrackerBind() 831 | { 832 | uint16_t i, j; 833 | uint8_t msb_CRC, lsb_CRC; 834 | uint16_t bindCRC; 835 | 836 | saveKeyin_buffer(); //loads key in bytes 0,1,2,3 of TX buffer 837 | 838 | lora_TXEnd = 4; //this is where the bind data starts 839 | 840 | for (i = addr_StartBindData; i <= addr_EndBindData; i++) 841 | { 842 | j = Memory_ReadByte(i); 843 | lora_TXBUFF[lora_TXEnd++] = j; 844 | } 845 | 846 | bindCRC = Print_CRC_Bind_Memory(); 847 | msb_CRC = highByte(bindCRC); 848 | lsb_CRC = lowByte(bindCRC); 849 | lora_TXBUFF[lora_TXEnd++] = lsb_CRC; 850 | lora_TXBUFF[lora_TXEnd] = msb_CRC; 851 | 852 | Serial.print(F("Bind PacketLen ")); 853 | Serial.println(lora_TXEnd + 4); //allow for 3 addressing bytes in length, plus 1 for packet starting at [0] 854 | 855 | lora_Send(0, lora_TXEnd, Bind, ramc_RemoteControlNode, ramc_ThisNode, 10, BindMode_Power, 0); 856 | 857 | } 858 | 859 | 860 | void printNodes() 861 | { 862 | Serial.print(F("ThisNode ")); 863 | Serial.print(ramc_ThisNode); 864 | Serial.print(F(" RemoteNode ")); 865 | Serial.println(ramc_RemoteControlNode); 866 | Serial.println(); 867 | } 868 | 869 | 870 | void Setup_TrackerMode() 871 | { 872 | lora_SetFreq(ramc_TrackerMode_Frequency, ramc_CalibrationOffset); 873 | lora_SetModem2(ramc_TrackerMode_Bandwidth, ramc_TrackerMode_SpreadingFactor, ramc_TrackerMode_CodeRate, Explicit); //Setup the LoRa modem parameters for tracker mode 874 | lora_Power = ramc_TrackerMode_Power; 875 | } 876 | 877 | 878 | void Setup_LoRaCommandMode() 879 | { 880 | lora_SetFreq(ramc_CommandMode_Frequency, ramc_CalibrationOffset); 881 | lora_SetModem2(ramc_CommandMode_Bandwidth, ramc_CommandMode_SpreadingFactor, ramc_CommandMode_CodeRate, Explicit); //Setup the LoRa modem parameters for command mode 882 | lora_Power = ramc_CommandMode_Power; 883 | } 884 | 885 | 886 | void Setup_LoRaBindMode() 887 | { 888 | lora_SetFreq(BindMode_Frequency, ramc_CalibrationOffset); 889 | lora_SetModem2(BindMode_Bandwidth, BindMode_SpreadingFactor, BindMode_CodeRate, Explicit); //Setup the LoRa modem parameters for bind mode 890 | lora_Power = BindMode_Power; 891 | } 892 | 893 | 894 | void display_current_frequency() 895 | { 896 | float freq_temp; 897 | freq_temp = lora_GetFreq(); 898 | Serial.print(F("Frequency ")); 899 | Serial.print(freq_temp, 3); 900 | Serial.println(F("MHz")); 901 | } 902 | 903 | 904 | void led_Flash(uint16_t flashes, uint16_t delaymS) 905 | { 906 | //flash LED to show tracker is alive 907 | uint16_t index; 908 | 909 | for (index = 1; index <= flashes; index++) 910 | { 911 | digitalWrite(LED1, HIGH); 912 | delay(delaymS); 913 | digitalWrite(LED1, LOW); 914 | delay(delaymS); 915 | } 916 | } 917 | 918 | 919 | //******************************************************************************************************* 920 | // Memory Routines 921 | //******************************************************************************************************* 922 | 923 | void do_ClearSavedData() 924 | { 925 | //clears the whole of memory, normally 1kbyte 926 | Serial.println(F("Clear Saved Memory")); 927 | Memory_Set(addr_StartMemory, addr_EndMemory, 0); 928 | } 929 | 930 | void Clear_All_Memory() 931 | { 932 | //clears the whole of memory, normally 1kbyte 933 | Serial.println(F("Clear All Memory")); 934 | Memory_Set(addr_StartMemory, addr_EndMemory, 0); 935 | } 936 | 937 | 938 | void Print_Config_Memory() 939 | { 940 | //prints the memory used for storing configuration settings 941 | uint8_t memory_LLoopv1; 942 | uint8_t memory_LLoopv2; 943 | uint16_t memory_Laddr = 0; 944 | uint8_t memory_Ldata; 945 | //uint16_t CRC; 946 | Serial.println(F("Config Memory")); 947 | Serial.print(F("Lcn 0 1 2 3 4 5 6 7 8 9 A B C D E F")); 948 | Serial.println(); 949 | 950 | for (memory_LLoopv1 = 0; memory_LLoopv1 <= 15; memory_LLoopv1++) 951 | { 952 | Serial.print(F("0x")); 953 | Serial.print(memory_LLoopv1, HEX); //print the register number 954 | Serial.print(F("0 ")); 955 | for (memory_LLoopv2 = 0; memory_LLoopv2 <= 15; memory_LLoopv2++) 956 | { 957 | memory_Ldata = Memory_ReadByte(memory_Laddr); 958 | if (memory_Ldata < 0x10) { 959 | Serial.print(F("0")); 960 | } 961 | Serial.print(memory_Ldata, HEX); //print the register number 962 | Serial.print(F(" ")); 963 | memory_Laddr++; 964 | } 965 | Serial.println(); 966 | } 967 | } 968 | 969 | 970 | void Print_CRC_Config_Memory() 971 | { 972 | uint16_t returnedCRC = Memory_CRC(addr_StartConfigData, addr_EndConfigData); 973 | Serial.print(F("CRC_Config ")); 974 | Serial.println(returnedCRC, HEX); 975 | } 976 | 977 | 978 | uint16_t Print_CRC_Bind_Memory() 979 | { 980 | uint16_t returnedCRC = Memory_CRC(addr_StartBindData, addr_EndBindData); 981 | Serial.print(F("Local BindCRC ")); 982 | Serial.println(returnedCRC, HEX); 983 | return returnedCRC; 984 | } 985 | 986 | 987 | void setup() 988 | { 989 | uint16_t j; 990 | 991 | pinMode(LED1, OUTPUT); //for PCB LED 992 | pinMode(WDI, OUTPUT); //for Watchdog pulse input 993 | 994 | led_Flash(2, 500); 995 | 996 | Serial.begin(38400); //Setup Serial console ouput 997 | 998 | Memory_Start(); 999 | 1000 | #ifdef ClearAllMemory 1001 | Clear_All_Memory(); 1002 | #endif 1003 | 1004 | 1005 | Serial.println(F(programname)); 1006 | Serial.println(F(aurthorname)); 1007 | 1008 | pinMode(GPSPOWER, OUTPUT); //in case power switching components are fitted 1009 | GPS_On(DoGPSPowerSwitch); //this will power the GPSon 1010 | 1011 | #ifdef USING_SERIALGPS 1012 | GPSserial.end(); //but we dont want soft serial running for now, it interferes with the LoRa device 1013 | #endif 1014 | 1015 | pinMode(lora_NReset, OUTPUT); //LoRa device reset line 1016 | digitalWrite(lora_NReset, HIGH); 1017 | 1018 | pinMode (lora_NSS, OUTPUT); //set the slave select pin as an output: 1019 | digitalWrite(lora_NSS, HIGH); 1020 | 1021 | SPI.begin(); //initialize SPI 1022 | SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); 1023 | 1024 | 1025 | #ifdef ClearSavedData 1026 | do_ClearSavedData(); 1027 | #endif 1028 | 1029 | Serial.print(F("Default_Config1 ")); 1030 | Serial.println(Default_config1, BIN); 1031 | 1032 | j = Memory_ReadUInt(addr_ResetCount); 1033 | j++; 1034 | Memory_WriteUInt(addr_ResetCount, j); 1035 | Serial.print(F("Resets ")); 1036 | Serial.println(j); 1037 | 1038 | #ifdef ConfigureDefaults 1039 | readSettingsDefaults(); 1040 | writeSettingsMemory(); 1041 | #endif 1042 | 1043 | 1044 | #ifdef ConfigureFromMemory 1045 | readSettingsMemory(); 1046 | #endif 1047 | 1048 | Print_CRC_Config_Memory(); 1049 | 1050 | ramc_ThisNode = ThisNode; 1051 | 1052 | printNodes(); 1053 | 1054 | lora_Setup(); 1055 | 1056 | if (!lora_CheckDevice()) 1057 | { 1058 | led_Flash(100, 50); //long medium speed flash for Lora device error 1059 | Serial.println(F("LoRa Error!")); 1060 | } 1061 | 1062 | display_current_frequency(); 1063 | 1064 | ramc_CalibrationOffset = Memory_ReadInt(addr_CalibrationOffset); //get calibration offset for this tracker 1065 | Serial.print(F("Cal Offset ")); 1066 | Serial.println(ramc_CalibrationOffset); 1067 | 1068 | lora_Print(); 1069 | 1070 | Serial.println(); 1071 | print_SupplyVoltage(); 1072 | print_Temperature(); 1073 | Serial.println(); 1074 | 1075 | j = read_SupplyVoltage(); //get supply mV 1076 | Write_Int(0, j, lora_TXBUFF); //write to first two bytes of buffer 1077 | Write_Byte(2, ramc_Current_TXconfig1, lora_TXBUFF); //add the current config byte 1078 | 1079 | Setup_TrackerMode(); 1080 | send_Command(PowerUp); //send power up command, includes supply mV and config, on tracker settings 1081 | sleepSecs(1); 1082 | 1083 | #ifdef SendBind 1084 | if (readConfigByte(TXEnable)) //is TX enabled ? 1085 | { 1086 | Setup_LoRaBindMode(); 1087 | sendTrackerBind(); 1088 | } 1089 | #endif 1090 | 1091 | Setup_TrackerMode(); //so that check tone is at correct frequency 1092 | 1093 | GPS_Config_Error = false; //make sure GPS error flag is cleared 1094 | 1095 | #ifndef DEBUGNoGPS 1096 | GPS_On(DoGPSPowerSwitch); //GPS should have been on for a while by now, so this is just to start soft serial 1097 | GPS_Setup(); //GPS should have had plenty of time to initialise by now 1098 | 1099 | if (GPS_Config_Error) 1100 | { 1101 | Serial.println(F("GPS Error !")); 1102 | Serial.println(); 1103 | send_Command(NoGPS); //make sure receiver knows about GPS error 1104 | led_Flash(100, 25); //long very rapid flash for GPS error 1105 | } 1106 | else 1107 | { 1108 | #ifdef CheckTone 1109 | if (readConfigByte(TXEnable)) //is TX enabled - needed because of fence limits 1110 | { 1111 | Serial.println(F("Check Tone")); //check tone indicates navigation model 6 set (if checktone enabled!) 1112 | lora_Tone(1000, 3000, 5); //Transmit an FM tone, 1000hz, 3000ms, 5dBm 1113 | } 1114 | #endif 1115 | } 1116 | 1117 | digitalWrite(LED1, HIGH); 1118 | setStatusByte(NoGPSTestMode, 0); 1119 | while (!gpsWaitFix(5, DontSwitch, LeaveOn)) //wait for the initial GPS fix, this could take a while, leave GPS powered on 1120 | { 1121 | 1122 | led_Flash(2, 50); //two short LED flashes to indicate GPS waiting for fix 1123 | 1124 | 1125 | } 1126 | #endif 1127 | 1128 | #ifndef DEBUGNoGPS 1129 | GPS_On(DoGPSPowerSwitch); 1130 | GPS_SetCyclicMode(); //set this regardless of whether hot fix mode is enabled 1131 | #endif 1132 | 1133 | lora_Tone(500, 500, 2); //Transmit an FM tone, 500hz, 500ms, 2dBm 1134 | digitalWrite(LED1, LOW); 1135 | sleepSecs(2); //wait for GPS to shut down 1136 | 1137 | #ifdef DEBUGNoGPS 1138 | setStatusByte(NoGPSTestMode, 1); 1139 | #endif 1140 | 1141 | } 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | -------------------------------------------------------------------------------- /Programs/Tracker_HAB2_101017/Tracker_HAB2_101017.ino: -------------------------------------------------------------------------------- 1 | //************************************************************************************************** 2 | // Note: 3 | // 4 | // Make changes to this Program file at your peril 5 | // 6 | // Configuration changes should be made in the HAB2_Settings file not here ! 7 | // 8 | //************************************************************************************************** 9 | 10 | #define programname "Tracker_HAB2_101017" 11 | #define aurthorname "Stuart Robinson" 12 | 13 | #include 14 | #include 15 | 16 | #include "Tracker_HAB2_Settings.h" 17 | #include Board_Definition 18 | #include "Program_Definitions.h" 19 | 20 | /* 21 | ************************************************************************************************** 22 | 23 | Tracker Programs for Arduino 24 | 25 | Copyright of the author Stuart Robinson 26 | 27 | 28 | 29 | These programs may be used free of charge for personal, recreational and educational purposes only. 30 | 31 | This program, or parts of it, may not be used for or in connection with any commercial purpose without 32 | the explicit permission of the author Stuart Robinson. 33 | 34 | The programs are supplied as is, it is up to individual to decide if the programs are suitable for the intended purpose and 35 | free from errors. 36 | 37 | Location payload is constructed thus; 38 | 39 | PayloadID,Sequence,Time,Lat,Lon,Alt,Sats,SupplyVolts,Temperature,Resets,Config0byte,StatusByte,RunmAhr,hertzoffset,GPSFixTime,Checksum 40 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 41 | 42 | To Do: 43 | Change test packet routine to allow for 17dBm packets 44 | 45 | Changes: 46 | 47 | ************************************************************************************************** 48 | */ 49 | 50 | char ramc_RemoteControlNode; 51 | char ramc_ThisNode; 52 | 53 | int ramc_CalibrationOffset; 54 | 55 | unsigned long ramc_TrackerMode_Frequency; //frequencies, and other parameters, are copied from memory into RAM. 56 | unsigned long ramc_SearchMode_Frequency; //this is so that these parameters can be changed in flight and then 57 | unsigned long ramc_CommandMode_Frequency; //copied into memory so that they survive reset. 58 | 59 | byte ramc_TrackerMode_Bandwidth; 60 | byte ramc_TrackerMode_SpreadingFactor; 61 | byte ramc_TrackerMode_CodeRate; 62 | byte ramc_TrackerMode_Power; 63 | byte TRStatus = 0; //used to store current status flag bits 64 | 65 | byte ramc_SearchMode_Bandwidth; 66 | byte ramc_SearchMode_SpreadingFactor; 67 | byte ramc_SearchMode_CodeRate; 68 | byte ramc_SearchMode_Power; 69 | 70 | byte ramc_CommandMode_Bandwidth; 71 | byte ramc_CommandMode_SpreadingFactor; 72 | byte ramc_CommandMode_CodeRate; 73 | byte ramc_CommandMode_Power; 74 | 75 | byte ramc_Current_TXconfig1; //sets the config of whats transmitted etc 76 | byte ramc_Cmd_WaitSecs; 77 | byte stripvalue; 78 | byte sats; //either sats in view from GPGSV or sats from NMEA fix sentence 79 | int internal_temperature; 80 | 81 | 82 | unsigned int ramc_Sleepsecs; //seconds for sleep at end of TX routine 83 | unsigned int ramc_WaitGPSFixSeconds; //in flight mode, default time to wait for a fix 84 | unsigned int ramc_FSKRTTYbaudDelay; //dealy used in FSKRTTY routine to give chosen baud rate 85 | 86 | unsigned long UPTime = 0; 87 | unsigned long UPStart = 0; 88 | unsigned long current_mASecs = 0; //running total of mAseconds used 89 | unsigned long current_Sleepsecs = 0; 90 | 91 | float Fence_Check_Lon; //used for fence check 92 | 93 | float TRLat; //tracker transmitter co-ordinates 94 | float TRLon; 95 | unsigned int TRAlt; 96 | 97 | byte ramc_promiscuous_Mode; 98 | byte ramc_FSKRTTYRegshift; 99 | byte ramc_FSKRTTYpips; 100 | unsigned int ramc_FSKRTTYleadin; 101 | byte ramc_key0; 102 | byte ramc_key1; 103 | byte ramc_key2; 104 | byte ramc_key3; 105 | byte keypress; 106 | 107 | unsigned long GPSonTime; 108 | unsigned long GPSFixTime; 109 | boolean GPS_Config_Error; 110 | 111 | 112 | #include Board_Definition //include previously defined board file 113 | #include Memory_Library //include previously defined Memory Library 114 | 115 | #include 116 | #include //https://github.com/rocketscream/Low-Power 117 | 118 | #include //http://arduiniana.org/libraries/tinygpsplus/ 119 | TinyGPSPlus gps; //create the TinyGPS++ object 120 | TinyGPSCustom GNGGAFIXQ(gps, "GNGGA", 5); //custom sentences used to detect possible switch to GLONASS mode 121 | 122 | #ifdef USE_SOFTSERIAL_GPS 123 | #include //https://github.com/SlashDevin/NeoSWSerial 124 | NeoSWSerial GPSserial(GPSRX, GPSTX); //this library is more relaible at GPS init than software serial 125 | #endif 126 | 127 | #include GPS_Library //include previously defined GPS Library 128 | 129 | #include "Voltage_Temperature.h" 130 | #include "LoRa3.h" 131 | #include "FSK_RTTY2.h" 132 | #include "Binary2.h" 133 | 134 | 135 | 136 | void loop() 137 | { 138 | UPStart = millis(); //set the start time for UPtime 139 | Serial.println(); 140 | Serial.println(); 141 | lora_TXTime = 0; 142 | lora_RXTime = 0; 143 | UPTime = 0; 144 | GPSFixTime = 0; 145 | printTimes(); 146 | internal_temperature = (int) read_Temperature(); //read temp just after sleep, when CPU is closest to ambient 147 | 148 | GPSonTime = millis(); 149 | 150 | #ifndef DEBUGNoGPS 151 | gpsWaitFix(ramc_WaitGPSFixSeconds, SwitchOn, LeaveOn); 152 | #endif 153 | 154 | #ifdef Use_Test_Location 155 | TRLat = TestLatitude; 156 | TRLon = TestLongitude; 157 | TRAlt = TestAltitude; 158 | #endif 159 | 160 | wait_Command(); //wait for incoming command 161 | 162 | if (readConfigByte(DozeEnable)) 163 | { 164 | Serial.println(F("Doze")); 165 | updatemAUsed(); 166 | printTimes(); 167 | sleepSecs(DozeSleepSecs); //tracker has doze made enabled, so just doze awhile and do not send transmissions 168 | return; 169 | } 170 | 171 | if (readConfigByte(CheckFence) && (!doFenceCheck())) //if fence check is enabled and tracker is outside fence 172 | { 173 | action_outside_fence(); 174 | } 175 | else //either fence check is disabled or tracker is within it 176 | { 177 | if (readConfigByte(TXEnable)) //is TX enabled ? 178 | { 179 | do_Transmissions(); //yes, so do transmissions 180 | } 181 | else 182 | { 183 | Serial.println(F("TX off")); 184 | inside_fence_no_transmit(); //no, TX is disabled 185 | } 186 | } 187 | 188 | updatemAUsed(); 189 | printTimes(); 190 | digitalWrite(lora_NSS, HIGH); //take NSS line high, makes sure LoRa device is off 191 | sleepSecs(ramc_Sleepsecs); //this sleep is used to set overall transmission cycle time 192 | 193 | } 194 | 195 | 196 | void wait_Command() 197 | { 198 | byte index; 199 | pulseWDI(); 200 | lora_Setup(); //resets then sets up LoRa device 201 | Setup_LoRaCommandMode(); //commands can be sent in any mode, make sure this is sent using the right frequency etc 202 | send_Command(ClearToSendCommand); //indicate ready for command 203 | 204 | lora_RXPacketType = 0; //use as flag to tell if anything received during listen 205 | Listen(Cmd_WaitSecs); //wait for command packet 206 | 207 | if (lora_RXPacketType > 0) 208 | { 209 | do 210 | { 211 | //there was activity during previous listen 212 | lora_RXPacketType = 0; 213 | 214 | for (index = 1; index <= Command_Loops; index++) 215 | { 216 | Setup_LoRaCommandMode(); //commands can be sent in any mode, make sure this is sent using the right frequency etc 217 | send_Command(ClearToSendCommand); 218 | Listen(Cmd_WaitSecs); 219 | } 220 | 221 | } while (lora_RXPacketType > 0); //wait until the extended listen exits with no packet received 222 | 223 | } 224 | else 225 | { 226 | Serial.println(F("No RX")); 227 | } 228 | } 229 | 230 | 231 | void do_Transmissions() 232 | { 233 | //this is where all the transmisions get sent 234 | byte index, Count; 235 | 236 | pulseWDI(); 237 | lora_Setup(); //resets then sets up LoRa device 238 | 239 | Setup_TrackerMode(); 240 | 241 | incMemoryULong(addr_SequenceNum); //increment sequence number 242 | Count = buildHABPacket(); 243 | stripvalue = readConfigByte(AddressStrip); 244 | Serial.println(F("Send HAB Pkt")); 245 | printPayload(Count); 246 | Serial.println(); 247 | digitalWrite(LED1, HIGH); 248 | lora_Send(0, Count, HABPacket, Broadcast, ramc_ThisNode, 10, lora_Power, stripvalue); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd 249 | digitalWrite(LED1, LOW); 250 | 251 | sleepSecs(delayforAFSKuploadSecs); //allow time for receiver AFSK upload 252 | 253 | sleepSecs(delayforRelaysecs); //wait for relay to operate 254 | 255 | if (readConfigByte(FSKRTTYEnable)) 256 | { 257 | 258 | Serial.println(F("Send FSKRTTY")); 259 | 260 | lora_DirectSetup(); //set for direct mode 261 | lora_SetFreq(ramc_TrackerMode_Frequency, ramc_CalibrationOffset); 262 | Start_FSKRTTY(FSKRTTYRegshift, FSKRTTYleadin, FSKRTTYpips); 263 | 264 | for (index = 1; index <= sync_chars; index++) 265 | { 266 | Send_FSKRTTY('$', FSKRTTYbaudDelay); 267 | } 268 | 269 | for (index = 0; index <= Count; index++) 270 | { 271 | Send_FSKRTTY(lora_TXBUFF[index], FSKRTTYbaudDelay); 272 | } 273 | Send_FSKRTTY(13, FSKRTTYbaudDelay); //finish RTTY with carriage return 274 | Send_FSKRTTY(10, FSKRTTYbaudDelay); //and line feed 275 | digitalWrite(LED1, LOW); //make sure LED off 276 | lora_TXOFF(); //to ensure TXTime updated correctly 277 | } 278 | 279 | if (readConfigByte(SearchEnable)) 280 | { 281 | Setup_LoRaSearchMode(); //setup is here so that any mode can be used to TX binary packet 282 | send_LocationBinary(TRLat, TRLon, TRAlt); 283 | } 284 | 285 | } 286 | 287 | 288 | byte buildHABPacket() //expects a char buffer, so this routine will not work without the -permissive setting 289 | { 290 | //build the long tracker payload 291 | unsigned int index, j, CRC, resets, runmAhr; 292 | int volts; 293 | byte Count,len; 294 | char LatArray[12], LonArray[12]; 295 | 296 | //unsigned long fixtime; 297 | unsigned long sequence; 298 | 299 | sequence = Memory_ReadULong(addr_SequenceNum); //sequence number is kept in non-volatile memory so it survives resets 300 | resets = Memory_ReadUInt(addr_ResetCount); //reset count is kept in non-volatile memory so it survives resets 301 | 302 | Serial.print("Resets "); 303 | Serial.println(resets); 304 | Serial.print("Temperature "); 305 | Serial.println(internal_temperature); 306 | 307 | runmAhr = (current_mASecs / 3600); 308 | 309 | volts = read_SupplyVoltage(); 310 | 311 | if (!readConfigByte(GPSHotFix)) 312 | { 313 | GPSFixTime = 0; //if GPS power save is off (no GPSHotFix), ensure GPS fix time is set to zero 314 | Serial.println("GPSFixTime set to 0"); 315 | } 316 | 317 | sats = gps.satellites.value(); 318 | dtostrf(TRLat, 7, 5, LatArray); //format is dtostrf(FLOAT,WIDTH,PRECISION,BUFFER); 319 | dtostrf(TRLon, 7, 5, LonArray); //converts float to character array 320 | len = sizeof(lora_TXBUFF); 321 | memset(lora_TXBUFF, 0, len); //clear array to 0s 322 | 323 | Count = snprintf((char*) lora_TXBUFF, 324 | Output_len_max, 325 | "$$$$%s,%lu,%02d:%02d:%02d,%s,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%lu", 326 | Flight_ID, 327 | sequence, 328 | gps.time.hour(), 329 | gps.time.minute(), 330 | gps.time.second(), 331 | LatArray, 332 | LonArray, 333 | TRAlt, 334 | sats, 335 | volts, 336 | internal_temperature, 337 | resets, 338 | ramc_Current_TXconfig1, 339 | TRStatus, 340 | runmAhr, 341 | ramc_CalibrationOffset, 342 | GPSFixTime 343 | ); 344 | 345 | //Count = strlen(lora_TXBUFF); //how long is the array ? 346 | 347 | CRC = 0xffff; //start value for CRC16 348 | 349 | for (index = 4; index < Count; index++) //element 4 is first character after $$ at start 350 | { 351 | CRC ^= (((unsigned int)lora_TXBUFF[index]) << 8); 352 | for (j = 0; j < 8; j++) 353 | { 354 | if (CRC & 0x8000) 355 | CRC = (CRC << 1) ^ 0x1021; 356 | else 357 | CRC <<= 1; 358 | } 359 | } 360 | 361 | lora_TXBUFF[Count++] = '*'; 362 | lora_TXBUFF[Count++] = Hex((CRC >> 12) & 15); //add the checksum bytes to the end 363 | lora_TXBUFF[Count++] = Hex((CRC >> 8) & 15); 364 | lora_TXBUFF[Count++] = Hex((CRC >> 4) & 15); 365 | lora_TXBUFF[Count] = Hex(CRC & 15); 366 | return Count; 367 | } 368 | 369 | char Hex(byte lchar) 370 | { 371 | //used in CRC calculation in buildHABPacket 372 | char Table[] = "0123456789ABCDEF"; 373 | return Table[lchar]; 374 | } 375 | 376 | 377 | 378 | void send_LocationBinary(float Lat, float Lon, unsigned int Alt) 379 | { 380 | Write_Float(0, Lat, lora_TXBUFF); 381 | Write_Float(4, Lon, lora_TXBUFF); 382 | Write_Int(8, Alt, lora_TXBUFF); 383 | Write_Byte(10, TRStatus, lora_TXBUFF); 384 | 385 | digitalWrite(LED1, HIGH); 386 | Serial.println(F("Send Binary Location")); 387 | lora_Send(0, 10, LocationBinaryPacket, Broadcast, ramc_ThisNode, 10, lora_Power, 0); //send the packet, data is in TXbuff from lora_TXStart to lora_TXEnd 388 | digitalWrite(LED1, LOW); 389 | } 390 | 391 | 392 | void inside_fence_no_transmit() 393 | { 394 | Setup_LoRaCommandMode(); //commands can be sent in any mode, make sure this is sent using the right frequency etc 395 | Listen(ramc_Cmd_WaitSecs); //wait for command packet} 396 | } 397 | 398 | 399 | void action_outside_fence() 400 | { 401 | sleepSecs(outside_fence_Sleep_seconds); //goto sleep for a long time 402 | lora_Setup(); 403 | Setup_LoRaCommandMode(); 404 | Listen(Cmd_WaitSecs); 405 | Listen(Cmd_WaitSecs); 406 | } 407 | 408 | 409 | byte doFenceCheck() //checks to see if GPS location is within an Western and Eastern limit 410 | { 411 | //there has been a fix, so check fence limits 412 | Fence_Check_Lon = gps.location.lng(); 413 | 414 | #ifdef DEBUGNoGPS 415 | Fence_Check_Lon = TestLongitude; 416 | #endif 417 | 418 | #ifdef DEBUG 419 | Serial.print(Fence_Check_Lon, 6); 420 | Serial.print(F(" ")); 421 | #endif 422 | 423 | if ((Fence_Check_Lon > west_fence) && (Fence_Check_Lon < east_fence)) //approximate to the limits for region 1 ISM band 424 | { 425 | Serial.println(F("Inside Fence")); 426 | return 1; //within the fence 427 | } 428 | else 429 | { 430 | Serial.println(F("Outside Fence")); 431 | return 0; 432 | } 433 | //outside the fence 434 | } 435 | 436 | 437 | void printPayload(byte lCount) 438 | { 439 | byte index; 440 | for (index = 0; index <= lCount; index++) 441 | { 442 | Serial.write(lora_TXBUFF[index]); 443 | } 444 | } 445 | 446 | 447 | void updatemAUsed() 448 | { 449 | unsigned long i; 450 | Serial.println(F("Update mA")); 451 | addmASecs(TXmA, lora_TXTime, 1); //add TXTime current consumed current to total 452 | addmASecs(RXmA, lora_RXTime, 2); //add RXTime current consumed current to total 453 | 454 | if (readConfigByte(GPSHotFix)) 455 | { 456 | addmASecs(GPSmA, (GPSFixTime + GPSShutdownTimemS), 3); //add GPS consumed current to total only if power save (GPSHotFix) enabled 457 | } 458 | 459 | UPTime = (millis() - UPStart); 460 | addmASecs(runmA, UPTime, 4); //add run current consumed current to total 461 | i = current_Sleepsecs * 1000; //convert total Sleepsecs this loop into mS 462 | addmASecs(SleepmA, i, 5); 463 | Memory_WriteULong(addr_mASecs, current_mASecs); //save running mASecs into memory 464 | current_Sleepsecs = 0; 465 | } 466 | 467 | 468 | void addmASecs(float lmAamp, unsigned long lmillis, byte number) 469 | { 470 | //adds to the running total of current_mASecs, i.e 10mA for 2000mS = 20mAmS 471 | //for a long unsigned int max Count = 4294967296 or 4294967 mAMins or 71582 maHr 472 | unsigned long i; 473 | i = (unsigned long) ((lmillis * lmAamp) / 1000) ; //calculate the mASecs, divide the time by 1000 474 | current_mASecs = current_mASecs + i; 475 | Serial.print(number); 476 | Serial.print(F(" mASecs ")); 477 | Serial.println(current_mASecs); 478 | } 479 | 480 | 481 | void printTimes() 482 | { 483 | //print the times used to calculate mAhr used 484 | Serial.print(F("TXTime ")); 485 | Serial.print(lora_TXTime); 486 | Serial.println(F("mS")); 487 | Serial.print(F("RXTime ")); 488 | Serial.print(lora_RXTime); 489 | Serial.println(F("mS")); 490 | Serial.print(F("UPTime ")); 491 | Serial.print((millis() - UPStart)); 492 | Serial.println(F("mS")); 493 | Serial.print(F("mASecs ")); 494 | Serial.println(current_mASecs); 495 | Serial.print(F("mAHour ")); 496 | Serial.println((current_mASecs) / 3600); 497 | } 498 | 499 | 500 | void Listen(unsigned int seconds) 501 | { 502 | //listen (in seconds) for an incoming packet using the current frequency and LoRa modem settings 503 | unsigned long tilltime; 504 | tilltime = (millis() + (seconds * 1000)); 505 | Serial.print(F("Listen ")); 506 | Serial.println(seconds); 507 | 508 | lora_RXONLoRa(); 509 | 510 | while (millis() < tilltime) 511 | { 512 | checkForPacket(); 513 | } 514 | lora_RXOFF(); //as we have finished listening 515 | } 516 | 517 | 518 | void checkForPacket() 519 | { 520 | //check LoRa device to see if a command packet has arrived 521 | byte lora_Ltemp; 522 | 523 | lora_Ltemp = lora_readRXready(); 524 | 525 | if (lora_Ltemp > 0) 526 | { 527 | 528 | Serial.print(F("RX ")); 529 | 530 | if (lora_Ltemp == 64) 531 | { 532 | //packet has arrived 533 | lora_ReadPacket(); 534 | 535 | #ifdef DEBUG 536 | Serial.write(lora_RXPacketType); 537 | Serial.write(lora_RXDestination); 538 | Serial.write(lora_RXSource); 539 | Serial.println(); 540 | #endif 541 | } 542 | else 543 | { 544 | //packet arrived with error 545 | Serial.println(F("Error")); 546 | lora_RXOFF(); 547 | lora_RXONLoRa(); 548 | } 549 | 550 | if (promiscuous_Mode) //can we accept packet from any source 551 | { 552 | processPacket(); 553 | lora_RXONLoRa(); 554 | } 555 | 556 | if (!promiscuous_Mode) //can we only accepts packet from known node 557 | { 558 | if (lora_RXSource == ramc_RemoteControlNode) 559 | { 560 | processPacket(); 561 | lora_RXONLoRa(); //ready for next and clear flags 562 | } 563 | else 564 | { 565 | Serial.println(F("Rejected")); 566 | lora_RXOFF(); 567 | Setup_LoRaCommandMode(); 568 | send_Command(NACK); 569 | lora_RXONLoRa(); 570 | } 571 | } 572 | } 573 | } 574 | 575 | 576 | void processPacket() 577 | { 578 | //we have a packet so lets decide what to do with it 579 | byte j, ptr; 580 | unsigned int i; 581 | 582 | if (lora_RXPacketType == Test) 583 | { 584 | if (lora_RXBUFF[0] == '0') 585 | { 586 | Serial.println(F("Pkt Test")); 587 | delay(inter_Packet_delay); 588 | Setup_LoRaCommandMode(); 589 | send_Command(ACK); 590 | delay(inter_Packet_delay); 591 | sendTest(); 592 | } 593 | 594 | if (lora_RXBUFF[0] == '1') 595 | { 596 | Serial.println(F("FSKRTTY Test")); 597 | delay(inter_Packet_delay); 598 | Setup_LoRaCommandMode(); 599 | send_Command(ACK); 600 | delay(inter_Packet_delay); 601 | Send_FSKRTTYTest(); 602 | } 603 | 604 | } 605 | 606 | if (lora_RXPacketType == LinkReport) 607 | { 608 | send_Command(ACK); 609 | delay(inter_Packet_delay); 610 | Serial.println(F("Link Report")); 611 | delay(inter_Packet_delay); 612 | Setup_LoRaCommandMode(); 613 | send_Command(Info); 614 | } 615 | 616 | 617 | if (lora_RXPacketType == Config0) //is it a change config byte request ? 618 | { 619 | Serial.println(F("Prog Cfgbyte")); 620 | 621 | i = ((lora_RXBUFF[0] - 48)); //config byte requests come in as ASCCI, '1' for 1 etc 622 | j = ((lora_RXBUFF[1] - 48)); 623 | setConfigByte(i, j); 624 | lora_RXBuffPrint(0); //print packet contents as ASCII 625 | Serial.println(); 626 | delay(inter_Packet_delay); 627 | Setup_LoRaCommandMode(); 628 | send_Command(ACK); //send the ack 629 | 630 | } 631 | 632 | if (lora_RXPacketType == ResetTracker) //is it a reset ? 633 | { 634 | Serial.println(F("Reset ?")); 635 | lora_RXBuffPrint(0); //print packet contents as ASCII 636 | Serial.println(); 637 | 638 | if ( isKeyValid() ) 639 | { 640 | Serial.println(F("Valid")); 641 | delay(inter_Packet_delay); 642 | Setup_LoRaCommandMode(); 643 | send_Command(ACK); 644 | Serial.flush(); 645 | sleepSecs(2); 646 | softReset(); 647 | } 648 | else 649 | { 650 | Serial.println(F("Invalid")); 651 | delay(inter_Packet_delay); 652 | Setup_LoRaCommandMode(); 653 | send_Command(NACK); 654 | } 655 | } 656 | 657 | if (lora_RXPacketType == WritePacketMemory) 658 | { 659 | Serial.println(F("Write Memory")); 660 | writePacketMemory(); 661 | delay(inter_Packet_delay); 662 | Setup_LoRaCommandMode(); 663 | send_Command(ACK); 664 | } 665 | 666 | if (lora_RXPacketType == INCFreq) 667 | { 668 | Serial.println(F("IncOffset 1KHZ")); 669 | ramc_CalibrationOffset = ramc_CalibrationOffset + 1000; 670 | delay(inter_Packet_delay); 671 | Setup_LoRaCommandMode(); 672 | send_Command(ACK); 673 | Memory_WriteInt(addr_CalibrationOffset, ramc_CalibrationOffset); 674 | printRAMFrequencies(); 675 | } 676 | 677 | if (lora_RXPacketType == DECFreq) 678 | { 679 | Serial.println(F("DecOffset 1KHZ")); 680 | ramc_CalibrationOffset = ramc_CalibrationOffset - 1000; 681 | delay(inter_Packet_delay); 682 | Setup_LoRaCommandMode(); 683 | send_Command(ACK); 684 | Memory_WriteInt(addr_CalibrationOffset, ramc_CalibrationOffset); 685 | printRAMFrequencies(); 686 | } 687 | 688 | if (lora_RXPacketType == Bind) 689 | { 690 | 691 | if (isKeyValid()) //only accept bind request when key is valid 692 | { 693 | 694 | ptr = 4; //bind packet has 4 bytes of key 695 | Serial.println(F("Bind RX")); 696 | 697 | for (i = addr_StartBindData; i <= addr_EndBindData; i++) 698 | { 699 | j = lora_RXBUFF[ptr++]; 700 | Memory_WriteByte(i, j); 701 | } 702 | 703 | readSettingsMemory(); 704 | 705 | #ifdef DEBUG 706 | printMemoryFrequencies(); 707 | printRAMFrequencies(); 708 | Print_Config_Memory(); 709 | Print_CRC_Config_Memory(); 710 | #endif 711 | 712 | delay(inter_Packet_delay); 713 | send_Command(ACK); 714 | } 715 | else 716 | { 717 | Serial.println(F("Key not valid")); 718 | } 719 | 720 | } 721 | } 722 | 723 | 724 | void printMemoryFrequencies() 725 | { 726 | //a useful check to see if memory is configured correctly 727 | unsigned long tempULong; 728 | tempULong = Memory_ReadULong(addr_TrackerMode_Frequency); 729 | Serial.print(F("Memory Tracker Freq ")); 730 | Serial.println(tempULong); 731 | 732 | tempULong = Memory_ReadULong(addr_SearchMode_Frequency); 733 | Serial.print(F("Memory Search Freq ")); 734 | Serial.println(tempULong); 735 | 736 | tempULong = Memory_ReadULong(addr_CommandMode_Frequency); 737 | Serial.print(F("Memory Command Freq ")); 738 | Serial.println(tempULong); 739 | } 740 | 741 | 742 | void printRAMFrequencies() 743 | { 744 | Serial.print(F("RAM Tracker Freq ")); 745 | Serial.println(ramc_TrackerMode_Frequency); 746 | 747 | Serial.print(F("RAM Search Freq ")); 748 | Serial.println(ramc_SearchMode_Frequency); 749 | 750 | Serial.print(F("RAM Command Freq ")); 751 | Serial.println(ramc_CommandMode_Frequency); 752 | 753 | Serial.print(F("RAM Calibration Offset ")); 754 | Serial.println(ramc_CalibrationOffset); 755 | } 756 | 757 | 758 | boolean isKeyValid() 759 | { 760 | if ( (lora_RXBUFF[0] == key0) && (lora_RXBUFF[1] == key1) && (lora_RXBUFF[2] == key2) && (lora_RXBUFF[3] == key3) ) 761 | { 762 | return true; 763 | } 764 | else 765 | { 766 | return false; 767 | } 768 | } 769 | 770 | 771 | void softReset() 772 | { 773 | asm volatile (" jmp 0"); 774 | } 775 | 776 | 777 | void send_Command(char cmd) 778 | { 779 | unsigned int volts; 780 | volts = read_SupplyVoltage(); 781 | Serial.print(F("Send Cmd ")); 782 | Serial.write(cmd); 783 | Serial.println(); 784 | Write_Byte(0, lora_PacketSNR, lora_TXBUFF); //so that receiver alwsys knows last received SNR 785 | Write_Byte(1, lora_PacketRSSI, lora_TXBUFF); //so that receiver alwsys knows last received RSSI 786 | Write_UInt(2, volts, lora_TXBUFF); 787 | Write_Byte(4, TRStatus, lora_TXBUFF); 788 | digitalWrite(LED1, HIGH); 789 | lora_Send(0, 4, cmd, Broadcast, ramc_ThisNode, 10, lora_Power, 0); 790 | digitalWrite(LED1, LOW); 791 | } 792 | 793 | 794 | void sendTest() 795 | { 796 | byte power; 797 | for (power = 10; power >= 2; power--) 798 | { 799 | Setup_TrackerMode(); 800 | lora_TXBUFF[0] = '0'; 801 | lora_TXBUFF[1] = power + 48; 802 | lora_TXEnd = 1; 803 | 804 | if (power == 10) 805 | { 806 | lora_TXBUFF[0] = '1'; 807 | lora_TXBUFF[1] = '0'; 808 | lora_TXEnd = 2; 809 | } 810 | 811 | Serial.print(F("Send ")); 812 | Serial.print(power); 813 | Serial.println(F("dBm")); 814 | 815 | lora_Send(0, 1, Test, Broadcast, ramc_ThisNode, 10, power, 0); //send the test packet 816 | sleepSecs(2); 817 | } 818 | } 819 | 820 | 821 | void Send_FSKRTTYTest() 822 | { 823 | byte power; 824 | 825 | Start_FSKRTTY(FSKRTTYRegshift, FSKRTTYleadin, FSKRTTYpips); 826 | Send_FSKRTTY(13, FSKRTTYbaudDelay); 827 | Send_FSKRTTY(10, FSKRTTYbaudDelay); 828 | 829 | for (power = 10; power >= 2; power--) 830 | { 831 | lora_TXONDirect(power); 832 | delay(200); 833 | Send_FSKRTTY(' ', FSKRTTYbaudDelay); 834 | 835 | 836 | if (power == 10) 837 | { 838 | Send_FSKRTTY('1', FSKRTTYbaudDelay); 839 | Send_FSKRTTY('0', FSKRTTYbaudDelay); 840 | } 841 | else 842 | { 843 | Send_FSKRTTY('0', FSKRTTYbaudDelay); 844 | Send_FSKRTTY(power + 48, FSKRTTYbaudDelay); 845 | } 846 | delay(200); 847 | } 848 | Send_FSKRTTY(13, FSKRTTYbaudDelay); 849 | Send_FSKRTTY(10, FSKRTTYbaudDelay); 850 | lora_Setup(); 851 | } 852 | 853 | 854 | void sleepSecs(unsigned int LNumberSleeps) 855 | { 856 | unsigned int i; 857 | 858 | Serial.print(F("zz ")); 859 | Serial.println(LNumberSleeps); 860 | Serial.flush(); //let print complete 861 | #ifdef USING_SERIALGPS 862 | GPSserial.end(); //we dont want GPS input interfering with sleep, make sure its off 863 | #endif 864 | digitalWrite(lora_NSS, HIGH); //ensure LoRa Device is off 865 | 866 | for (i = 1; i <= LNumberSleeps; i++) 867 | { 868 | LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); //sleep 1 second 869 | pulseWDI(); 870 | } 871 | current_Sleepsecs = current_Sleepsecs + LNumberSleeps; 872 | } 873 | 874 | 875 | void incMemoryULong(unsigned int laddress) 876 | { 877 | unsigned long val; 878 | val = Memory_ReadULong(laddress); 879 | val++; 880 | Memory_WriteULong(laddress, val); 881 | } 882 | 883 | 884 | byte readConfigByte(byte bitnum) 885 | { 886 | return bitRead(ramc_Current_TXconfig1, bitnum); 887 | } 888 | 889 | 890 | void setConfigByte(byte bitnum, byte bitval) 891 | { 892 | //program the config byte 893 | 894 | if (bitval == 0) 895 | { 896 | bitClear(ramc_Current_TXconfig1, bitnum); 897 | } 898 | else 899 | { 900 | bitSet(ramc_Current_TXconfig1, bitnum); 901 | } 902 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 903 | 904 | #ifdef DEBUG 905 | if (bitval) 906 | { 907 | Serial.print(F("Set Config Bit ")); 908 | } 909 | else 910 | { 911 | Serial.print(F("Clear Config Bit ")); 912 | } 913 | Serial.println(bitnum); 914 | 915 | #endif 916 | } 917 | 918 | 919 | void setStatusByte(byte bitnum, byte bitval) 920 | { 921 | //program the status byte 922 | 923 | if (bitval == 0) 924 | { 925 | bitClear(TRStatus, bitnum); 926 | } 927 | else 928 | { 929 | bitSet(TRStatus, bitnum); 930 | } 931 | 932 | #ifdef DEBUG 933 | if (bitval) 934 | { 935 | Serial.print(F("Set Status Bit ")); 936 | } 937 | else 938 | { 939 | Serial.print(F("Clear Status Bit ")); 940 | } 941 | 942 | Serial.println(bitnum); 943 | #endif 944 | } 945 | 946 | 947 | void pulseWDI() 948 | { 949 | //if the watchdog is fitted it needs a regular pulse top prevent reset 950 | //togle the WDI pin twice 951 | digitalWrite(WDI, !digitalRead(WDI)); 952 | delayMicroseconds(1); 953 | digitalWrite(WDI, !digitalRead(WDI)); 954 | } 955 | 956 | 957 | boolean gpsWaitFix(unsigned long waitSecs, byte StartState, byte LeaveState) 958 | { 959 | //waits a specified number of seconds for a fix, returns true for good fix 960 | //StartState when set to 1 will turn GPS on at routine start 961 | //LeaveState when set to 0 will turn GPS off at routine end, used perhaps when there is no fix 962 | 963 | unsigned long endwaitmS, millistowait, currentmillis; 964 | pulseWDI(); 965 | byte GPSByte; 966 | //ong temp; 967 | 968 | if (StartState == 1) 969 | { 970 | GPS_On(DoGPSPowerSwitch); 971 | GPSonTime = millis(); 972 | } 973 | else 974 | { 975 | GPS_On(NoGPSPowerSwitch); 976 | } 977 | 978 | #ifdef Check_GPS_Navigation_Model_OK 979 | Serial.println(F("Check GPSNavigation Model")); 980 | if (!GPS_CheckNavigation()) 981 | { 982 | //something wrong with GPS, navigation mode not set so reconfigure the GPS 983 | Serial.println(F("GPS Configuration Error !!!!")); 984 | GPS_Setup(); 985 | } 986 | #endif 987 | 988 | 989 | Serial.print(F("Wait Fix ")); 990 | Serial.print(waitSecs); 991 | Serial.println(F(" Secs")); 992 | 993 | currentmillis = millis(); 994 | millistowait = waitSecs * 1000; 995 | endwaitmS = currentmillis + millistowait; 996 | 997 | while (millis() < endwaitmS) 998 | { 999 | 1000 | do 1001 | { 1002 | GPSByte = GPS_GetByte(); 1003 | if (GPSByte != 0xFF) 1004 | { 1005 | gps.encode(GPSByte); 1006 | } 1007 | } 1008 | while (GPSByte != 0xFF); 1009 | 1010 | if (gps.location.isUpdated() && gps.altitude.isUpdated()) 1011 | { 1012 | Serial.println(F("GPS Fix")); 1013 | TRLat = gps.location.lat(); 1014 | TRLon = gps.location.lng(); 1015 | TRAlt = (unsigned int) gps.altitude.meters(); 1016 | 1017 | //Altitude is used as an unsigned integer, so that the binary payload is as short as possible. 1018 | //However gps.altitude.meters(); can return a negative value which converts to 1019 | //65535 - Altitude, which we dont want. So we will assume any value over 60,000M is zero 1020 | 1021 | if (TRAlt > 60000) 1022 | { 1023 | TRAlt = 0; 1024 | } 1025 | 1026 | if (readConfigByte(GPSHotFix)) 1027 | { 1028 | GPS_Off(DoGPSPowerSwitch); 1029 | GPSFixTime = (millis() - GPSonTime); 1030 | //GPSoffTime = millis(); 1031 | Serial.print(F("GPS FixTime ")); 1032 | Serial.print(GPSFixTime); 1033 | Serial.println(F("mS")); 1034 | } 1035 | else 1036 | { 1037 | GPS_Off(NoGPSPowerSwitch); 1038 | } 1039 | 1040 | setStatusByte(GPSFix, 1); 1041 | pulseWDI(); 1042 | return true; 1043 | } 1044 | 1045 | #ifdef UBLOX 1046 | if (GNGGAFIXQ.age() < 2000) //check to see if GLONASS has gone active 1047 | { 1048 | Serial.println(F("GLONASS !")); 1049 | setStatusByte(GLONASSisoutput, 1); 1050 | GPS_SetGPMode(); 1051 | GPS_SetCyclicMode(); 1052 | sleepSecs(1); 1053 | } 1054 | else 1055 | { 1056 | setStatusByte(GLONASSisoutput, 0); //GLONASS not detected 1057 | } 1058 | #endif 1059 | 1060 | 1061 | 1062 | } 1063 | 1064 | //if here then there has been no fix and a timeout 1065 | setStatusByte(GPSFix, 0); //set status bit to flag no fix 1066 | Serial.println(F("No Fix")); 1067 | 1068 | if (LeaveState == 0) 1069 | { 1070 | //no fix and gpsWaitFix called with gpspower to be turned off on exit 1071 | GPS_Off(DoGPSPowerSwitch); 1072 | } 1073 | else 1074 | { 1075 | //no fix but gpsWaitFix called with gpspower to be left on at exit 1076 | GPS_Off(NoGPSPowerSwitch); 1077 | } 1078 | 1079 | pulseWDI(); 1080 | return false; 1081 | } 1082 | 1083 | 1084 | void readSettingsDefaults() 1085 | { 1086 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 1087 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) in the same way as the transmitter. 1088 | //There are some exceptions, where the local programs need to use a setting unique to the particular 1089 | //receiver. 1090 | Serial.println(F("Config Defaults")); 1091 | ramc_TrackerMode_Frequency = TrackerMode_Frequency; 1092 | ramc_TrackerMode_Bandwidth = TrackerMode_Bandwidth; 1093 | ramc_TrackerMode_SpreadingFactor = TrackerMode_SpreadingFactor; 1094 | ramc_TrackerMode_CodeRate = TrackerMode_CodeRate; 1095 | ramc_TrackerMode_Power = TrackerMode_Power; 1096 | 1097 | ramc_SearchMode_Frequency = SearchMode_Frequency; 1098 | ramc_SearchMode_Bandwidth = SearchMode_Bandwidth; 1099 | ramc_SearchMode_SpreadingFactor = SearchMode_SpreadingFactor; 1100 | ramc_SearchMode_CodeRate = SearchMode_CodeRate; 1101 | ramc_SearchMode_Power = SearchMode_Power; 1102 | 1103 | ramc_CommandMode_Frequency = CommandMode_Frequency; 1104 | ramc_CommandMode_Bandwidth = CommandMode_Bandwidth; 1105 | ramc_CommandMode_SpreadingFactor = CommandMode_SpreadingFactor; 1106 | ramc_CommandMode_CodeRate = CommandMode_CodeRate; 1107 | ramc_CommandMode_Power = CommandMode_Power; 1108 | 1109 | ramc_ThisNode = ThisNode; 1110 | ramc_RemoteControlNode = RemoteControlNode; 1111 | 1112 | ramc_Current_TXconfig1 = Default_config1; 1113 | ramc_Cmd_WaitSecs = Cmd_WaitSecs; 1114 | ramc_WaitGPSFixSeconds = WaitGPSFixSeconds; 1115 | ramc_Sleepsecs = Loop_Sleepsecs; 1116 | ramc_promiscuous_Mode = promiscuous_Mode; 1117 | 1118 | ramc_FSKRTTYbaudDelay = FSKRTTYbaudDelay; 1119 | ramc_FSKRTTYRegshift = FSKRTTYRegshift; 1120 | ramc_FSKRTTYpips = FSKRTTYpips; 1121 | ramc_FSKRTTYleadin = FSKRTTYleadin; 1122 | 1123 | ramc_key0 = key0; 1124 | ramc_key1 = key1; 1125 | ramc_key2 = key2; 1126 | ramc_key3 = key3; 1127 | 1128 | ramc_CalibrationOffset = CalibrationOffset; 1129 | } 1130 | 1131 | 1132 | void readSettingsMemory() 1133 | { 1134 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 1135 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) in the same way as the transmitter. 1136 | //There are some exceptions, where the local programs need to use a setting unique to the particular 1137 | //receiver. 1138 | Serial.println(F("Config from Memory")); 1139 | 1140 | ramc_TrackerMode_Frequency = Memory_ReadULong(addr_TrackerMode_Frequency); 1141 | ramc_TrackerMode_Bandwidth = Memory_ReadByte(addr_TrackerMode_Bandwidth); 1142 | ramc_TrackerMode_SpreadingFactor = Memory_ReadByte(addr_TrackerMode_SpreadingFactor); 1143 | ramc_TrackerMode_CodeRate = Memory_ReadByte(addr_TrackerMode_CodeRate); 1144 | ramc_TrackerMode_Power = Memory_ReadByte(addr_TrackerMode_Power); 1145 | 1146 | ramc_SearchMode_Frequency = Memory_ReadULong(addr_SearchMode_Frequency); 1147 | ramc_SearchMode_Bandwidth = Memory_ReadByte(addr_SearchMode_Bandwidth); 1148 | ramc_SearchMode_SpreadingFactor = Memory_ReadByte(addr_SearchMode_SpreadingFactor); 1149 | ramc_SearchMode_CodeRate = Memory_ReadByte(addr_SearchMode_CodeRate); 1150 | ramc_SearchMode_Power = Memory_ReadByte(addr_SearchMode_Power); 1151 | 1152 | ramc_CommandMode_Frequency = Memory_ReadULong(addr_CommandMode_Frequency); 1153 | ramc_CommandMode_Bandwidth = Memory_ReadByte(addr_CommandMode_Bandwidth); 1154 | ramc_CommandMode_SpreadingFactor = Memory_ReadByte(addr_CommandMode_SpreadingFactor); 1155 | ramc_CommandMode_CodeRate = Memory_ReadByte(addr_CommandMode_CodeRate); 1156 | ramc_CommandMode_Power = Memory_ReadByte(addr_CommandMode_Power); 1157 | 1158 | ramc_ThisNode = Memory_ReadByte(addr_ThisNode);; 1159 | ramc_RemoteControlNode = Memory_ReadByte(addr_RemoteControlNode);; 1160 | 1161 | ramc_Current_TXconfig1 = Memory_ReadByte(addr_Default_config1); 1162 | ramc_Cmd_WaitSecs = Memory_ReadByte(addr_Cmd_WaitSecs); 1163 | ramc_WaitGPSFixSeconds = Memory_ReadUInt(addr_WaitGPSFixSeconds); 1164 | ramc_Sleepsecs = Memory_ReadUInt(addr_Sleepsecs); 1165 | ramc_promiscuous_Mode = Memory_ReadByte(addr_promiscuous_Mode); 1166 | 1167 | ramc_FSKRTTYbaudDelay = Memory_ReadUInt(addr_FSKRTTYbaudDelay); 1168 | ramc_FSKRTTYRegshift = Memory_ReadByte(addr_FSKRTTYRegshift); 1169 | ramc_FSKRTTYpips = Memory_ReadByte(addr_FSKRTTYpips); 1170 | ramc_FSKRTTYleadin = Memory_ReadUInt(addr_FSKRTTYleadin); 1171 | ramc_key0 = Memory_ReadByte(addr_key0); 1172 | ramc_key1 = Memory_ReadByte(addr_key1); 1173 | ramc_key2 = Memory_ReadByte(addr_key2); 1174 | ramc_key3 = Memory_ReadByte(addr_key3); 1175 | 1176 | ramc_CalibrationOffset = Memory_ReadInt(addr_CalibrationOffset); 1177 | 1178 | readIDMemory(); 1179 | } 1180 | 1181 | 1182 | void writeSettingsMemory() 1183 | { 1184 | //To ensure the program routines are as common as possible betweeen transmitter and receiver 1185 | //this program uses constants in RAM copied from Memory (EEPROM or FRAM) 1186 | 1187 | Serial.println(F("Write RAM Settings to Memory")); 1188 | 1189 | Memory_Set(addr_StartConfigData, addr_EndConfigData, 0); //fill config area with 0 1190 | writeIDMemory(); 1191 | 1192 | Memory_WriteULong(addr_TrackerMode_Frequency, ramc_TrackerMode_Frequency); 1193 | Memory_WriteByte(addr_TrackerMode_Bandwidth, ramc_TrackerMode_Bandwidth); 1194 | Memory_WriteByte(addr_TrackerMode_SpreadingFactor, ramc_TrackerMode_SpreadingFactor); 1195 | Memory_WriteByte(addr_TrackerMode_CodeRate, ramc_TrackerMode_CodeRate); 1196 | Memory_WriteByte(addr_TrackerMode_Power, ramc_TrackerMode_Power); 1197 | 1198 | Memory_WriteULong(addr_SearchMode_Frequency, ramc_SearchMode_Frequency); 1199 | Memory_WriteByte(addr_SearchMode_Bandwidth, ramc_SearchMode_Bandwidth); 1200 | Memory_WriteByte(addr_SearchMode_SpreadingFactor, ramc_SearchMode_SpreadingFactor); 1201 | Memory_WriteByte(addr_SearchMode_CodeRate, ramc_SearchMode_CodeRate); 1202 | Memory_WriteByte(addr_SearchMode_Power, ramc_SearchMode_Power); 1203 | 1204 | Memory_WriteULong(addr_CommandMode_Frequency, ramc_CommandMode_Frequency); 1205 | Memory_WriteByte(addr_CommandMode_Bandwidth, ramc_CommandMode_Bandwidth); 1206 | Memory_WriteByte(addr_CommandMode_SpreadingFactor, ramc_CommandMode_SpreadingFactor); 1207 | Memory_WriteByte(addr_CommandMode_CodeRate, ramc_CommandMode_CodeRate); 1208 | Memory_WriteByte(addr_CommandMode_Power, ramc_CommandMode_Power); 1209 | 1210 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 1211 | Memory_WriteByte(addr_RemoteControlNode, ramc_RemoteControlNode); 1212 | 1213 | Memory_WriteByte(addr_ThisNode, ramc_ThisNode); 1214 | Memory_WriteByte(addr_RemoteControlNode, ramc_RemoteControlNode); 1215 | 1216 | Memory_WriteByte(addr_Default_config1, ramc_Current_TXconfig1); 1217 | Memory_WriteByte(addr_Cmd_WaitSecs, ramc_Cmd_WaitSecs); 1218 | Memory_WriteUInt(addr_WaitGPSFixSeconds, ramc_WaitGPSFixSeconds); 1219 | Memory_WriteUInt(addr_Sleepsecs, ramc_Sleepsecs); 1220 | Memory_WriteByte(addr_promiscuous_Mode, ramc_promiscuous_Mode); 1221 | 1222 | Memory_WriteUInt(addr_FSKRTTYbaudDelay, ramc_FSKRTTYbaudDelay); 1223 | Memory_WriteByte(addr_FSKRTTYRegshift, ramc_FSKRTTYRegshift); 1224 | Memory_WriteByte(addr_FSKRTTYpips, ramc_FSKRTTYpips); 1225 | Memory_WriteUInt(addr_FSKRTTYleadin, ramc_FSKRTTYleadin); 1226 | Memory_WriteByte(addr_key0, ramc_key0); 1227 | Memory_WriteByte(addr_key1, ramc_key1); 1228 | Memory_WriteByte(addr_key2, ramc_key2); 1229 | Memory_WriteByte(addr_key3, ramc_key3); 1230 | 1231 | Memory_WriteInt(addr_CalibrationOffset, ramc_CalibrationOffset); 1232 | } 1233 | 1234 | 1235 | void writeIDMemory() 1236 | { 1237 | unsigned int i, addr; 1238 | byte j; 1239 | j = sizeof(Flight_ID); 1240 | j--; 1241 | addr = addr_FlightID; 1242 | for (i = 0; i <= j; i++) 1243 | { 1244 | Memory_WriteByte(addr, Flight_ID[i]); 1245 | addr++; 1246 | } 1247 | } 1248 | 1249 | void readIDMemory() 1250 | { 1251 | unsigned int addr; 1252 | byte i; 1253 | byte j = 0; 1254 | 1255 | addr = addr_FlightID; 1256 | do 1257 | { 1258 | i = Memory_ReadByte(addr); 1259 | Flight_ID[j++] = i; 1260 | addr++; 1261 | } 1262 | while (i != 0) ; 1263 | } 1264 | 1265 | 1266 | void saveKeyin_buffer() 1267 | { 1268 | lora_TXBUFF[0] = key0; //key used in sme packets to reduce chances of a change being applied by accident 1269 | lora_TXBUFF[1] = key1; 1270 | lora_TXBUFF[2] = key2; 1271 | lora_TXBUFF[3] = key3; 1272 | } 1273 | 1274 | 1275 | void printMemoryChange(byte number) 1276 | { 1277 | #ifdef DEBUG 1278 | byte index, j; 1279 | Serial.print(F("Memory Change")); 1280 | for (index = 0; index <= number; index++) 1281 | { 1282 | j = lora_RXBUFF[index]; 1283 | Serial.print(F(" ")); 1284 | Serial.print(j, HEX); 1285 | } 1286 | Serial.println(); 1287 | #endif 1288 | } 1289 | 1290 | 1291 | void writePacketMemory() 1292 | { 1293 | //there is an incoming packet which is a request to write bytes to Memory. 1294 | //the effect is to change stored program definitions and constants 1295 | byte i, j, k, ptr; 1296 | //byte i, j, k, ptr, low, high; 1297 | unsigned int addr_Memory; 1298 | //float tempfloat; 1299 | 1300 | //packet format is key0, key1, key2, key3, number of bytes to write, address to write to, bytes to write 1301 | //terminate list with 0 bytes to write. 1302 | 1303 | if (isKeyValid()) 1304 | { 1305 | Serial.print(F("Not Valid")); 1306 | return; 1307 | } 1308 | 1309 | i = lora_RXPacketL - 4; //end of packet will be length - 1 for 0 offset and -3 for adddress bytes 1310 | 1311 | printMemoryChange(i); 1312 | 1313 | ptr = 4; 1314 | 1315 | j = lora_RXBUFF[ptr++]; 1316 | 1317 | addr_Memory = Read_Int(5, lora_RXBUFF); //read address for frequency offset into buffer 1318 | 1319 | ptr++; 1320 | ptr++; 1321 | 1322 | Serial.println(F("Write memory ")); 1323 | 1324 | for (i = 1; i <= j; i++) 1325 | { 1326 | Memory_WriteByte(addr_Memory, lora_RXBUFF[ptr]); 1327 | k = lora_RXBUFF[ptr]; 1328 | Serial.print(k, HEX); 1329 | Serial.print(F(" ")); 1330 | addr_Memory++; 1331 | ptr++; 1332 | } 1333 | readSettingsMemory(); 1334 | Setup_TrackerMode(); //dummy change so we can see if offset chnages 1335 | } 1336 | 1337 | 1338 | 1339 | void sendTrackerBind() 1340 | { 1341 | unsigned int i, j; 1342 | byte msb_CRC, lsb_CRC; 1343 | unsigned int bindCRC; 1344 | 1345 | saveKeyin_buffer(); //loads key in bytes 0,1,2,3 of TX buffer 1346 | 1347 | lora_TXEnd = 4; //this is where the bind data starts 1348 | 1349 | for (i = addr_StartBindData; i <= addr_EndBindData; i++) 1350 | { 1351 | j = Memory_ReadByte(i); 1352 | lora_TXBUFF[lora_TXEnd++] = j; 1353 | } 1354 | 1355 | bindCRC = Print_CRC_Bind_Memory(); 1356 | msb_CRC = highByte(bindCRC); 1357 | lsb_CRC = lowByte(bindCRC); 1358 | lora_TXBUFF[lora_TXEnd++] = lsb_CRC; 1359 | lora_TXBUFF[lora_TXEnd] = msb_CRC; 1360 | 1361 | #ifdef DEBUG 1362 | Serial.print(F("Bind PacketLen ")); 1363 | Serial.println(lora_TXEnd + 4); //allow for 3 addressing bytes in length, plus 1 for packet starting at [0] 1364 | #endif 1365 | 1366 | lora_Send(0, lora_TXEnd, Bind, ramc_RemoteControlNode, ramc_ThisNode, 10, BindMode_Power, 0); 1367 | 1368 | } 1369 | 1370 | 1371 | void printNodes() 1372 | { 1373 | Serial.print(F("ThisNode ")); 1374 | Serial.print(ramc_ThisNode); 1375 | Serial.print(F(" RemoteNode ")); 1376 | Serial.println(ramc_RemoteControlNode); 1377 | Serial.println(); 1378 | } 1379 | 1380 | 1381 | void Setup_TrackerMode() 1382 | { 1383 | lora_SetFreq(ramc_TrackerMode_Frequency, ramc_CalibrationOffset); 1384 | lora_SetModem2(ramc_TrackerMode_Bandwidth, ramc_TrackerMode_SpreadingFactor, ramc_TrackerMode_CodeRate, Explicit); //Setup the LoRa modem parameters for tracker mode 1385 | lora_Power = ramc_TrackerMode_Power; 1386 | } 1387 | 1388 | 1389 | void Setup_LoRaSearchMode() 1390 | { 1391 | lora_SetFreq(ramc_SearchMode_Frequency, ramc_CalibrationOffset); 1392 | lora_SetModem2(ramc_SearchMode_Bandwidth, ramc_SearchMode_SpreadingFactor, ramc_SearchMode_CodeRate, Explicit); //Setup the LoRa modem parameters for search mode 1393 | } 1394 | 1395 | 1396 | void Setup_LoRaCommandMode() 1397 | { 1398 | lora_SetFreq(ramc_CommandMode_Frequency, ramc_CalibrationOffset); 1399 | lora_SetModem2(ramc_CommandMode_Bandwidth, ramc_CommandMode_SpreadingFactor, ramc_CommandMode_CodeRate, Explicit); //Setup the LoRa modem parameters for command mode 1400 | lora_Power = ramc_CommandMode_Power; 1401 | } 1402 | 1403 | 1404 | void Setup_LoRaBindMode() 1405 | { 1406 | lora_SetFreq(BindMode_Frequency, ramc_CalibrationOffset); 1407 | lora_SetModem2(BindMode_Bandwidth, BindMode_SpreadingFactor, BindMode_CodeRate, Explicit); //Setup the LoRa modem parameters for bind mode 1408 | lora_Power = BindMode_Power; 1409 | } 1410 | 1411 | 1412 | void display_current_frequency() 1413 | { 1414 | float freq_temp; 1415 | freq_temp = lora_GetFreq(); 1416 | Serial.print(F("Frequency ")); 1417 | Serial.print(freq_temp, 3); 1418 | Serial.println(F("MHz")); 1419 | } 1420 | 1421 | 1422 | void led_Flash(unsigned int flashes, unsigned int delaymS) 1423 | { 1424 | //flash LED to show tracker is alive 1425 | unsigned int index; 1426 | 1427 | for (index = 1; index <= flashes; index++) 1428 | { 1429 | digitalWrite(LED1, HIGH); 1430 | delay(delaymS); 1431 | digitalWrite(LED1, LOW); 1432 | delay(delaymS); 1433 | } 1434 | } 1435 | 1436 | 1437 | //******************************************************************************************************* 1438 | // Memory Routines 1439 | //******************************************************************************************************* 1440 | 1441 | void do_ClearSavedData() 1442 | { 1443 | //clears the whole of memory, normally 1kbyte 1444 | Serial.println(F("Clear Saved Memory")); 1445 | Memory_Set(addr_StartMemory, addr_EndMemory, 0); 1446 | } 1447 | 1448 | void Clear_All_Memory() 1449 | { 1450 | //clears the whole of memory, normally 1kbyte 1451 | Serial.println(F("Clear All Memory")); 1452 | Memory_Set(addr_StartMemory, addr_EndMemory, 0); 1453 | } 1454 | 1455 | 1456 | void Print_Config_Memory() 1457 | { 1458 | //prints the memory used for storing configuration settings 1459 | byte memory_LLoopv1; 1460 | byte memory_LLoopv2; 1461 | unsigned int memory_Laddr = 0; 1462 | byte memory_Ldata; 1463 | //unsigned int CRC; 1464 | Serial.println(F("Config Memory")); 1465 | Serial.print(F("Lcn 0 1 2 3 4 5 6 7 8 9 A B C D E F")); 1466 | Serial.println(); 1467 | 1468 | for (memory_LLoopv1 = 0; memory_LLoopv1 <= 15; memory_LLoopv1++) 1469 | { 1470 | Serial.print(F("0x")); 1471 | Serial.print(memory_LLoopv1, HEX); //print the register number 1472 | Serial.print(F("0 ")); 1473 | for (memory_LLoopv2 = 0; memory_LLoopv2 <= 15; memory_LLoopv2++) 1474 | { 1475 | memory_Ldata = Memory_ReadByte(memory_Laddr); 1476 | if (memory_Ldata < 0x10) { 1477 | Serial.print(F("0")); 1478 | } 1479 | Serial.print(memory_Ldata, HEX); //print the register number 1480 | Serial.print(F(" ")); 1481 | memory_Laddr++; 1482 | } 1483 | Serial.println(); 1484 | } 1485 | } 1486 | 1487 | 1488 | void Print_CRC_Config_Memory() 1489 | { 1490 | unsigned int returnedCRC = Memory_CRC(addr_StartConfigData, addr_EndConfigData); 1491 | Serial.print(F("CRC_Config ")); 1492 | Serial.println(returnedCRC, HEX); 1493 | } 1494 | 1495 | 1496 | unsigned int Print_CRC_Bind_Memory() 1497 | { 1498 | unsigned int returnedCRC = Memory_CRC(addr_StartBindData, addr_EndBindData); 1499 | Serial.print(F("Local BindCRC ")); 1500 | Serial.println(returnedCRC, HEX); 1501 | return returnedCRC; 1502 | } 1503 | 1504 | 1505 | void setup() 1506 | { 1507 | unsigned long int i; 1508 | unsigned int j; 1509 | 1510 | pinMode(LED1, OUTPUT); //for PCB LED 1511 | pinMode(WDI, OUTPUT); //for Watchdog pulse input 1512 | 1513 | led_Flash(2, 500); 1514 | 1515 | Serial.begin(38400); //Setup Serial console ouput 1516 | 1517 | Memory_Start(); 1518 | 1519 | #ifdef ClearAllMemory 1520 | Clear_All_Memory(); 1521 | #endif 1522 | 1523 | 1524 | Serial.println(F(programname)); 1525 | Serial.println(F(aurthorname)); 1526 | 1527 | pinMode(GPSPOWER, OUTPUT); //in case power switching components are fitted 1528 | GPS_On(DoGPSPowerSwitch); //this will power the GPSon 1529 | GPSonTime = millis(); 1530 | 1531 | #ifdef USING_SERIALGPS 1532 | GPSserial.end(); //but we dont want soft serial running for now, it interferes with the LoRa device 1533 | #endif 1534 | 1535 | pinMode(lora_NReset, OUTPUT); //LoRa device reset line 1536 | digitalWrite(lora_NReset, HIGH); 1537 | 1538 | pinMode (lora_NSS, OUTPUT); //set the slave select pin as an output: 1539 | digitalWrite(lora_NSS, HIGH); 1540 | 1541 | SPI.begin(); //initialize SPI 1542 | SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 1543 | 1544 | 1545 | #ifdef ClearSavedData 1546 | do_ClearSavedData(); 1547 | #endif 1548 | 1549 | Serial.print(F("Default_Config1 ")); 1550 | Serial.println(Default_config1, BIN); 1551 | current_mASecs = Memory_ReadULong(addr_mASecs); 1552 | 1553 | Serial.print(F("mASecs ")); 1554 | Serial.println(current_mASecs); 1555 | 1556 | j = Memory_ReadUInt(addr_ResetCount); 1557 | j++; 1558 | Memory_WriteUInt(addr_ResetCount, j); 1559 | Serial.print(F("Resets ")); 1560 | Serial.println(j); 1561 | Serial.print(F("Sequence ")); 1562 | i = Memory_ReadULong(addr_SequenceNum); 1563 | Serial.println(i); 1564 | 1565 | 1566 | #ifdef ConfigureDefaults 1567 | readSettingsDefaults(); 1568 | writeSettingsMemory(); 1569 | #endif 1570 | 1571 | 1572 | #ifdef ConfigureFromMemory 1573 | readSettingsMemory(); 1574 | #endif 1575 | 1576 | Print_CRC_Config_Memory(); 1577 | 1578 | ramc_ThisNode = ThisNode; 1579 | 1580 | #ifdef DEBUG 1581 | printNodes(); 1582 | #endif 1583 | 1584 | lora_Setup(); 1585 | 1586 | if (!lora_CheckDevice()) 1587 | { 1588 | led_Flash(100, 50); //long medium speed flash for Lora device error 1589 | Serial.println(F("LoRa Error!")); 1590 | } 1591 | 1592 | #ifdef DEBUG 1593 | display_current_frequency(); 1594 | #endif 1595 | 1596 | ramc_CalibrationOffset = Memory_ReadInt(addr_CalibrationOffset); //get calibration offset for this tracker 1597 | Serial.print(F("Cal Offset ")); 1598 | Serial.println(ramc_CalibrationOffset); 1599 | 1600 | #ifdef DEBUG 1601 | lora_Print(); 1602 | #endif 1603 | 1604 | Serial.println(); 1605 | print_SupplyVoltage(); 1606 | print_Temperature(); 1607 | Serial.println(); 1608 | 1609 | j = read_SupplyVoltage(); //get supply mV 1610 | Write_Int(0, j, lora_TXBUFF); //write to first two bytes of buffer 1611 | Write_Byte(2, ramc_Current_TXconfig1, lora_TXBUFF); //add the current config byte 1612 | 1613 | Setup_TrackerMode(); 1614 | send_Command(PowerUp); //send power up command, includes supply mV and config, on tracker settings 1615 | sleepSecs(1); 1616 | 1617 | #ifdef SendBind 1618 | if (readConfigByte(TXEnable)) //is TX enabled ? 1619 | { 1620 | Setup_LoRaBindMode(); 1621 | sendTrackerBind(); 1622 | } 1623 | #endif 1624 | 1625 | Setup_TrackerMode(); //so that check tone is at correct frequency 1626 | 1627 | GPS_Config_Error = false; //make sure GPS error flag is cleared 1628 | 1629 | #ifndef DEBUGNoGPS 1630 | GPS_On(DoGPSPowerSwitch); //GPS should have been on for a while by now, so this is just to start soft serial 1631 | GPSonTime = millis(); 1632 | GPS_Setup(); //GPS should have had plenty of time to initialise by now 1633 | 1634 | #ifdef UBLOX 1635 | if (!GPS_CheckNavigation()) //Check that UBLOX GPS is in Navigation model 6 1636 | { 1637 | Serial.println(); 1638 | GPS_Config_Error = true; 1639 | setStatusByte(GPSError, 1); 1640 | setStatusByte(UBLOXDynamicModel6Set, 0); 1641 | } 1642 | else 1643 | { 1644 | setStatusByte(UBLOXDynamicModel6Set, 1); 1645 | } 1646 | #endif 1647 | 1648 | if (GPS_Config_Error) 1649 | { 1650 | Serial.println(F("GPS Error !")); 1651 | Serial.println(); 1652 | send_Command(NoGPS); //make sure receiver knows about GPS error 1653 | led_Flash(100, 25); //long very rapid flash for GPS error 1654 | } 1655 | else 1656 | { 1657 | #ifdef CheckTone 1658 | if (readConfigByte(TXEnable)) //is TX enabled - needed because of fence limits 1659 | { 1660 | Serial.println(F("Check Tone")); //check tone indicates navigation model 6 set (if checktone enabled!) 1661 | lora_Tone(1000, 3000, 5); //Transmit an FM tone, 1000hz, 3000ms, 5dBm 1662 | } 1663 | #endif 1664 | } 1665 | 1666 | digitalWrite(LED1, HIGH); 1667 | setStatusByte(NoGPSTestMode, 0); 1668 | GPSonTime = millis(); 1669 | while (!gpsWaitFix(5, DontSwitch, LeaveOn)) //wait for the initial GPS fix, this could take a while, leave GPS powered on 1670 | { 1671 | 1672 | led_Flash(2, 50); //two short LED flashes to indicate GPS waiting for fix 1673 | 1674 | #ifdef DEBUG 1675 | i = (millis() - GPSonTime) / 1000; 1676 | Serial.print(F("GPS OnTime ")); 1677 | Serial.print(i); 1678 | Serial.println(F(" Secs")); 1679 | #endif 1680 | } 1681 | addmASecs(GPSmA, (GPSFixTime + GPSShutdownTimemS), 3); //add GPS consumed current to total 1682 | #endif 1683 | 1684 | #ifndef DEBUGNoGPS 1685 | GPS_On(DoGPSPowerSwitch); 1686 | GPS_SetCyclicMode(); //set this regardless of whether hot fix mode is enabled 1687 | #endif 1688 | 1689 | lora_Tone(500, 500, 2); //Transmit an FM tone, 500hz, 500ms, 2dBm 1690 | digitalWrite(LED1, LOW); 1691 | sleepSecs(2); //wait for GPS to shut down 1692 | 1693 | #ifdef DEBUGNoGPS 1694 | setStatusByte(NoGPSTestMode, 1); 1695 | #endif 1696 | 1697 | setConfigByte(DozeEnable, Disabled); //ensure Doze mode disabled at reset 1698 | } 1699 | --------------------------------------------------------------------------------