diff --git a/Framing.h b/Framing.h
index efa4b31..79a5b38 100644
--- a/Framing.h
+++ b/Framing.h
@@ -77,6 +77,9 @@
#define CMD_RESET 0x55
#define CMD_RESET_BYTE 0xF8
+ #define CMD_GPS_CMD 0xA0
+ #define CMD_GPS_RATE 0xA1
+
#define DETECT_REQ 0x73
#define DETECT_RESP 0x46
diff --git a/GPS.h b/GPS.h
new file mode 100644
index 0000000..f1a94d8
--- /dev/null
+++ b/GPS.h
@@ -0,0 +1,443 @@
+// Copyright (C) 2024, Michael Faragher
+// Extended from the RNode Firmware. Copyright (C) 2023, Mark Qvist
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+//#include
+
+
+char GPS_Buffer[100];
+byte GPS_Index;
+char GPSGGA[100] = " ";
+char GPSGLL[100] = " ";
+char GPSVTG[100] = " ";
+char GPSRMC[100] = " ";
+char GPSTime[6] = {'9','0','0','0','0','0'};
+bool isGPS_Automated = false;
+bool isGPS_Waiting_Time = false;
+bool isGPS_Waiting_Location = false;
+bool isGPS_Waiting_NMEA = false;
+char GPS_Lat[8] = {'N','O',' ',' ','F','I','X','X'};
+char GPS_Lon[9] = {'N','O',' ',' ',' ','F','I','X','X'};
+
+#define GPS_CMD_TIME 0x00
+#define GPS_CMD_LOCATION 0x01
+#define GPS_CMD_RATE 0x02
+#define GPS_CMD_SENTENCE 0x03
+#define GPS_CMD_ENABLE_HEARTBEAT 0x10
+#define GPS_CMD_DISABLE_HEARTBEAT 0x11
+#define GPS_CMD_ENABLE_AUTOMATIC 0x12
+#define GPS_CMD_DISABLE_AUTOMATIC 0x13
+#define GPS_CMD_HOT 0x20
+#define GPS_CMD_COLD 0x21
+
+
+byte NMEA_checksum(char message[], byte length){
+ byte buffer = 0;
+ byte working;
+ for(byte i = 0; i < length; i++){
+ working = message[int(i)];// Apparently not & 127; //Lower seven bits
+ buffer = buffer ^ working; //XORed
+ }
+ return buffer;
+}
+
+void GPS_poling(byte Target, byte Rate){ //Divisor, 0 = off, 1-?, 0-9 in this implementation
+ //Targets:
+ // 0 GGA
+ // 1 GLL
+ // 2 GSA
+ // 3 GSV
+ // 4 RMC
+ // 5 VTG
+ char cRate[10] = {'0','1','2','3','4','5','6','7','8','9'};
+ //char cTarget[6] = {'0','1','2','3','4','5'};
+ char cTargetA[6] = {'G','G','G','G','R','V'};
+ char cTargetB[6] = {'G','L','S','S','M','T'};
+ char cTargetC[6] = {'A','L','A','V','C','G'};
+ char message[24] = "PUBX,40,GGA,0,0,0,0,0,0";
+ if(Rate>9){Rate=9;}
+ if(Rate<0){Rate=0;}
+ //itoa(Rate, cRate,10);
+ message[14]=cRate[Rate];
+ message[8] = cTargetA[int(Target)];
+ message[9] = cTargetB[int(Target)];
+ message[10] = cTargetC[int(Target)];
+ byte checksum = NMEA_checksum(message, 19);
+
+ Serial2.write('$');
+ for(int i = 0; i < 19; i++){
+ Serial2.write(message[i]);
+ }
+
+ Serial2.write('*');
+ Serial2.print(checksum,HEX);
+ Serial2.write(0x0d);
+ Serial2.write(0x0a);
+
+
+}
+
+void GPS_request(byte Target){
+ //Targets:
+ // 0 GGA
+ // 1 GLL
+ // 2 GSA
+ // 3 GSV
+ // 4 RMC
+ // 5 VTG
+ if(Target>5){return;}
+ char cTargetA[6] = {'G','G','G','G','R','V'};
+ char cTargetB[6] = {'G','L','S','S','M','T'};
+ char cTargetC[6] = {'A','L','A','V','C','G'};
+ char message[10] = "EIGPQ,GGA";
+ message[6] = cTargetA[int(Target)];
+ message[7] = cTargetB[int(Target)];
+ message[8] = cTargetC[int(Target)];
+ byte checksum = NMEA_checksum(message, 9);
+
+ Serial2.write('$');
+ for(int i = 0; i < 9; i++){
+ Serial2.write(message[i]);
+ }
+
+ Serial2.write('*');
+ Serial2.print(checksum,HEX);
+ Serial2.write(0x0d);
+ Serial2.write(0x0a);
+
+}
+
+void GPS_Query_Time(){
+ if(GPSTime[0]!='9'){
+ serial_write(FEND);
+ serial_write(CMD_GPS_CMD);
+ serial_write(GPS_CMD_TIME);
+ for(int i = 0; i < 6; i++){
+ serial_write(GPSTime[i]);
+ }
+ serial_write(FEND);
+ //debug
+ serial_write(char(13));
+ serial_write(char(10));
+ //eng debug
+ }
+ else{//if time not buffered
+ isGPS_Waiting_Time = true;
+ }
+}
+
+void GPS_Query_Location(){
+ if(GPS_Lon[0]=='0'||GPS_Lon[0]=='1'){
+ serial_write(' ');
+ serial_write(GPS_Lat[0]);
+ serial_write(GPS_Lat[1]);
+ serial_write(' ');
+ serial_write(GPS_Lat[2]);
+ serial_write(GPS_Lat[3]);
+ serial_write('.');
+ serial_write(GPS_Lat[4]);
+ serial_write(GPS_Lat[5]);
+ serial_write(GPS_Lat[6]);
+ serial_write('\'');
+ serial_write(' ');
+ serial_write(GPS_Lat[7]);
+ serial_write(char(13));
+ serial_write(char(10));
+
+ serial_write(GPS_Lon[0]);
+ serial_write(GPS_Lon[1]);
+ serial_write(GPS_Lon[2]);
+ serial_write(' ');
+ serial_write(GPS_Lon[3]);
+ serial_write(GPS_Lon[4]);
+ serial_write('.');
+ serial_write(GPS_Lon[5]);
+ serial_write(GPS_Lon[6]);
+ serial_write(GPS_Lon[7]);
+ serial_write('\'');
+ serial_write(' ');
+ serial_write(GPS_Lon[8]);
+ serial_write(char(13));
+ serial_write(char(10));
+ }
+ else{
+ isGPS_Waiting_Location = true;
+ }
+}
+
+
+void GPS_Parse_Time(){
+ if(GPSGGA[8]==','){return;}
+ for(int i = 0; i < 6; i++){
+ GPSTime[i] = GPSGGA[8+i];
+ }
+}
+
+void GPS_Parse_Location(){
+ if(GPSGGA[18]!=','){
+ if(GPSGGA[31]=='0'||GPSGGA[31]=='1'){
+ GPS_Lat[0] = GPSGGA[18];
+ GPS_Lat[1] = GPSGGA[19];
+ GPS_Lat[2] = GPSGGA[20];
+ GPS_Lat[3] = GPSGGA[21];
+ GPS_Lat[4] = GPSGGA[23];
+ GPS_Lat[5] = GPSGGA[24];
+ GPS_Lat[6] = GPSGGA[25];
+ GPS_Lat[7] = GPSGGA[29];
+
+ GPS_Lon[0] = GPSGGA[31];
+ GPS_Lon[1] = GPSGGA[32];
+ GPS_Lon[2] = GPSGGA[33];
+ GPS_Lon[3] = GPSGGA[34];
+ GPS_Lon[4] = GPSGGA[35];
+ GPS_Lon[5] = GPSGGA[37];
+ GPS_Lon[6] = GPSGGA[38];
+ GPS_Lon[7] = GPSGGA[39];
+ GPS_Lon[8] = GPSGGA[43];
+ }
+ }
+
+
+
+}
+
+void GPS_init(){
+ Serial2.begin(GPS_BAUD_RATE, SERIAL_8N1, PIN_GPS_RX, PIN_GPS_TX);
+ GPS_poling(0,0);
+ GPS_poling(1,0);
+ GPS_poling(2,0);
+ GPS_poling(3,0);
+ GPS_poling(4,0);
+ GPS_poling(5,0);
+
+}
+
+void GPS_sweep(){
+ char coi[1];
+ Serial2.readBytes(coi,1);
+ if(coi[0] == char(13)){
+
+ if(GPS_Buffer[4]=='G'&&GPS_Buffer[5]=='G'&&GPS_Buffer[6]=='A'){
+ memset(GPSGGA,0xFF,100);
+ strncpy(GPSGGA,GPS_Buffer,GPS_Index);
+ GPS_Parse_Time();
+ GPS_Parse_Location();
+ if(isGPS_Waiting_Time){
+ isGPS_Waiting_Time = false;
+ GPS_Query_Time();
+ }
+ if(isGPS_Waiting_Location){
+ isGPS_Waiting_Location = false;
+ GPS_Query_Location();
+ }
+ }
+ if(GPS_Buffer[4]=='G'&&GPS_Buffer[5]=='L'&&GPS_Buffer[6]=='L'){
+ memset(GPSGLL,0xFF,100);
+ strncpy(GPSGLL,GPS_Buffer,GPS_Index);
+ }
+ if(GPS_Buffer[4]=='V'&&GPS_Buffer[5]=='T'&&GPS_Buffer[6]=='G'){
+ memset(GPSVTG,0xFF,100);
+ strncpy(GPSVTG,GPS_Buffer,GPS_Index);
+ }
+ if(GPS_Buffer[4]=='R'&&GPS_Buffer[5]=='M'&&GPS_Buffer[6]=='C'){
+ memset(GPSRMC,0xFF,100);
+ strncpy(GPSRMC,GPS_Buffer,GPS_Index);
+ }
+ GPS_Index = 0;
+ memset(GPS_Buffer,0xFF,100);
+ }
+ else {
+ GPS_Buffer[GPS_Index] = coi[0];
+ GPS_Index++;
+ }
+
+ if(GPS_Index > 98){
+ //Serial.println("ERROR");
+ //Serial.println("Buffer Overflow: GPS");
+ GPS_Index=0;
+ memset(GPS_Buffer,0xFF,100);
+ }
+
+}
+
+
+
+
+
+
+
+void GPS_SetAutomatic(bool state)
+{
+ isGPS_Automated = state;
+}
+
+// Updates all useful buffers at full rate
+void GPS_Go_Hot(){
+ GPS_poling(0,1);
+ GPS_poling(1,1);
+ GPS_poling(2,0);
+ GPS_poling(3,0);
+ GPS_poling(4,1);
+ GPS_poling(5,1);
+}
+
+// Shuts down automated buffering
+void GPS_Go_Cold(){
+ GPS_poling(0,0);
+ GPS_poling(1,0);
+ GPS_poling(2,0);
+ GPS_poling(3,0);
+ GPS_poling(4,0);
+ GPS_poling(5,0);
+}
+
+void GPS_Enable_Heartbeat(bool state){
+ if(state){
+ GPS_poling(0,1);
+ GPS_SetAutomatic(true);
+ }
+ else
+ {
+ GPS_poling(0,0);
+ GPS_SetAutomatic(false);
+ }
+
+}
+
+void GPS_send(){
+ if(GPSGGA[1]=='$'){
+ byte i = 0;
+ char coi;
+ serial_write(FEND);
+ serial_write(CMD_GPS_CMD);
+ serial_write(GPS_CMD_SENTENCE);
+ while(coi != 0xFF){
+ coi = GPSGGA[i];
+ if(coi != 0xFF){serial_write(coi);}
+ i++;
+ if(i>99){break;}
+ }
+ serial_write(FEND);
+// Serial.println("");
+// GPSGGA[0]=0;
+ memset(GPSGGA,0xFF,100);
+ }
+
+ if(GPSGLL[1]=='$'){
+ byte i = 0;
+ char coi;
+ serial_write(FEND);
+ serial_write(CMD_GPS_CMD);
+ serial_write(GPS_CMD_SENTENCE);
+ while(coi != 0xFF){
+ coi = GPSGLL[i];
+ if(coi != 0xFF){serial_write(coi);}
+ i++;
+ if(i>99){break;}
+ }
+ serial_write(FEND);
+// GPSGLL[0]=0;
+ memset(GPSGLL,0xFF,100);
+ }
+
+ if(GPSVTG[1]=='$'){
+ byte i = 0;
+ char coi;
+ serial_write(FEND);
+ serial_write(CMD_GPS_CMD);
+ serial_write(GPS_CMD_SENTENCE);
+ while(coi != 0xFF){
+ coi = GPSVTG[i];
+ if(coi != 0xFF){serial_write(coi);}
+ i++;
+ if(i>99){break;}
+ }
+ serial_write(FEND);
+// GPSVTG[0]=0;
+ memset(GPSVTG,0xFF,100);
+ }
+
+ if(GPSRMC[1]=='$'){
+ byte i = 0;
+ char coi;
+ serial_write(FEND);
+ serial_write(CMD_GPS_CMD);
+ serial_write(GPS_CMD_SENTENCE);
+ while(coi != 0xFF){
+ coi = GPSRMC[i];
+ if(coi != 0xFF){serial_write(coi);}
+ i++;
+ if(i>99){break;}
+ }
+ serial_write(FEND);
+// GPSRMC[0]=0;
+ memset(GPSRMC,0xFF,100);
+ }
+}
+
+void kiss_GPS_send(){
+ GPS_send();
+}
+
+void kiss_GPS_location(){
+
+}
+
+void kiss_GPS_time(){
+
+}
+
+void GPS_Query_NMEA(){
+ GPS_send();
+}
+
+
+void GPS_process(){
+ GPS_sweep();
+ if(isGPS_Automated || isGPS_Waiting_NMEA){
+ GPS_send();
+ }
+}
+
+void GPS_handler(byte CMD){
+ if(CMD==GPS_CMD_TIME){
+ GPS_Query_Time();
+ }
+ if(CMD== GPS_CMD_LOCATION){
+ GPS_Query_Location();
+ }
+ if(CMD==GPS_CMD_SENTENCE){
+ GPS_Query_NMEA();
+ }
+ if(CMD==GPS_CMD_ENABLE_HEARTBEAT){
+ GPS_Enable_Heartbeat(true);
+ }
+ if(CMD==GPS_CMD_DISABLE_HEARTBEAT){
+ GPS_Enable_Heartbeat(false);
+ }
+ if(CMD==GPS_CMD_HOT){
+ GPS_Go_Hot();
+ }
+ if(CMD==GPS_CMD_COLD){
+ GPS_Go_Cold();
+ }
+ if(CMD==GPS_CMD_ENABLE_AUTOMATIC){
+ GPS_SetAutomatic(true);
+ }
+ if(CMD==GPS_CMD_DISABLE_AUTOMATIC){
+ GPS_SetAutomatic(false);
+ }
+
+}
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 0d0fb51..dceb08d 100644
--- a/Makefile
+++ b/Makefile
@@ -130,15 +130,15 @@ firmware-rak4631:
arduino-cli compile --log --fqbn rakwireless:nrf52:WisCoreRAK4631Board -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x51\""
upload:
- arduino-cli upload -p /dev/ttyUSB0 --fqbn unsignedio:avr:rnode
+ arduino-cli upload -p /dev/ttyACM0 --fqbn unsignedio:avr:rnode
upload-mega2560:
arduino-cli upload -p /dev/ttyACM0 --fqbn arduino:avr:mega
upload-tbeam:
- arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:t-beam
+ arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:t-beam
@sleep 1
- rnodeconf /dev/ttyUSB0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/RNode_Firmware.ino.bin)
+ rnodeconf /dev/ttyACM0 --firmware-hash $$(./partition_hashes ./build/esp32.esp32.t-beam/RNode_Firmware.ino.bin)
@sleep 3
python ./Release/esptool/esptool.py --chip esp32 --port /dev/ttyACM0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size 4MB 0x210000 ./Release/console_image.bin
@@ -252,6 +252,15 @@ release-tbeam: check_bt_buffers
zip --junk-paths ./Release/rnode_firmware_tbeam.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam.boot_app0 build/rnode_firmware_tbeam.bin build/rnode_firmware_tbeam.bootloader build/rnode_firmware_tbeam.partitions
rm -r build
+release-tbeam_GPS: check_bt_buffers
+ arduino-cli compile --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DENABLE_GPS\""
+ cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_GPS.boot_app0
+ cp build/esp32.esp32.t-beam/RNode_Firmware.ino.bin build/rnode_firmware_tbeam_GPS.bin
+ cp build/esp32.esp32.t-beam/RNode_Firmware.ino.bootloader.bin build/rnode_firmware_tbeam_GPS.bootloader
+ cp build/esp32.esp32.t-beam/RNode_Firmware.ino.partitions.bin build/rnode_firmware_tbeam_GPS.partitions
+ zip --junk-paths ./Release/rnode_firmware_tbeam_GPS.zip ./Release/esptool/esptool.py ./Release/console_image.bin build/rnode_firmware_tbeam_GPS.boot_app0 build/rnode_firmware_tbeam_GPS.bin build/rnode_firmware_tbeam_GPS.bootloader build/rnode_firmware_tbeam_GPS.partitions
+ rm -r build
+
release-tbeam_sx1262: check_bt_buffers
arduino-cli compile --fqbn esp32:esp32:t-beam -e --build-property "build.partitions=no_ota" --build-property "upload.maximum_size=2097152" --build-property "compiler.cpp.extra_flags=\"-DBOARD_MODEL=0x33\" \"-DMODEM=0x03\""
cp ~/.arduino15/packages/esp32/hardware/esp32/$(ARDUINO_ESP_CORE_VER)/tools/partitions/boot_app0.bin build/rnode_firmware_tbeam_sx1262.boot_app0
diff --git a/Power.h b/Power.h
index 1d1dfb8..a5e3a05 100644
--- a/Power.h
+++ b/Power.h
@@ -344,7 +344,10 @@ bool init_pmu() {
PMU->enablePowerOutput(XPOWERS_LDO2);
// Turn on GPS
- //PMU->enablePowerOutput(XPOWERS_LDO3);
+ #if defined(ENABLE_GPS)
+ PMU->enablePowerOutput(XPOWERS_LDO3);
+ PMU->enablePowerOutput(XPOWERS_VBACKUP); // RTC/GPS battery charging
+ #endif
// protected oled power source
PMU->setProtectedChannel(XPOWERS_DCDC1);
@@ -385,9 +388,9 @@ bool init_pmu() {
// Set the power of LoRa and GPS module to 3.3V
// LoRa
PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300);
- // GPS
+ // GPS Voltage
PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300);
- PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300);
+ //PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300); // I don't beleive tihs to be proper or safe. - Faragher
// ESP32 VDD
// ! No need to set, automatically open , Don't close it
@@ -398,11 +401,15 @@ bool init_pmu() {
// LoRa VDD
PMU->enablePowerOutput(XPOWERS_ALDO2);
- // GNSS VDD
- //PMU->enablePowerOutput(XPOWERS_ALDO3);
+ // GPS/GNSS VDD
+ #if defined(ENABLE_GPS)
+ PMU->enablePowerOutput(XPOWERS_ALDO3);
+ #endif
- // GNSS RTC PowerVDD
- //PMU->enablePowerOutput(XPOWERS_VBACKUP);
+ // GNSS RTC Power - Enables charging onboard battery
+ #if defined(ENABLE_GPS)
+ PMU->enablePowerOutput(XPOWERS_VBACKUP);
+ #endif
}
PMU->enableSystemVoltageMeasure();
diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino
index 57a7f2f..aba530f 100644
--- a/RNode_Firmware.ino
+++ b/RNode_Firmware.ino
@@ -41,6 +41,10 @@ volatile bool serial_buffering = false;
#include "Console.h"
#endif
+#if defined(ENABLE_GPS)
+ #include "GPS.h"
+#endif
+
#if PLATFORM == PLATFORM_ESP32 || PLATFORM == PLATFORM_NRF52
#define MODEM_QUEUE_SIZE 4
typedef struct {
@@ -228,6 +232,10 @@ void setup() {
kiss_indicate_reset();
}
#endif
+
+ #if defined(ENABLE_GPS)
+ GPS_init();
+ #endif
// Validate board health, EEPROM and config
validate_status();
@@ -1054,6 +1062,17 @@ void serialCallback(uint8_t sbyte) {
}
}
#endif
+ } else if (command == CMD_GPS_CMD) {
+ #if defined(ENABLE_GPS)
+ GPS_handler(sbyte);
+ #endif
+ } else if (command == CMD_GPS_RATE) {
+ #if defined(ENABLE_GPS)
+ if(frame_len < CMD_L) cmdbuf[frame_len++] = sbyte;
+ if(frame_len == 2){
+ GPS_poling(cmdbuf[0],int(cmdbuf[1]));
+ }
+ #endif
} else if (command == CMD_DISP_INT) {
#if HAS_DISPLAY
if (sbyte == FESC) {
@@ -1475,6 +1494,12 @@ void loop() {
#if HAS_INPUT
input_read();
#endif
+
+ #if defined(ENABLE_GPS)
+ if(hw_ready){
+ GPS_process();
+ }
+ #endif
if (memory_low) {
#if PLATFORM == PLATFORM_ESP32