Issue#199 update - add satellite info, change DOP display, add compass rose
1.2-legacy
Kevin Hester 2020-07-05 12:10:03 -07:00 zatwierdzone przez GitHub
commit 29c8543f87
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
5 zmienionych plików z 122 dodań i 70 usunięć

Wyświetl plik

@ -17,13 +17,15 @@ namespace meshtastic {
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0; int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use) uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use)
uint32_t heading = 0;
uint32_t numSatellites = 0;
public: public:
GPSStatus() { GPSStatus() {
statusType = STATUS_TYPE_GPS; statusType = STATUS_TYPE_GPS;
} }
GPSStatus( bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop ) : Status() GPSStatus( bool hasLock, bool isConnected, int32_t latitude, int32_t longitude, int32_t altitude, uint32_t dop, uint32_t heading, uint32_t numSatellites ) : Status()
{ {
this->hasLock = hasLock; this->hasLock = hasLock;
this->isConnected = isConnected; this->isConnected = isConnected;
@ -31,6 +33,8 @@ namespace meshtastic {
this->longitude = longitude; this->longitude = longitude;
this->altitude = altitude; this->altitude = altitude;
this->dop = dop; this->dop = dop;
this->heading = heading;
this->numSatellites = numSatellites;
} }
GPSStatus(const GPSStatus &); GPSStatus(const GPSStatus &);
GPSStatus &operator=(const GPSStatus &); GPSStatus &operator=(const GPSStatus &);
@ -70,6 +74,16 @@ namespace meshtastic {
return dop; return dop;
} }
uint32_t getHeading() const
{
return heading;
}
uint32_t getNumSatellites() const
{
return numSatellites;
}
bool matches(const GPSStatus *newStatus) const bool matches(const GPSStatus *newStatus) const
{ {
return ( return (
@ -78,7 +92,9 @@ namespace meshtastic {
newStatus->latitude != latitude || newStatus->latitude != latitude ||
newStatus->longitude != longitude || newStatus->longitude != longitude ||
newStatus->altitude != altitude || newStatus->altitude != altitude ||
newStatus->dop != dop newStatus->dop != dop ||
newStatus->heading != heading ||
newStatus->numSatellites != numSatellites
); );
} }
int updateStatus(const GPSStatus *newStatus) { int updateStatus(const GPSStatus *newStatus) {
@ -93,9 +109,11 @@ namespace meshtastic {
longitude = newStatus->longitude; longitude = newStatus->longitude;
altitude = newStatus->altitude; altitude = newStatus->altitude;
dop = newStatus->dop; dop = newStatus->dop;
heading = newStatus->heading;
numSatellites = newStatus->numSatellites;
} }
if(isDirty) { if(isDirty) {
DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2); DEBUG_MSG("New GPS pos lat=%f, lon=%f, alt=%d, pdop=%f, heading=%f, sats=%d\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5, numSatellites);
onNewStatus.notifyObservers(this); onNewStatus.notifyObservers(this);
} }
return 0; return 0;

Wyświetl plik

@ -36,6 +36,8 @@ class GPS : public Observable<void *>
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
int32_t altitude = 0; int32_t altitude = 0;
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use) uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs scaling before use)
uint32_t heading = 0; // Heading of motion, in degrees * 10^-5
uint32_t numSatellites = 0;
bool isConnected = false; // Do we have a GPS we are talking to bool isConnected = false; // Do we have a GPS we are talking to

Wyświetl plik

@ -54,12 +54,18 @@ void NEMAGPS::loop()
longitude = toDegInt(loc.lng); longitude = toDegInt(loc.lng);
} }
// Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it // Diminution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
if(reader.hdop.isValid()) { if (reader.hdop.isValid()) {
dop = reader.hdop.value(); dop = reader.hdop.value();
} }
if (reader.course.isValid()) {
heading = reader.course.value() * 1e3; //Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
}
if (reader.satellites.isValid()) {
numSatellites = reader.satellites.value();
}
// expect gps pos lat=37.520825, lon=-122.309162, alt=158 // expect gps pos lat=37.520825, lon=-122.309162, alt=158
DEBUG_MSG("new NEMA GPS pos lat=%f, lon=%f, alt=%d, hdop=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2); DEBUG_MSG("new NEMA GPS pos lat=%f, lon=%f, alt=%d, hdop=%f, heading=%f\n", latitude * 1e-7, longitude * 1e-7, altitude, dop * 1e-2, heading * 1e-5);
hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0 hasValidLocation = (latitude != 0) || (longitude != 0); // bogus lat lon is reported as 0,0
if (hasValidLocation) if (hasValidLocation)
@ -67,7 +73,7 @@ void NEMAGPS::loop()
} }
// Notify any status instances that are observing us // Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop); const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status); newStatus.notifyObservers(&status);
} }
} }

