sforkowany z mirror/meshtastic-firmware
Merge pull request #248 from Professr/issue#199
Issue#199 update - add satellite info, change DOP display, add compass rose1.2-legacy
commit
29c8543f87
|
@ -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 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 heading = 0;
|
||||
uint32_t numSatellites = 0;
|
||||
|
||||
public:
|
||||
|
||||
GPSStatus() {
|
||||
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->isConnected = isConnected;
|
||||
|
@ -31,6 +33,8 @@ namespace meshtastic {
|
|||
this->longitude = longitude;
|
||||
this->altitude = altitude;
|
||||
this->dop = dop;
|
||||
this->heading = heading;
|
||||
this->numSatellites = numSatellites;
|
||||
}
|
||||
GPSStatus(const GPSStatus &);
|
||||
GPSStatus &operator=(const GPSStatus &);
|
||||
|
@ -70,6 +74,16 @@ namespace meshtastic {
|
|||
return dop;
|
||||
}
|
||||
|
||||
uint32_t getHeading() const
|
||||
{
|
||||
return heading;
|
||||
}
|
||||
|
||||
uint32_t getNumSatellites() const
|
||||
{
|
||||
return numSatellites;
|
||||
}
|
||||
|
||||
bool matches(const GPSStatus *newStatus) const
|
||||
{
|
||||
return (
|
||||
|
@ -78,7 +92,9 @@ namespace meshtastic {
|
|||
newStatus->latitude != latitude ||
|
||||
newStatus->longitude != longitude ||
|
||||
newStatus->altitude != altitude ||
|
||||
newStatus->dop != dop
|
||||
newStatus->dop != dop ||
|
||||
newStatus->heading != heading ||
|
||||
newStatus->numSatellites != numSatellites
|
||||
);
|
||||
}
|
||||
int updateStatus(const GPSStatus *newStatus) {
|
||||
|
@ -93,9 +109,11 @@ namespace meshtastic {
|
|||
longitude = newStatus->longitude;
|
||||
altitude = newStatus->altitude;
|
||||
dop = newStatus->dop;
|
||||
heading = newStatus->heading;
|
||||
numSatellites = newStatus->numSatellites;
|
||||
}
|
||||
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);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -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 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 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
|
||||
|
||||
|
|
|
@ -54,12 +54,18 @@ void NEMAGPS::loop()
|
|||
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
|
||||
if(reader.hdop.isValid()) {
|
||||
if (reader.hdop.isValid()) {
|
||||
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
|
||||
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
|
||||
if (hasValidLocation)
|
||||
|
@ -67,7 +73,7 @@ void NEMAGPS::loop()
|
|||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
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
|
||||
heading = ublox.getHeading(0);
|
||||
numSatellites = ublox.getSIV(0);
|
||||
|
||||
// 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!
|
||||
|
@ -129,7 +131,7 @@ The Unix epoch (or Unix time or POSIX time or Unix timestamp) is the number of s
|
|||
wantNewLocation = true;
|
||||
|
||||
// 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);
|
||||
|
||||
// Once we have sent a location once we only poll the GPS rarely, otherwise check back every 1s until we have something over
|
||||
|
|
150
src/screen.cpp
150
src/screen.cpp
|
@ -52,7 +52,10 @@ static FrameCallback normalFrames[MAX_NUM_NODES + NUM_EXTRA_FRAMES];
|
|||
static uint32_t targetFramerate = IDLE_FRAMERATE;
|
||||
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
|
||||
// #define SHOW_REDRAWS
|
||||
|
@ -212,38 +215,39 @@ static void drawNodes(OLEDDisplay *display, int16_t x, int16_t y, NodeStatus *no
|
|||
// Draw GPS status summary
|
||||
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");
|
||||
return;
|
||||
}
|
||||
display->drawFastImage(x, y, 6, 8, gps->getHasLock() ? imgPositionSolid : imgPositionEmpty);
|
||||
if (!gps->getHasLock()) {
|
||||
if (!gps->getHasLock())
|
||||
{
|
||||
display->drawString(x + 8, y - 2, "No sats");
|
||||
return;
|
||||
}
|
||||
if (gps->getDOP() <= 100) {
|
||||
display->drawString(x + 8, y - 2, "Ideal");
|
||||
return;
|
||||
}
|
||||
if (gps->getDOP() <= 200) {
|
||||
display->drawString(x + 8, y - 2, "Exc.");
|
||||
return;
|
||||
}
|
||||
if (gps->getDOP() <= 500) {
|
||||
display->drawString(x + 8, y - 2, "Good");
|
||||
return;
|
||||
}
|
||||
if (gps->getDOP() <= 1000) {
|
||||
display->drawString(x + 8, y - 2, "Mod.");
|
||||
return;
|
||||
}
|
||||
if (gps->getDOP() <= 2000) {
|
||||
display->drawString(x + 8, y - 2, "Fair");
|
||||
return;
|
||||
}
|
||||
if (gps->getDOP() > 0) {
|
||||
display->drawString(x + 8, y - 2, "Poor");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
char satsString[3];
|
||||
uint8_t bar[2] = { 0 };
|
||||
|
||||
//Draw DOP signal bars
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
if (gps->getDOP() <= dopThresholds[i])
|
||||
bar[0] = ~((1 << (5 - i)) - 1);
|
||||
else
|
||||
bar[0] = 0b10000000;
|
||||
//bar[1] = bar[0];
|
||||
display->drawFastImage(x + 9 + (i * 2), y, 2, 8, bar);
|
||||
}
|
||||
|
||||
//Draw satellite image
|
||||
display->drawFastImage(x + 24, y, 8, 8, imgSatellite);
|
||||
|
||||
//Draw the number of satellites
|
||||
sprintf(satsString, "%d", gps->getNumSatellites());
|
||||
display->drawString(x + 34, y - 2, satsString);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,28 +390,41 @@ static bool hasPosition(NodeInfo *n)
|
|||
static size_t nodeIndex;
|
||||
static int8_t prevFrame = -1;
|
||||
|
||||
// Draw the compass and arrow pointing to location
|
||||
static void drawCompass(OLEDDisplay *display, int16_t compassX, int16_t compassY, float headingRadian)
|
||||
// Draw the arrow pointing to a node's location
|
||||
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
|
||||
float arrowOffsetX = 0.2f, arrowOffsetY = 0.2f;
|
||||
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++) {
|
||||
points[i]->rotate(headingRadian);
|
||||
points[i]->scale(COMPASS_DIAM * 0.6);
|
||||
points[i]->translate(compassX, compassY);
|
||||
arrowPoints[i]->rotate(headingRadian);
|
||||
arrowPoints[i]->scale(COMPASS_DIAM * 0.6);
|
||||
arrowPoints[i]->translate(compassX, compassY);
|
||||
}
|
||||
drawLine(display, tip, tail);
|
||||
drawLine(display, leftArrow, 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
|
||||
|
@ -461,29 +478,35 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
|
|||
const char *fields[] = {username, distStr, signalStr, lastStr, NULL};
|
||||
|
||||
// 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
|
||||
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));
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
if(ourNode && hasPosition(ourNode))
|
||||
{
|
||||
Position &op = ourNode->position;
|
||||
float myHeading = estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
drawCompassHeading(display, compassX, compassY, myHeading);
|
||||
|
||||
// FIXME, also keep the guess at the operators heading and add/substract
|
||||
// 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));
|
||||
float myHeading = estimatedHeading(DegD(p.latitude_i), DegD(p.longitude_i));
|
||||
headingRadian = bearingToOther - myHeading;
|
||||
drawCompass(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));
|
||||
if(hasPosition(node)) { // display direction toward node
|
||||
Position &p = node->position;
|
||||
float d = latLongToMeter(DegD(p.latitude_i), DegD(p.longitude_i), DegD(op.latitude_i), DegD(op.longitude_i));
|
||||
if (d < 2000)
|
||||
snprintf(distStr, sizeof(distStr), "%.0f m", d);
|
||||
else
|
||||
snprintf(distStr, sizeof(distStr), "%.1f km", d / 1000);
|
||||
|
||||
display->drawString(compassX - FONT_HEIGHT / 4, compassY - FONT_HEIGHT / 2, "?");
|
||||
display->drawCircle(compassX, compassY, COMPASS_DIAM / 2);
|
||||
// FIXME, also keep the guess at the operators heading and add/substract
|
||||
// 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
|
||||
drawColumns(display, x, y, fields);
|
||||
|
@ -760,7 +783,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||
// Display nodes status
|
||||
drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
|
||||
// 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);
|
||||
|
@ -790,13 +813,14 @@ void Screen::adjustBrightness()
|
|||
dispdev.setBrightness(brightness);
|
||||
}
|
||||
|
||||
int Screen::handleStatusUpdate(const Status *arg)
|
||||
int Screen::handleStatusUpdate(const Status *arg)
|
||||
{
|
||||
DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
|
||||
switch (arg->getStatusType()) {
|
||||
case STATUS_TYPE_NODE:
|
||||
setFrames();
|
||||
break;
|
||||
//DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
|
||||
switch(arg->getStatusType())
|
||||
{
|
||||
case STATUS_TYPE_NODE:
|
||||
setFrames();
|
||||
break;
|
||||
}
|
||||
setPeriod(1); // Update the screen right away
|
||||
return 0;
|
||||
|
|
Ładowanie…
Reference in New Issue