2020-06-28 04:19:49 +00:00
|
|
|
#pragma once
|
2022-05-07 10:31:21 +00:00
|
|
|
#include "NodeDB.h"
|
2020-06-29 01:17:52 +00:00
|
|
|
#include "Status.h"
|
2020-06-28 04:19:49 +00:00
|
|
|
#include "configuration.h"
|
2020-09-26 20:49:22 +00:00
|
|
|
#include <Arduino.h>
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2021-09-15 22:58:09 +00:00
|
|
|
extern NodeDB nodeDB;
|
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
namespace meshtastic
|
|
|
|
{
|
|
|
|
|
|
|
|
/// Describes the state of the GPS system.
|
|
|
|
class GPSStatus : public Status
|
|
|
|
{
|
|
|
|
|
|
|
|
private:
|
|
|
|
CallbackObserver<GPSStatus, const GPSStatus *> statusObserver =
|
|
|
|
CallbackObserver<GPSStatus, const GPSStatus *>(this, &GPSStatus::updateStatus);
|
|
|
|
|
2022-05-07 10:31:21 +00:00
|
|
|
bool hasLock = false; // default to false, until we complete our first read
|
|
|
|
bool isConnected = false; // Do we have a GPS we are talking to
|
2021-10-24 00:36:18 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
bool isPowerSaving = false; // Are we in power saving state
|
2022-12-13 22:23:58 +00:00
|
|
|
|
2023-01-21 17:22:19 +00:00
|
|
|
meshtastic_Position p = meshtastic_Position_init_default;
|
2020-09-26 20:49:22 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
2021-10-24 00:36:18 +00:00
|
|
|
|
|
|
|
// preferred method
|
2023-01-21 17:22:19 +00:00
|
|
|
GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const meshtastic_Position &pos) : Status()
|
2021-10-24 00:36:18 +00:00
|
|
|
{
|
|
|
|
this->hasLock = hasLock;
|
|
|
|
this->isConnected = isConnected;
|
2022-12-13 22:23:58 +00:00
|
|
|
this->isPowerSaving = isPowerSaving;
|
2021-10-24 00:36:18 +00:00
|
|
|
|
|
|
|
// all-in-one struct copy
|
|
|
|
this->p = pos;
|
|
|
|
}
|
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
GPSStatus(const GPSStatus &);
|
|
|
|
GPSStatus &operator=(const GPSStatus &);
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
void observe(Observable<const GPSStatus *> *source) { statusObserver.observe(source); }
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
bool getHasLock() const { return hasLock; }
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
bool getIsConnected() const { return isConnected; }
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
bool getIsPowerSaving() const { return isPowerSaving; }
|
2022-12-13 22:23:58 +00:00
|
|
|
|
2022-05-07 10:31:21 +00:00
|
|
|
int32_t getLatitude() const
|
|
|
|
{
|
2022-05-21 20:38:33 +00:00
|
|
|
if (config.position.fixed_position) {
|
2022-04-26 11:00:11 +00:00
|
|
|
#ifdef GPS_EXTRAVERBOSE
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_WARN("Using fixed latitude\n");
|
2022-02-03 13:22:46 +00:00
|
|
|
#endif
|
2023-06-17 14:10:09 +00:00
|
|
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
2021-09-15 22:58:09 +00:00
|
|
|
return node->position.latitude_i;
|
|
|
|
} else {
|
2021-10-24 00:36:18 +00:00
|
|
|
return p.latitude_i;
|
2021-09-15 22:58:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2022-05-07 10:31:21 +00:00
|
|
|
int32_t getLongitude() const
|
|
|
|
{
|
2022-05-21 20:38:33 +00:00
|
|
|
if (config.position.fixed_position) {
|
2022-04-26 11:00:11 +00:00
|
|
|
#ifdef GPS_EXTRAVERBOSE
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_WARN("Using fixed longitude\n");
|
2022-02-03 13:22:46 +00:00
|
|
|
#endif
|
2023-06-17 14:10:09 +00:00
|
|
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
2021-09-15 22:58:09 +00:00
|
|
|
return node->position.longitude_i;
|
|
|
|
} else {
|
2021-10-24 00:36:18 +00:00
|
|
|
return p.longitude_i;
|
2021-09-15 22:58:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-07 10:31:21 +00:00
|
|
|
int32_t getAltitude() const
|
|
|
|
{
|
2022-05-21 20:38:33 +00:00
|
|
|
if (config.position.fixed_position) {
|
2022-04-26 11:00:11 +00:00
|
|
|
#ifdef GPS_EXTRAVERBOSE
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_WARN("Using fixed altitude\n");
|
2022-02-03 13:22:46 +00:00
|
|
|
#endif
|
2023-06-17 14:10:09 +00:00
|
|
|
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
|
2021-09-15 22:58:09 +00:00
|
|
|
return node->position.altitude;
|
|
|
|
} else {
|
2021-10-24 00:36:18 +00:00
|
|
|
return p.altitude;
|
2021-09-15 22:58:09 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
uint32_t getDOP() const
|
|
|
|
{
|
|
|
|
return p.PDOP;
|
|
|
|
}
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
uint32_t getHeading() const
|
|
|
|
{
|
|
|
|
return p.ground_track;
|
|
|
|
}
|
2020-06-29 01:17:52 +00:00
|
|
|
|
2023-01-21 13:34:29 +00:00
|
|
|
uint32_t getNumSatellites() const
|
|
|
|
{
|
|
|
|
return p.sats_in_view;
|
|
|
|
}
|
2020-06-29 01:17:52 +00:00
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
bool matches(const GPSStatus *newStatus) const
|
|
|
|
{
|
2022-04-26 11:00:11 +00:00
|
|
|
#ifdef GPS_EXTRAVERBOSE
|
2023-07-16 21:57:14 +00:00
|
|
|
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x\n", newStatus->p.timestamp, p.timestamp);
|
2021-10-24 13:02:31 +00:00
|
|
|
#endif
|
2023-01-21 13:34:29 +00:00
|
|
|
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
|
|
|
|
newStatus->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i ||
|
|
|
|
newStatus->p.longitude_i != p.longitude_i || newStatus->p.altitude != p.altitude ||
|
|
|
|
newStatus->p.altitude_hae != p.altitude_hae || newStatus->p.PDOP != p.PDOP ||
|
|
|
|
newStatus->p.ground_track != p.ground_track || newStatus->p.ground_speed != p.ground_speed ||
|
2021-10-24 00:36:18 +00:00
|
|
|
newStatus->p.sats_in_view != p.sats_in_view);
|
2020-09-26 20:49:22 +00:00
|
|
|
}
|
2021-10-24 13:02:31 +00:00
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
int updateStatus(const GPSStatus *newStatus)
|
|
|
|
{
|
|
|
|
// Only update the status if values have actually changed
|
2021-10-24 13:02:31 +00:00
|
|
|
bool isDirty = matches(newStatus);
|
|
|
|
|
2022-09-09 10:51:41 +00:00
|
|
|
if (isDirty && p.timestamp && (newStatus->p.timestamp == p.timestamp)) {
|
2021-10-24 13:02:31 +00:00
|
|
|
// We can NEVER be in two locations at the same time! (also PR #886)
|
2022-12-30 16:27:07 +00:00
|
|
|
LOG_ERROR("BUG: Positional timestamp unchanged from prev solution\n");
|
2020-06-28 04:19:49 +00:00
|
|
|
}
|
2021-10-24 13:02:31 +00:00
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
hasLock = newStatus->hasLock;
|
|
|
|
isConnected = newStatus->isConnected;
|
|
|
|
|
|
|
|
p = newStatus->p;
|
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
if (isDirty) {
|
2021-10-24 13:02:31 +00:00
|
|
|
if (hasLock) {
|
|
|
|
// In debug logs, identify position by @timestamp:stage (stage 3 = notify)
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("New GPS pos@%x:3 lat=%f, lon=%f, alt=%d, pdop=%.2f, track=%.2f, speed=%.2f, sats=%d\n", p.timestamp,
|
2022-05-07 10:31:21 +00:00
|
|
|
p.latitude_i * 1e-7, p.longitude_i * 1e-7, p.altitude, p.PDOP * 1e-2, p.ground_track * 1e-5,
|
2022-10-03 18:30:11 +00:00
|
|
|
p.ground_speed * 1e-2, p.sats_in_view);
|
2023-05-13 10:33:14 +00:00
|
|
|
} else {
|
2022-12-30 02:41:37 +00:00
|
|
|
LOG_DEBUG("No GPS lock\n");
|
2023-05-13 10:33:14 +00:00
|
|
|
}
|
2020-09-26 20:49:22 +00:00
|
|
|
onNewStatus.notifyObservers(this);
|
2020-06-28 04:19:49 +00:00
|
|
|
}
|
2020-09-26 20:49:22 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2020-09-26 20:49:22 +00:00
|
|
|
} // namespace meshtastic
|
2020-06-28 04:19:49 +00:00
|
|
|
|
2023-06-17 14:10:09 +00:00
|
|
|
extern meshtastic::GPSStatus *gpsStatus;
|