mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-26 09:59:01 +00:00
Backport T-Echo fix for GPS and Reset Button to 1.2
This commit is contained in:
parent
ba894ae95b
commit
7c253bfc3c
@ -83,9 +83,8 @@ lib_deps =
|
|||||||
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
|
mathertel/OneButton@^2.0.3 ; OneButton library for non-blocking button debounce
|
||||||
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
1202 ; CRC32, explicitly needed because dependency is missing in the ble ota update lib
|
||||||
https://github.com/meshtastic/arduino-fsm.git
|
https://github.com/meshtastic/arduino-fsm.git
|
||||||
https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git#31015a55e630a2df77d9d714669c621a5bf355ad
|
|
||||||
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
https://github.com/meshtastic/RadioLib.git#5582ac30578ff3f53f20630a00b2a8a4b8f92c74
|
||||||
https://github.com/meshtastic/TinyGPSPlus.git#f0f47067ef2f67c856475933188251c1ef615e79
|
https://github.com/meshtastic/TinyGPSPlus.git
|
||||||
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
|
||||||
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
Wire ; explicitly needed here because the AXP202 library forgets to add it
|
||||||
SPI
|
SPI
|
||||||
|
@ -63,7 +63,7 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
int32_t getLatitude() const {
|
int32_t getLatitude() const {
|
||||||
if (radioConfig.preferences.fixed_position){
|
if (radioConfig.preferences.fixed_position){
|
||||||
#if GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
DEBUG_MSG("WARNING: Using fixed latitude\n");
|
DEBUG_MSG("WARNING: Using fixed latitude\n");
|
||||||
#endif
|
#endif
|
||||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||||
@ -75,7 +75,7 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
int32_t getLongitude() const {
|
int32_t getLongitude() const {
|
||||||
if (radioConfig.preferences.fixed_position){
|
if (radioConfig.preferences.fixed_position){
|
||||||
#if GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
DEBUG_MSG("WARNING: Using fixed longitude\n");
|
DEBUG_MSG("WARNING: Using fixed longitude\n");
|
||||||
#endif
|
#endif
|
||||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||||
@ -87,7 +87,7 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
int32_t getAltitude() const {
|
int32_t getAltitude() const {
|
||||||
if (radioConfig.preferences.fixed_position){
|
if (radioConfig.preferences.fixed_position){
|
||||||
#if GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
DEBUG_MSG("WARNING: Using fixed altitude\n");
|
DEBUG_MSG("WARNING: Using fixed altitude\n");
|
||||||
#endif
|
#endif
|
||||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||||
@ -105,7 +105,7 @@ class GPSStatus : public Status
|
|||||||
|
|
||||||
bool matches(const GPSStatus *newStatus) const
|
bool matches(const GPSStatus *newStatus) const
|
||||||
{
|
{
|
||||||
#if GPS_EXTRAVERBOSE
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n",
|
DEBUG_MSG("GPSStatus.match() new pos@%x to old pos@%x\n",
|
||||||
newStatus->p.pos_timestamp, p.pos_timestamp);
|
newStatus->p.pos_timestamp, p.pos_timestamp);
|
||||||
#endif
|
#endif
|
||||||
|
@ -100,6 +100,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define GPS_TX_PIN 12
|
#define GPS_TX_PIN 12
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef TTGO_T_ECHO
|
||||||
|
#define GPS_UBLOX
|
||||||
|
#endif
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// LoRa SPI
|
// LoRa SPI
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -149,6 +153,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
#define GPS_BAUDRATE 9600
|
#define GPS_BAUDRATE 9600
|
||||||
|
|
||||||
|
#ifndef GPS_THREAD_INTERVAL
|
||||||
|
#define GPS_THREAD_INTERVAL 100
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(TBEAM_V10)
|
#if defined(TBEAM_V10)
|
||||||
// This string must exactly match the case used in release file names or the android updater won't work
|
// This string must exactly match the case used in release file names or the android updater won't work
|
||||||
#define HW_VENDOR HardwareModel_TBEAM
|
#define HW_VENDOR HardwareModel_TBEAM
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
#include "Air530GPS.h"
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
Helpful translations from the Air530 GPS datasheet
|
|
||||||
|
|
||||||
Sat acquision mode
|
|
||||||
捕获电流值@3.3v 42.6 mA
|
|
||||||
|
|
||||||
sat tracking mode
|
|
||||||
跟踪电流值@3.3v 36.7 mA
|
|
||||||
|
|
||||||
Low power mode
|
|
||||||
低功耗模式@3.3V 0.85 mA
|
|
||||||
(发送指令:$PGKC051,0)
|
|
||||||
|
|
||||||
Super low power mode
|
|
||||||
超低功耗模式@3.3V 31 uA
|
|
||||||
(发送指令:$PGKC105,4)
|
|
||||||
|
|
||||||
To exit sleep use WAKE pin
|
|
||||||
|
|
||||||
Commands to enter sleep
|
|
||||||
6、Command: 105
|
|
||||||
进入周期性低功耗模式
|
|
||||||
Arguments:
|
|
||||||
|
|
||||||
Arg1: “0”,正常运行模式 (normal mode)
|
|
||||||
“1”,周期超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (periodic low power tracking mode - keeps sat positions, use wake to wake up)
|
|
||||||
“2”,周期低功耗模式 (periodic low power mode)
|
|
||||||
“4”,直接进入超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (super low power consumption mode immediately, need WAKE to resume)
|
|
||||||
“8”,自动低功耗模式,可以通过串口唤醒 (automatic low power mode, wake by sending characters to serial port)
|
|
||||||
“9”, 自动超低功耗跟踪模式,需要拉高 WAKE 来唤醒 (automatic low power tracking when possible, need wake pin to resume)
|
|
||||||
|
|
||||||
(Arg 2 & 3 only valid if Arg1 is "1" or "2")
|
|
||||||
Arg2:运行时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用
|
|
||||||
ON time in msecs
|
|
||||||
|
|
||||||
Arg3:睡眠时间(毫秒),在 Arg1 为 1、2 的周期模式下,此参数起作用
|
|
||||||
Sleep time in msecs
|
|
||||||
|
|
||||||
Example:
|
|
||||||
$PGKC105,8*3F<CR><LF>
|
|
||||||
This will set automatic low power mode with waking when we send chars to the serial port. Possibly do this as soon as we get a
|
|
||||||
new location. When we wake again in a minute we send a character to wake up.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void Air530GPS::sendCommand(const char *cmd) {
|
|
||||||
uint8_t sum = 0;
|
|
||||||
|
|
||||||
// Skip the $
|
|
||||||
assert(cmd[0] == '$');
|
|
||||||
const char *p = cmd + 1;
|
|
||||||
while(*p)
|
|
||||||
sum ^= *p++;
|
|
||||||
|
|
||||||
assert(_serial_gps);
|
|
||||||
|
|
||||||
_serial_gps->write(cmd);
|
|
||||||
_serial_gps->printf("*%02x\r\n", sum);
|
|
||||||
|
|
||||||
// DEBUG_MSG("xsum %02x\n", sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Air530GPS::sleep() {
|
|
||||||
NMEAGPS::sleep();
|
|
||||||
#ifdef PIN_GPS_WAKE
|
|
||||||
sendCommand("$PGKC105,4");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/// wake the GPS into normal operation mode
|
|
||||||
void Air530GPS::wake()
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
NMEAGPS::wake();
|
|
||||||
#else
|
|
||||||
// For power testing - keep GPS sleeping forever
|
|
||||||
sleep();
|
|
||||||
#endif
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "NMEAGPS.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A gps class thatreads from a NMEA GPS stream (and FIXME - eventually keeps the gps powered down except when reading)
|
|
||||||
*
|
|
||||||
* When new data is available it will notify observers.
|
|
||||||
*/
|
|
||||||
class Air530GPS : public NMEAGPS
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
/// If possible force the GPS into sleep/low power mode
|
|
||||||
virtual void sleep() override;
|
|
||||||
|
|
||||||
/// wake the GPS into normal operation mode
|
|
||||||
virtual void wake() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Send a NMEA cmd with checksum
|
|
||||||
void sendCommand(const char *str);
|
|
||||||
};
|
|
106
src/gps/GPS.cpp
106
src/gps/GPS.cpp
@ -16,12 +16,6 @@ HardwareSerial *GPS::_serial_gps = &Serial1;
|
|||||||
HardwareSerial *GPS::_serial_gps = NULL;
|
HardwareSerial *GPS::_serial_gps = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef GPS_I2C_ADDRESS
|
|
||||||
uint8_t GPS::i2cAddress = GPS_I2C_ADDRESS;
|
|
||||||
#else
|
|
||||||
uint8_t GPS::i2cAddress = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GPS *gps;
|
GPS *gps;
|
||||||
|
|
||||||
/// Multiple GPS instances might use the same serial port (in sequence), but we can
|
/// Multiple GPS instances might use the same serial port (in sequence), but we can
|
||||||
@ -41,6 +35,75 @@ bool GPS::setupGPS()
|
|||||||
#endif
|
#endif
|
||||||
#ifndef NO_ESP32
|
#ifndef NO_ESP32
|
||||||
_serial_gps->setRxBufferSize(2048); // the default is 256
|
_serial_gps->setRxBufferSize(2048); // the default is 256
|
||||||
|
#endif
|
||||||
|
#ifdef TTGO_T_ECHO
|
||||||
|
// Switch to 4800 baud, then close and reopen port
|
||||||
|
_serial_gps->write("$PCAS01,0*1C\r\n");
|
||||||
|
delay(250);
|
||||||
|
_serial_gps->end();
|
||||||
|
delay(250);
|
||||||
|
_serial_gps->begin(4800);
|
||||||
|
delay(250);
|
||||||
|
// Initialize the L76K Chip, use GPS + GLONASS
|
||||||
|
_serial_gps->write("$PCAS04,5*1C\r\n");
|
||||||
|
delay(250);
|
||||||
|
// only ask for RMC and GGA
|
||||||
|
_serial_gps->write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n");
|
||||||
|
delay(250);
|
||||||
|
// Switch to Vehicle Mode, since SoftRF enables Aviation < 2g
|
||||||
|
_serial_gps->write("$PCAS11,3*1E\r\n");
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#ifdef GPS_UBLOX
|
||||||
|
// Set the UART port to output NMEA only
|
||||||
|
byte _message_nmea[] = {0xB5, 0x62, 0x06, 0x00, 0x14, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0x80, 0x25, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x91, 0xAF};
|
||||||
|
_serial_gps->write(_message_nmea,sizeof(_message_nmea));
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
// disable GGL
|
||||||
|
byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
|
||||||
|
0xF0, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x05,0x3A};
|
||||||
|
_serial_gps->write(_message_GGL,sizeof(_message_GGL));
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
// disable GSA
|
||||||
|
byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
|
||||||
|
0xF0, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x06,0x41};
|
||||||
|
_serial_gps->write(_message_GSA,sizeof(_message_GSA));
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
// disable GSV
|
||||||
|
byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
|
||||||
|
0xF0, 0x03, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x07,0x48};
|
||||||
|
_serial_gps->write(_message_GSV,sizeof(_message_GSV));
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
// disable VTG
|
||||||
|
byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
|
||||||
|
0xF0, 0x05, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x09,0x56};
|
||||||
|
_serial_gps->write(_message_VTG,sizeof(_message_VTG));
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
// enable RMC
|
||||||
|
byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
|
||||||
|
0xF0, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x09,0x54};
|
||||||
|
_serial_gps->write(_message_RMC,sizeof(_message_RMC));
|
||||||
|
delay(250);
|
||||||
|
|
||||||
|
// enable GGA
|
||||||
|
byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00,
|
||||||
|
0xF0, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||||
|
0x05, 0x38};
|
||||||
|
_serial_gps->write(_message_GGA,sizeof(_message_GGA));
|
||||||
|
delay(250);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +114,7 @@ bool GPS::setup()
|
|||||||
{
|
{
|
||||||
// Master power for the GPS
|
// Master power for the GPS
|
||||||
#ifdef PIN_GPS_EN
|
#ifdef PIN_GPS_EN
|
||||||
digitalWrite(PIN_GPS_EN, PIN_GPS_EN);
|
digitalWrite(PIN_GPS_EN, 1);
|
||||||
pinMode(PIN_GPS_EN, OUTPUT);
|
pinMode(PIN_GPS_EN, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -257,7 +320,6 @@ int32_t GPS::runOnce()
|
|||||||
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
|
bool tooLong = wakeTime != UINT32_MAX && (now - lastWakeStartMsec) > wakeTime;
|
||||||
|
|
||||||
// Once we get a location we no longer desperately want an update
|
// Once we get a location we no longer desperately want an update
|
||||||
// or if we got a time and we are in GpsOpTimeOnly mode
|
|
||||||
// DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
|
// DEBUG_MSG("gotLoc %d, tooLong %d, gotTime %d\n", gotLoc, tooLong, gotTime);
|
||||||
if ((gotLoc && gotTime) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) {
|
if ((gotLoc && gotTime) || tooLong || (gotTime && getGpsOp() == GpsOperation_GpsOpTimeOnly)) {
|
||||||
|
|
||||||
@ -280,7 +342,7 @@ int32_t GPS::runOnce()
|
|||||||
|
|
||||||
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
|
// 9600bps is approx 1 byte per msec, so considering our buffer size we never need to wake more often than 200ms
|
||||||
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
|
// if not awake we can run super infrquently (once every 5 secs?) to see if we need to wake.
|
||||||
return isAwake ? 100 : 5000;
|
return isAwake ? GPS_THREAD_INTERVAL : 5000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPS::forceWake(bool on)
|
void GPS::forceWake(bool on)
|
||||||
@ -318,13 +380,7 @@ int GPS::prepareDeepSleep(void *unused)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef GPS_TX_PIN
|
#ifndef NO_GPS
|
||||||
#include "UBloxGPS.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_AIR530_GPS
|
|
||||||
#include "Air530GPS.h"
|
|
||||||
#elif !defined(NO_GPS)
|
|
||||||
#include "NMEAGPS.h"
|
#include "NMEAGPS.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -339,29 +395,11 @@ GPS *createGps()
|
|||||||
#else
|
#else
|
||||||
DEBUG_MSG("Using MSL altitude model\n");
|
DEBUG_MSG("Using MSL altitude model\n");
|
||||||
#endif
|
#endif
|
||||||
// If we don't have bidirectional comms, we can't even try talking to UBLOX
|
|
||||||
#ifdef GPS_TX_PIN
|
|
||||||
// Init GPS - first try ublox
|
|
||||||
UBloxGPS *ublox = new UBloxGPS();
|
|
||||||
|
|
||||||
if (!ublox->setup()) {
|
|
||||||
DEBUG_MSG("ERROR: No UBLOX GPS found\n");
|
|
||||||
delete ublox;
|
|
||||||
ublox = NULL;
|
|
||||||
} else {
|
|
||||||
return ublox;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (GPS::_serial_gps) {
|
if (GPS::_serial_gps) {
|
||||||
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
// Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just
|
||||||
// assume NMEA at 9600 baud.
|
// assume NMEA at 9600 baud.
|
||||||
DEBUG_MSG("Hoping that NMEA might work\n");
|
DEBUG_MSG("Hoping that NMEA might work\n");
|
||||||
#ifdef HAS_AIR530_GPS
|
|
||||||
GPS *new_gps = new Air530GPS();
|
|
||||||
#else
|
|
||||||
GPS *new_gps = new NMEAGPS();
|
GPS *new_gps = new NMEAGPS();
|
||||||
#endif
|
|
||||||
new_gps->setup();
|
new_gps->setup();
|
||||||
return new_gps;
|
return new_gps;
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,6 @@ class GPS : private concurrency::OSThread
|
|||||||
/** If !NULL we will use this serial port to construct our GPS */
|
/** If !NULL we will use this serial port to construct our GPS */
|
||||||
static HardwareSerial *_serial_gps;
|
static HardwareSerial *_serial_gps;
|
||||||
|
|
||||||
/** If !0 we will attempt to connect to the GPS over I2C */
|
|
||||||
static uint8_t i2cAddress;
|
|
||||||
|
|
||||||
Position p = Position_init_default;
|
Position p = Position_init_default;
|
||||||
|
|
||||||
GPS() : concurrency::OSThread("GPS") {}
|
GPS() : concurrency::OSThread("GPS") {}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <TinyGPS++.h>
|
#include <TinyGPS++.h>
|
||||||
|
|
||||||
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
|
// GPS solutions older than this will be rejected - see TinyGPSDatum::age()
|
||||||
#define GPS_SOL_EXPIRY_MS 300 // in millis
|
#define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway
|
||||||
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
|
#define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc)
|
||||||
|
|
||||||
static int32_t toDegInt(RawDegrees d)
|
static int32_t toDegInt(RawDegrees d)
|
||||||
@ -64,13 +64,14 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
|||||||
t.tm_mon = d.month() - 1;
|
t.tm_mon = d.month() - 1;
|
||||||
t.tm_year = d.year() - 1900;
|
t.tm_year = d.year() - 1900;
|
||||||
t.tm_isdst = false;
|
t.tm_isdst = false;
|
||||||
DEBUG_MSG("NMEA GPS time %d\n", t.tm_sec);
|
if (t.tm_mon > -1){
|
||||||
|
DEBUG_MSG("NMEA GPS time %02d-%02d-%02d %02d:%02d:%02d\n", d.year(), d.month(), t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
|
||||||
perhapsSetRTC(RTCQualityGPS, t);
|
perhapsSetRTC(RTCQualityGPS, t);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,7 +117,7 @@ bool NMEAGPS::lookForLocation()
|
|||||||
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
|
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
|
||||||
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
|
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
|
||||||
{
|
{
|
||||||
DEBUG_MSG("SOME data is TOO OLD\n");
|
DEBUG_MSG("SOME data is TOO OLD: LOC %u, TIME %u, DATE %u\n", reader.location.age(), reader.time.age(), reader.date.age());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,10 +128,17 @@ bool NMEAGPS::lookForLocation()
|
|||||||
// We know the solution is fresh and valid, so just read the data
|
// We know the solution is fresh and valid, so just read the data
|
||||||
auto loc = reader.location.value();
|
auto loc = reader.location.value();
|
||||||
|
|
||||||
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
|
|
||||||
// Bail out EARLY to avoid overwriting previous good data (like #857)
|
// Bail out EARLY to avoid overwriting previous good data (like #857)
|
||||||
if(toDegInt(loc.lat) == 0) {
|
if (toDegInt(loc.lat) > 900000000) {
|
||||||
DEBUG_MSG("Ignoring bogus NMEA position\n");
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
|
DEBUG_MSG("Bail out EARLY on LAT %i\n",toDegInt(loc.lat));
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (toDegInt(loc.lng) > 1800000000) {
|
||||||
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
|
DEBUG_MSG("Bail out EARLY on LNG %i\n",toDegInt(loc.lng));
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,328 +0,0 @@
|
|||||||
#include "configuration.h"
|
|
||||||
#include "UBloxGPS.h"
|
|
||||||
#include "RTC.h"
|
|
||||||
#include "error.h"
|
|
||||||
#include "sleep.h"
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
// if gps_update_interval below this value, do not powercycle the GPS
|
|
||||||
#define UBLOX_POWEROFF_THRESHOLD 90
|
|
||||||
|
|
||||||
#define PDOP_INVALID 9999
|
|
||||||
|
|
||||||
// #define UBX_MODE_NMEA
|
|
||||||
|
|
||||||
extern RadioConfig radioConfig;
|
|
||||||
|
|
||||||
UBloxGPS::UBloxGPS() {}
|
|
||||||
|
|
||||||
bool UBloxGPS::tryConnect()
|
|
||||||
{
|
|
||||||
bool c = false;
|
|
||||||
|
|
||||||
if (_serial_gps)
|
|
||||||
c = ublox.begin(*_serial_gps);
|
|
||||||
|
|
||||||
if (!c && i2cAddress) {
|
|
||||||
extern bool neo6M; // Super skanky - if we are talking to the device i2c we assume it is a neo7 on a RAK815, which
|
|
||||||
// supports the newer API
|
|
||||||
neo6M = true;
|
|
||||||
|
|
||||||
c = ublox.begin(Wire, i2cAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c)
|
|
||||||
setConnected();
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UBloxGPS::setupGPS()
|
|
||||||
{
|
|
||||||
GPS::setupGPS();
|
|
||||||
|
|
||||||
// uncomment to see debug info
|
|
||||||
// ublox.enableDebugging(Serial);
|
|
||||||
|
|
||||||
// try a second time, the ublox lib serial parsing is buggy?
|
|
||||||
// see https://github.com/meshtastic/Meshtastic-device/issues/376
|
|
||||||
for (int i = 0; (i < 3) && !tryConnect(); i++)
|
|
||||||
delay(500);
|
|
||||||
|
|
||||||
if (isConnected()) {
|
|
||||||
#ifdef UBX_MODE_NMEA
|
|
||||||
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
|
|
||||||
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
|
|
||||||
#else
|
|
||||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!setUBXMode())
|
|
||||||
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
|
||||||
|
|
||||||
#ifdef UBX_MODE_NMEA
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UBloxGPS::setUBXMode()
|
|
||||||
{
|
|
||||||
#ifdef UBX_MODE_NMEA
|
|
||||||
if (_serial_gps) {
|
|
||||||
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
|
|
||||||
}
|
|
||||||
if (i2cAddress) {
|
|
||||||
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false; // pretend initialization failed to force NMEA mode
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_serial_gps) {
|
|
||||||
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (i2cAddress) {
|
|
||||||
if (!ublox.setI2COutput(COM_TYPE_UBX, 1000))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ublox.setNavigationFrequency(1, 1000)) // Produce 4x/sec to keep the amount of time we stall in getPVT low
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// ok = ublox.setAutoPVT(false); // Not implemented on NEO-6M
|
|
||||||
// assert(ok);
|
|
||||||
// ok = ublox.setDynamicModel(DYN_MODEL_BIKE); // probably PEDESTRIAN but just in case assume bike speeds
|
|
||||||
// assert(ok);
|
|
||||||
|
|
||||||
// per https://github.com/meshtastic/Meshtastic-device/issues/376 powerSaveMode might not work with the marginal
|
|
||||||
// TTGO antennas
|
|
||||||
// if (!ublox.powerSaveMode(true, 2000)) // use power save mode, the default timeout (1100ms seems a bit too tight)
|
|
||||||
// return false;
|
|
||||||
|
|
||||||
if (!ublox.saveConfiguration(3000))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset our GPS back to factory settings
|
|
||||||
*
|
|
||||||
* @return true for success
|
|
||||||
*/
|
|
||||||
bool UBloxGPS::factoryReset()
|
|
||||||
{
|
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
// It is useful to force back into factory defaults (9600baud, NMEA to test the behavior of boards that don't have
|
|
||||||
// GPS_TX connected)
|
|
||||||
ublox.factoryReset();
|
|
||||||
delay(5000);
|
|
||||||
tryConnect(); // sets isConnected
|
|
||||||
|
|
||||||
// try a second time, the ublox lib serial parsing is buggy?
|
|
||||||
for (int i = 0; (i < 3) && !tryConnect(); i++)
|
|
||||||
delay(500);
|
|
||||||
|
|
||||||
DEBUG_MSG("GPS Factory reset success=%d\n", isConnected());
|
|
||||||
if (isConnected())
|
|
||||||
ok = setUBXMode();
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Idle processing while GPS is looking for lock */
|
|
||||||
void UBloxGPS::whileActive()
|
|
||||||
{
|
|
||||||
ublox.flushPVT(); // reset ALL freshness flags first
|
|
||||||
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
|
|
||||||
|
|
||||||
// Ask for a new position fix - hopefully it will have results ready by next time
|
|
||||||
// the order here is important, because we only check for has latitude when reading
|
|
||||||
|
|
||||||
//ublox.getSIV(maxWait()); // redundant with getPDOP below
|
|
||||||
ublox.getPDOP(maxWait()); // will trigger getSOL on NEO6, getP on others
|
|
||||||
ublox.getP(maxWait()); // will trigger getPosLLH on NEO6, getP on others
|
|
||||||
|
|
||||||
// the fixType flag will be checked and updated in lookForLocation()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
|
||||||
* Override this method to check for new locations
|
|
||||||
*
|
|
||||||
* @return true if we've acquired a new location
|
|
||||||
*/
|
|
||||||
bool UBloxGPS::lookForTime()
|
|
||||||
{
|
|
||||||
if (ublox.moduleQueried.gpsSecond) {
|
|
||||||
/* Convert to unix time
|
|
||||||
The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of seconds that have elapsed since January
|
|
||||||
1, 1970 (midnight UTC/GMT), not counting leap seconds (in ISO 8601: 1970-01-01T00:00:00Z).
|
|
||||||
*/
|
|
||||||
struct tm t;
|
|
||||||
t.tm_sec = ublox.getSecond(0);
|
|
||||||
t.tm_min = ublox.getMinute(0);
|
|
||||||
t.tm_hour = ublox.getHour(0);
|
|
||||||
t.tm_mday = ublox.getDay(0);
|
|
||||||
t.tm_mon = ublox.getMonth(0) - 1;
|
|
||||||
t.tm_year = ublox.getYear(0) - 1900;
|
|
||||||
t.tm_isdst = false;
|
|
||||||
perhapsSetRTC(RTCQualityGPS, t);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
|
||||||
* Override this method to check for new locations
|
|
||||||
*
|
|
||||||
* @return true if we've acquired a new location
|
|
||||||
*/
|
|
||||||
bool UBloxGPS::lookForLocation()
|
|
||||||
{
|
|
||||||
bool foundLocation = false;
|
|
||||||
|
|
||||||
// check if a complete GPS solution set is available for reading
|
|
||||||
// (some of these, like lat/lon are redundant and can be removed)
|
|
||||||
if ( ! (ublox.moduleQueried.fixType &&
|
|
||||||
ublox.moduleQueried.latitude &&
|
|
||||||
ublox.moduleQueried.longitude &&
|
|
||||||
ublox.moduleQueried.altitude &&
|
|
||||||
ublox.moduleQueried.pDOP &&
|
|
||||||
ublox.moduleQueried.SIV &&
|
|
||||||
ublox.moduleQueried.gpsDay))
|
|
||||||
{
|
|
||||||
// Not ready? No problem! We'll try again later.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fixType = ublox.getFixType();
|
|
||||||
#ifdef UBLOX_EXTRAVERBOSE
|
|
||||||
DEBUG_MSG("FixType=%d\n", fixType);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// check if GPS has an acceptable lock
|
|
||||||
if (! hasLock()) {
|
|
||||||
ublox.flushPVT(); // reset ALL freshness flags
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read lat/lon/alt/dop data into temporary variables to avoid
|
|
||||||
// overwriting global variables with potentially invalid data
|
|
||||||
int32_t tmp_dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
|
|
||||||
int32_t tmp_lat = ublox.getLatitude(0);
|
|
||||||
int32_t tmp_lon = ublox.getLongitude(0);
|
|
||||||
int32_t tmp_alt_msl = ublox.getAltitudeMSL(0);
|
|
||||||
int32_t tmp_alt_hae = ublox.getAltitude(0);
|
|
||||||
int32_t max_dop = PDOP_INVALID;
|
|
||||||
if (radioConfig.preferences.gps_max_dop)
|
|
||||||
max_dop = radioConfig.preferences.gps_max_dop * 100; // scaling
|
|
||||||
|
|
||||||
// Note: heading is only currently implmented in the ublox for the 8m chipset - therefore
|
|
||||||
// don't read it here - it will generate an ignored getPVT command on the 6ms
|
|
||||||
// heading = ublox.getHeading(0);
|
|
||||||
|
|
||||||
// read positional timestamp
|
|
||||||
struct tm t;
|
|
||||||
t.tm_sec = ublox.getSecond(0);
|
|
||||||
t.tm_min = ublox.getMinute(0);
|
|
||||||
t.tm_hour = ublox.getHour(0);
|
|
||||||
t.tm_mday = ublox.getDay(0);
|
|
||||||
t.tm_mon = ublox.getMonth(0) - 1;
|
|
||||||
t.tm_year = ublox.getYear(0) - 1900;
|
|
||||||
t.tm_isdst = false;
|
|
||||||
|
|
||||||
time_t tmp_ts = mktime(&t);
|
|
||||||
|
|
||||||
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
|
|
||||||
|
|
||||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
|
||||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
|
||||||
// FIXME - NULL ISLAND is a real location on Earth!
|
|
||||||
foundLocation = (tmp_lat != 0) && (tmp_lon != 0) &&
|
|
||||||
(tmp_lat <= 900000000) && (tmp_lat >= -900000000) &&
|
|
||||||
(tmp_dop < max_dop);
|
|
||||||
|
|
||||||
// only if entire dataset is valid, update globals from temp vars
|
|
||||||
if (foundLocation) {
|
|
||||||
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
|
|
||||||
p.longitude_i = tmp_lon;
|
|
||||||
p.latitude_i = tmp_lat;
|
|
||||||
if (fixType > 2) {
|
|
||||||
// if fix is 2d, ignore altitude data
|
|
||||||
p.altitude = tmp_alt_msl / 1000;
|
|
||||||
p.altitude_hae = tmp_alt_hae / 1000;
|
|
||||||
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
|
|
||||||
} else {
|
|
||||||
#ifdef GPS_EXTRAVERBOSE
|
|
||||||
DEBUG_MSG("no altitude data (fixType=%d)\n", fixType);
|
|
||||||
#endif
|
|
||||||
// clean up old values in case it's a 3d-2d fix transition
|
|
||||||
p.altitude = p.altitude_hae = p.alt_geoid_sep = 0;
|
|
||||||
}
|
|
||||||
p.pos_timestamp = tmp_ts;
|
|
||||||
p.PDOP = tmp_dop;
|
|
||||||
p.fix_type = fixType;
|
|
||||||
p.sats_in_view = ublox.getSIV(0);
|
|
||||||
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
|
|
||||||
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
|
|
||||||
} else {
|
|
||||||
// INVALID solution - should never happen
|
|
||||||
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
|
|
||||||
tmp_lat, tmp_lon, tmp_alt_hae, tmp_dop);
|
|
||||||
}
|
|
||||||
|
|
||||||
ublox.flushPVT(); // reset ALL freshness flags at the end
|
|
||||||
|
|
||||||
return foundLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UBloxGPS::hasLock()
|
|
||||||
{
|
|
||||||
if (radioConfig.preferences.gps_accept_2d)
|
|
||||||
return (fixType >= 2 && fixType <= 4);
|
|
||||||
else
|
|
||||||
return (fixType >= 3 && fixType <= 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UBloxGPS::whileIdle()
|
|
||||||
{
|
|
||||||
// if using i2c or serial look too see if any chars are ready
|
|
||||||
return ublox.checkUblox(); // See if new data is available. Process bytes as they come in.
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If possible force the GPS into sleep/low power mode
|
|
||||||
/// Note: ublox doesn't need a wake method, because as soon as we send chars to the GPS it will wake up
|
|
||||||
void UBloxGPS::sleep()
|
|
||||||
{
|
|
||||||
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
|
|
||||||
// Tell GPS to power down until we send it characters on serial port (we leave vcc connected)
|
|
||||||
ublox.powerOff();
|
|
||||||
// setGPSPower(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UBloxGPS::wake()
|
|
||||||
{
|
|
||||||
if (radioConfig.preferences.gps_update_interval > UBLOX_POWEROFF_THRESHOLD) {
|
|
||||||
fixType = 0; // assume we have no fix yet
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is idempotent
|
|
||||||
setGPSPower(true);
|
|
||||||
|
|
||||||
// Note: no delay needed because now we leave gps power on always and instead use ublox.powerOff()
|
|
||||||
// Give time for the GPS to boot
|
|
||||||
// delay(200);
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "GPS.h"
|
|
||||||
#include "Observer.h"
|
|
||||||
#include "SparkFun_Ublox_Arduino_Library.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A gps class that only reads from the GPS periodically (and FIXME - eventually keeps the gps powered down except when reading)
|
|
||||||
*
|
|
||||||
* When new data is available it will notify observers.
|
|
||||||
*/
|
|
||||||
class UBloxGPS : public GPS
|
|
||||||
{
|
|
||||||
SFE_UBLOX_GPS ublox;
|
|
||||||
uint8_t fixType = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
UBloxGPS();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset our GPS back to factory settings
|
|
||||||
*
|
|
||||||
* @return true for success
|
|
||||||
*/
|
|
||||||
bool factoryReset() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/**
|
|
||||||
* Returns true if we succeeded
|
|
||||||
*/
|
|
||||||
virtual bool setupGPS() override;
|
|
||||||
|
|
||||||
/** Subclasses should look for serial rx characters here and feed it to their GPS parser
|
|
||||||
*
|
|
||||||
* Return true if we received a valid message from the GPS
|
|
||||||
*/
|
|
||||||
virtual bool whileIdle() override;
|
|
||||||
|
|
||||||
/** Idle processing while GPS is looking for lock */
|
|
||||||
virtual void whileActive() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
|
||||||
* Override this method to check for new locations
|
|
||||||
*
|
|
||||||
* @return true if we've acquired a time
|
|
||||||
*/
|
|
||||||
virtual bool lookForTime() override;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform any processing that should be done only while the GPS is awake and looking for a fix.
|
|
||||||
* Override this method to check for new locations
|
|
||||||
*
|
|
||||||
* @return true if we've acquired a new location
|
|
||||||
*/
|
|
||||||
virtual bool lookForLocation() override;
|
|
||||||
virtual bool hasLock() override;
|
|
||||||
|
|
||||||
/// If possible force the GPS into sleep/low power mode
|
|
||||||
virtual void sleep() override;
|
|
||||||
virtual void wake() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Attempt to connect to our GPS, returns false if no gps is present
|
|
||||||
bool tryConnect();
|
|
||||||
|
|
||||||
/// Switch to our desired operating mode and save the settings to flash
|
|
||||||
/// returns true for success
|
|
||||||
bool setUBXMode();
|
|
||||||
|
|
||||||
uint16_t maxWait() const { return i2cAddress ? 300 : 0; /*If using i2c we must poll with wait */ }
|
|
||||||
};
|
|
@ -408,6 +408,12 @@ void setup()
|
|||||||
|
|
||||||
initDeepSleep();
|
initDeepSleep();
|
||||||
|
|
||||||
|
// Testing this fix für erratic T-Echo boot behaviour
|
||||||
|
#if defined(TTGO_T_ECHO) && defined(PIN_EINK_PWR_ON)
|
||||||
|
pinMode(PIN_EINK_PWR_ON, OUTPUT);
|
||||||
|
digitalWrite(PIN_EINK_PWR_ON, HIGH);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef VEXT_ENABLE
|
#ifdef VEXT_ENABLE
|
||||||
pinMode(VEXT_ENABLE, OUTPUT);
|
pinMode(VEXT_ENABLE, OUTPUT);
|
||||||
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
|
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
|
||||||
|
@ -226,7 +226,7 @@ External serial flash WP25R1635FZUIL0
|
|||||||
#define PIN_SPI1_SCK PIN_EINK_SCLK
|
#define PIN_SPI1_SCK PIN_EINK_SCLK
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Air530 GPS pins
|
* GPS pins
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PIN_GPS_WAKE (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake
|
#define PIN_GPS_WAKE (32 + 2) // An output to wake GPS, low means allow sleep, high means force wake
|
||||||
@ -235,6 +235,8 @@ External serial flash WP25R1635FZUIL0
|
|||||||
#define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU
|
#define PIN_GPS_TX (32 + 9) // This is for bits going TOWARDS the CPU
|
||||||
#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS
|
#define PIN_GPS_RX (32 + 8) // This is for bits going TOWARDS the GPS
|
||||||
|
|
||||||
|
#define GPS_THREAD_INTERVAL 50
|
||||||
|
|
||||||
#define PIN_SERIAL1_RX PIN_GPS_TX
|
#define PIN_SERIAL1_RX PIN_GPS_TX
|
||||||
#define PIN_SERIAL1_TX PIN_GPS_RX
|
#define PIN_SERIAL1_TX PIN_GPS_RX
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user