Wyświetl plik

@ -116,6 +116,8 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
longitude = ublox.getLongitude(0); longitude = ublox.getLongitude(0);
altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters altitude = ublox.getAltitude(0) / 1000; // in mm convert to meters
dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it dop = ublox.getPDOP(0); // PDOP (an accuracy metric) is reported in 10^2 units so we have to scale down when we use it
heading = ublox.getHeading(0);
numSatellites = ublox.getSIV(0);
// bogus lat lon is reported as 0 or 0 (can be bogus just for one) // 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! // Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
@ -129,7 +131,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
wantNewLocation = true; wantNewLocation = true;
// Notify any status instances that are observing us // Notify any status instances that are observing us
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop); const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites);
newStatus.notifyObservers(&status); newStatus.notifyObservers(&status);
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over // Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over

Wyświetl plik

@ -52,7 +52,10 @@ static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
static uint32_t targetFramerate = IDLE_FRAMERATE; static uint32_t targetFramerate = IDLE_FRAMERATE;
static char btPIN[16] = "888888"; static char btPIN[16] = "888888";
uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C}; uint8_t imgBattery[16] = { 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C };
uint8_t imgSatellite[8] = { 0x70, 0x71, 0x22, 0xFA, 0xFA, 0x22, 0x71, 0x70 };
uint32_t dopThresholds[5] = { 2000, 1000, 500, 200, 100 };
// if defined a pixel will blink to show redraws // if defined a pixel will blink to show redraws
// #define SHOW_REDRAWS // #define SHOW_REDRAWS
@ -212,38 +215,39 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
// Draw GPS status summary // Draw GPS status summary
static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps) static void drawGPS(OLEDDisplay *display, int16_t x, int16_t y, const GPSStatus *gps)
{ {
if (!gps->getIsConnected()) { if (!gps->getIsConnected())
{
display->drawString(x, y - 2, "No GPS"); display->drawString(x, y - 2, "No GPS");
return; return;
} }
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty); display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
if (!gps->getHasLock()) { if (!gps->getHasLock())
{
display->drawString(x + 8, y - 2, "No sats"); display->drawString(x + 8, y - 2, "No sats");
return; return;
} }
if (gps->getDOP() <= 100) { else
display->drawString(x + 8, y - 2, "Ideal"); {
return; char satsString[3];
} uint8_t bar[2] = { 0 };
if (gps->getDOP() <= 200) {
display->drawString(x + 8, y - 2, "Exc."); //Draw DOP signal bars
return; for(int i = 0; i < 5; i++)
} {
if (gps->getDOP() <= 500) { if (gps->getDOP() <= dopThresholds[i])
display->drawString(x + 8, y - 2, "Good"); bar[0] = ~((1 << (5 - i)) - 1);
return; else
} bar[0] = 0b10000000;
if (gps->getDOP() <= 1000) { //bar[1] = bar[0];
display->drawString(x + 8, y - 2, "Mod."); display->drawFastImage(x + 9 + (i * 2), y, 2, 8, bar);
return; }
}
if (gps->getDOP() <= 2000) { //Draw satellite image
display->drawString(x + 8, y - 2, "Fair"); display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
return;
} //Draw the number of satellites
if (gps->getDOP() > 0) { sprintf(satsString, "%d", gps->getNumSatellites());
display->drawString(x + 8, y - 2, "Poor"); display->drawString(x + 34, y - 2, satsString);
return;
} }
} }
@ -386,28 +390,41 @@ static bool hasPosition(NodeInfo *n)
static size_t nodeIndex; static size_t nodeIndex;
static int8_t prevFrame = -1; static int8_t prevFrame = -1;
// Draw the compass and arrow pointing to location // Draw the arrow pointing to a node's location
static void drawCompass(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian) static void drawNodeHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian)
{ {
// display->drawXbm(compassX, compassY, compass_width, compass_height,
// (const uint8_t *)compass_bits);
Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially Point tip(0.0f, 0.5f), tail(0.0f, -0.5f); // pointing up initially
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f; float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY); Point leftArrow(tip.x - arrowOffsetX, tip.y - arrowOffsetY), rightArrow(tip.x + arrowOffsetX, tip.y - arrowOffsetY);
Point *points[] = {&tip, &tail, &leftArrow, &rightArrow};
Point *arrowPoints[] = {&tip, &tail, &leftArrow, &rightArrow};
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
points[i]->rotate(headingRadian); arrowPoints[i]->rotate(headingRadian);
points[i]->scale(COMPASS_DIAM * 0.6); arrowPoints[i]->scale(COMPASS_DIAM * 0.6);
points[i]->translate(compassX, compassY); arrowPoints[i]->translate(compassX, compassY);
} }
drawLine(display, tip, tail); drawLine(display, tip, tail);
drawLine(display, leftArrow, tip); drawLine(display, leftArrow, tip);
drawLine(display, rightArrow, tip); drawLine(display, rightArrow, tip);
}
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2); // Draw the compass heading
static void drawCompassHeading(OLEDDisplay *display, int16_t compassX, int16_t compassY, float myHeading)
{
Point N1(-0.04f, -0.65f), N2( 0.04f, -0.65f);
Point N3(-0.04f, -0.55f), N4( 0.04f, -0.55f);
Point *rosePoints[] = {&N1, &N2, &N3, &N4};
for (int i = 0; i < 4; i++) {
rosePoints[i]->rotate(myHeading);
rosePoints[i]->scale(COMPASS_DIAM);
rosePoints[i]->translate(compassX, compassY);
}
drawLine(display, N1, N3);
drawLine(display, N2, N4);
drawLine(display, N1, N4);
} }
/// Convert an integer GPS coords to a floating point /// Convert an integer GPS coords to a floating point
@ -461,29 +478,35 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
const char *fields[] = {username, distStr, signalStr, lastStr, NULL}; const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
// coordinates for the center of the compass/circle // coordinates for the center of the compass/circle
int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 1, compassY = y + SCREEN_HEIGHT / 2; int16_t compassX = x + SCREEN_WIDTH - COMPASS_DIAM / 2 - 5, compassY = y + SCREEN_HEIGHT / 2;
if (ourNode && hasPosition(ourNode) && hasPosition(node)) { // display direction toward node if(ourNode && hasPosition(ourNode))
Position &op = ourNode->position, &p = node->position; {
float d = latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); Position &op = ourNode->position;
if (d < 2000) float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
snprintf(distStr, sizeof(distStr), "%.0f m", d); drawCompassHeading(display, compassX, compassY, myHeading);
else
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
// FIXME, also keep the guess at the operators heading and add/substract if(hasPosition(node)) { // display direction toward node
// it. currently we don't do this and instead draw north up only. Position &p = node->position;
float bearingToOther = bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i)); float d = latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
float myHeading = estimatedHeading(DegD(p.latitude_i), DegD(p.longitude_i)); if (d < 2000)
headingRadian = bearingToOther - myHeading; snprintf(distStr, sizeof(distStr), "%.0f m", d);
drawCompass(display, compassX, compassY, headingRadian); else
} else { // direction to node is unknown so display question mark snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
// Debug info for gps lock errors
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?"); // FIXME, also keep the guess at the operators heading and add/substract
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2); // it. currently we don't do this and instead draw north up only.
float bearingToOther = bearing(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
headingRadian = bearingToOther - myHeading;
drawNodeHeading(display, compassX, compassY, headingRadian);
} else { // direction to node is unknown so display question mark
// Debug info for gps lock errors
// DEBUG_MSG("ourNode %d, ourPos %d, theirPos %d\n", !!ourNode, ourNode && hasPosition(ourNode), hasPosition(node));
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?");
}
} }
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
// Must be after distStr is populated // Must be after distStr is populated
drawColumns(display, x, y, fields); drawColumns(display, x, y, fields);
@ -760,7 +783,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Display nodes status // Display nodes status
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
// Display GPS status // Display GPS status
drawGPS(display, x + (SCREEN_WIDTH * 0.66), y + 2, gpsStatus); drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
} }
display->drawString(x, y + FONT_HEIGHT, channelStr); display->drawString(x, y + FONT_HEIGHT, channelStr);
@ -792,11 +815,12 @@ void Screen::adjustBrightness()
int Screen::handleStatusUpdate(const Status *arg) int Screen::handleStatusUpdate(const Status *arg)
{ {
DEBUG_MSG("Screen got status update %d\n", arg->getStatusType()); //DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
switch (arg->getStatusType()) { switch(arg->getStatusType())
case STATUS_TYPE_NODE: {
setFrames(); case STATUS_TYPE_NODE:
break; setFrames();
break;
} }
setPeriod(1); // Update the screen right away setPeriod(1); // Update the screen right away
return 0; return 0;