diff --git a/bin/version.sh b/bin/version.sh index 5a11b5c23..00e265428 100644 --- a/bin/version.sh +++ b/bin/version.sh @@ -1,3 +1,3 @@ -export VERSION=0.9.2 \ No newline at end of file +export VERSION=0.9.3 \ No newline at end of file diff --git a/docs/hardware/DS_SX1261-2_V1.2.pdf b/docs/hardware/DS_SX1261-2_V1.2.pdf new file mode 100644 index 000000000..2d6c51cb5 Binary files /dev/null and b/docs/hardware/DS_SX1261-2_V1.2.pdf differ diff --git a/docs/hardware/T-SX1262.pdf b/docs/hardware/T-SX1262.pdf new file mode 100644 index 000000000..0e9fbfc11 Binary files /dev/null and b/docs/hardware/T-SX1262.pdf differ diff --git a/docs/hardware/WIFI_LoRa_32_V2(868-915).PDF b/docs/hardware/heltec-wifi-lora-32-v2-915.pdf similarity index 100% rename from docs/hardware/WIFI_LoRa_32_V2(868-915).PDF rename to docs/hardware/heltec-wifi-lora-32-v2-915.pdf diff --git a/src/Power.cpp b/src/Power.cpp index e582807a6..1145c51c4 100644 --- a/src/Power.cpp +++ b/src/Power.cpp @@ -16,6 +16,8 @@ bool pmu_irq = false; Power *power; +using namespace meshtastic; + /** * If this board has a battery level sensor, set this to a valid implementation */ @@ -36,7 +38,7 @@ class AnalogBatteryLevel : public HasBatteryLevel float v = getBattVoltage() / 1000; if (v < 2.1) - return -1; + return -1; // If voltage is super low assume no battery installed return 100 * (v - 3.27) / (4.2 - 3.27); } @@ -57,7 +59,7 @@ class AnalogBatteryLevel : public HasBatteryLevel /** * return true if there is a battery installed in this unit */ - virtual bool isBatteryConnect() { return true; } + virtual bool isBatteryConnect() { return getBattVoltage() != -1; } } analogLevel; bool Power::analogInit() @@ -97,7 +99,7 @@ void Power::readPowerStatus() if (batteryLevel) { bool hasBattery = batteryLevel->isBatteryConnect(); int batteryVoltageMv = 0; - uint8_t batteryChargePercent = 0; + int8_t batteryChargePercent = 0; if (hasBattery) { batteryVoltageMv = batteryLevel->getBattVoltage(); // If the AXP192 returns a valid battery percentage, use it @@ -114,13 +116,18 @@ void Power::readPowerStatus() } // Notify any status instances that are observing us - const meshtastic::PowerStatus powerStatus = meshtastic::PowerStatus( - hasBattery, batteryLevel->isVBUSPlug(), batteryLevel->isChargeing(), batteryVoltageMv, batteryChargePercent); + const PowerStatus powerStatus = + PowerStatus(hasBattery ? OptTrue : OptFalse, batteryLevel->isVBUSPlug() ? OptTrue : OptFalse, + batteryLevel->isChargeing() ? OptTrue : OptFalse, batteryVoltageMv, batteryChargePercent); newStatus.notifyObservers(&powerStatus); // If we have a battery at all and it is less than 10% full, force deep sleep if (powerStatus.getHasBattery() && !powerStatus.getHasUSB() && batteryLevel->getBattVoltage() < MIN_BAT_MILLIVOLTS) powerFSM.trigger(EVENT_LOW_BATTERY); + } else { + // No power sensing on this board - tell everyone else we have no idea what is happening + const PowerStatus powerStatus = PowerStatus(OptUnknown, OptUnknown, OptUnknown, -1, -1); + newStatus.notifyObservers(&powerStatus); } } diff --git a/src/PowerStatus.h b/src/PowerStatus.h index f40d9445c..c9bb89a05 100644 --- a/src/PowerStatus.h +++ b/src/PowerStatus.h @@ -1,103 +1,94 @@ #pragma once -#include #include "Status.h" #include "configuration.h" +#include -namespace meshtastic { +namespace meshtastic +{ - /// Describes the state of the GPS system. - class PowerStatus : public Status +/** + * A boolean where we have a third state of Unknown + */ +enum OptionalBool { OptFalse = 0, OptTrue = 1, OptUnknown = 2 }; + +/// Describes the state of the GPS system. +class PowerStatus : public Status +{ + + private: + CallbackObserver statusObserver = + CallbackObserver(this, &PowerStatus::updateStatus); + + /// Whether we have a battery connected + OptionalBool hasBattery = OptUnknown; + /// Battery voltage in mV, valid if haveBattery is true + int batteryVoltageMv = 0; + /// Battery charge percentage, either read directly or estimated + int8_t batteryChargePercent = 0; + /// Whether USB is connected + OptionalBool hasUSB = OptUnknown; + /// Whether we are charging the battery + OptionalBool isCharging = OptUnknown; + + public: + PowerStatus() { statusType = STATUS_TYPE_POWER; } + PowerStatus(OptionalBool hasBattery, OptionalBool hasUSB, OptionalBool isCharging, int batteryVoltageMv = -1, + int8_t batteryChargePercent = 0) + : Status() { + this->hasBattery = hasBattery; + this->hasUSB = hasUSB; + this->isCharging = isCharging; + this->batteryVoltageMv = batteryVoltageMv; + this->batteryChargePercent = batteryChargePercent; + } + PowerStatus(const PowerStatus &); + PowerStatus &operator=(const PowerStatus &); - private: - CallbackObserver statusObserver = CallbackObserver(this, &PowerStatus::updateStatus); + void observe(Observable *source) { statusObserver.observe(source); } - /// Whether we have a battery connected - bool hasBattery; - /// Battery voltage in mV, valid if haveBattery is true - int batteryVoltageMv; - /// Battery charge percentage, either read directly or estimated - uint8_t batteryChargePercent; - /// Whether USB is connected - bool hasUSB; - /// Whether we are charging the battery - bool isCharging; + bool getHasBattery() const { return hasBattery == OptTrue; } - public: + bool getHasUSB() const { return hasUSB == OptTrue; } - PowerStatus() { - statusType = STATUS_TYPE_POWER; - } - PowerStatus( bool hasBattery, bool hasUSB, bool isCharging, int batteryVoltageMv, uint8_t batteryChargePercent ) : Status() + /// Can we even know if this board has USB power or not + bool knowsUSB() const { return hasUSB != OptUnknown; } + + bool getIsCharging() const { return isCharging == OptTrue; } + + int getBatteryVoltageMv() const { return batteryVoltageMv; } + + /** + * Note: 0% battery means 'unknown/this board doesn't have a battery installed' + */ + uint8_t getBatteryChargePercent() const { return getHasBattery() ? batteryChargePercent : 0; } + + bool matches(const PowerStatus *newStatus) const + { + return (newStatus->getHasBattery() != hasBattery || newStatus->getHasUSB() != hasUSB || + newStatus->getBatteryVoltageMv() != batteryVoltageMv); + } + int updateStatus(const PowerStatus *newStatus) + { + // Only update the status if values have actually changed + bool isDirty; { - this->hasBattery = hasBattery; - this->hasUSB = hasUSB; - this->isCharging = isCharging; - this->batteryVoltageMv = batteryVoltageMv; - this->batteryChargePercent = batteryChargePercent; + isDirty = matches(newStatus); + initialized = true; + hasBattery = newStatus->hasBattery; + batteryVoltageMv = newStatus->getBatteryVoltageMv(); + batteryChargePercent = newStatus->getBatteryChargePercent(); + hasUSB = newStatus->hasUSB; + isCharging = newStatus->isCharging; } - PowerStatus(const PowerStatus &); - PowerStatus &operator=(const PowerStatus &); - - void observe(Observable *source) - { - statusObserver.observe(source); + if (isDirty) { + DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent); + onNewStatus.notifyObservers(this); } + return 0; + } +}; - bool getHasBattery() const - { - return hasBattery; - } - - bool getHasUSB() const - { - return hasUSB; - } - - bool getIsCharging() const - { - return isCharging; - } - - int getBatteryVoltageMv() const - { - return batteryVoltageMv; - } - - uint8_t getBatteryChargePercent() const - { - return batteryChargePercent; - } - - bool matches(const PowerStatus *newStatus) const - { - return ( - newStatus->getHasBattery() != hasBattery || - newStatus->getHasUSB() != hasUSB || - newStatus->getBatteryVoltageMv() != batteryVoltageMv - ); - } - int updateStatus(const PowerStatus *newStatus) { - // Only update the status if values have actually changed - bool isDirty; - { - isDirty = matches(newStatus); - initialized = true; - hasBattery = newStatus->getHasBattery(); - batteryVoltageMv = newStatus->getBatteryVoltageMv(); - batteryChargePercent = newStatus->getBatteryChargePercent(); - hasUSB = newStatus->getHasUSB(); - isCharging = newStatus->getIsCharging(); - } - if(isDirty) { - DEBUG_MSG("Battery %dmV %d%%\n", batteryVoltageMv, batteryChargePercent); - onNewStatus.notifyObservers(this); - } - return 0; - } - - }; - -} +} // namespace meshtastic extern meshtastic::PowerStatus *powerStatus; diff --git a/src/Status.h b/src/Status.h index eb41b60ce..4f0c71445 100644 --- a/src/Status.h +++ b/src/Status.h @@ -20,7 +20,7 @@ namespace meshtastic CallbackObserver statusObserver = CallbackObserver(this, &Status::updateStatus); bool initialized = false; // Workaround for no typeid support - int statusType; + int statusType = 0; public: // Allows us to generate observable events diff --git a/src/configuration.h b/src/configuration.h index 4b1addbb3..50e16e6ac 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -309,6 +309,7 @@ along with this program. If not, see . #define BUTTON_PIN \ 12 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one // between this pin and ground +#define BUTTON_NEED_PULLUP #define USE_RF95 #define LORA_DIO0 26 // a No connect on the SX1262 module diff --git a/src/gps/UBloxGPS.cpp b/src/gps/UBloxGPS.cpp index cab1ada4c..80d7064bb 100644 --- a/src/gps/UBloxGPS.cpp +++ b/src/gps/UBloxGPS.cpp @@ -102,8 +102,13 @@ bool UBloxGPS::factoryReset() // It is useful to force back into factory defaults (9600baud, NEMA to test the behavior of boards that don't have // GPS_TX connected) ublox.factoryReset(); - delay(3000); + delay(5000); tryConnect(); // sets isConnected + + // try a second time, the ublox lib serial parsing is buggy? + if (!tryConnect()) + tryConnect(); + DEBUG_MSG("GPS Factory reset success=%d\n", isConnected); if (isConnected) ok = setUBXMode(); @@ -122,72 +127,72 @@ int UBloxGPS::prepareSleep(void *unused) void UBloxGPS::doTask() { - uint8_t fixtype = 3; // If we are only using the RX pin, assume we have a 3d fix + if (isConnected) { + // Consume all characters that have arrived - assert(isConnected); + uint8_t fixtype = 3; // If we are only using the RX pin, assume we have a 3d fix - // Consume all characters that have arrived + // if using i2c or serial look too see if any chars are ready + ublox.checkUblox(); // See if new data is available. Process bytes as they come in. - // if using i2c or serial look too see if any chars are ready - ublox.checkUblox(); // See if new data is available. Process bytes as they come in. + // If we don't have a fix (a quick check), don't try waiting for a solution) + // Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions + // turn off for now + uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait + fixtype = ublox.getFixType(maxWait); + DEBUG_MSG("GPS fix type %d\n", fixtype); - // If we don't have a fix (a quick check), don't try waiting for a solution) - // Hmmm my fix type reading returns zeros for fix, which doesn't seem correct, because it is still sptting out positions - // turn off for now - uint16_t maxWait = i2cAddress ? 300 : 0; // If using i2c we must poll with wait - fixtype = ublox.getFixType(maxWait); - DEBUG_MSG("GPS fix type %d\n", fixtype); + // DEBUG_MSG("sec %d\n", ublox.getSecond()); + // DEBUG_MSG("lat %d\n", ublox.getLatitude()); - // DEBUG_MSG("sec %d\n", ublox.getSecond()); - // DEBUG_MSG("lat %d\n", ublox.getLatitude()); + // any fix that has time - // any fix that has time + if (ublox.getT(maxWait)) { + /* 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(t); + } - if (ublox.getT(maxWait)) { - /* 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(t); + latitude = ublox.getLatitude(0); + 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! + hasValidLocation = + (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0); + + // we only notify if position has changed due to a new fix + if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only + { + if (hasValidLocation) { + wantNewLocation = false; + // ublox.powerOff(); + } + } else // we didn't get a location update, go back to sleep and hope the characters show up + wantNewLocation = true; + + // Notify any status instances that are observing us + const meshtastic::GPSStatus status = + meshtastic::GPSStatus(hasLock(), isConnected, latitude, longitude, altitude, dop, heading, numSatellites); + newStatus.notifyObservers(&status); } - latitude = ublox.getLatitude(0); - 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! - hasValidLocation = - (latitude != 0) && (longitude != 0) && (latitude <= 900000000 && latitude >= -900000000) && (numSatellites > 0); - - // we only notify if position has changed due to a new fix - if ((fixtype >= 3 && fixtype <= 4) && ublox.getP(maxWait)) // rd fixes only - { - if (hasValidLocation) { - wantNewLocation = false; - // ublox.powerOff(); - } - } else // we didn't get a location update, go back to sleep and hope the characters show up - wantNewLocation = true; - - // Notify any status instances that are observing us - 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 - // the serial + // Once we have sent a location once we only poll the GPS rarely, otherwise check back every 10s until we have something + // over the serial setPeriod(hasValidLocation && !wantNewLocation ? 30 * 1000 : 10 * 1000); } diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index ca0995c65..3cf3e93f7 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -774,7 +774,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 // Display power status if (powerStatus->getHasBattery()) drawBattery(display, x, y + 2, imgBattery, powerStatus); - else + else if (powerStatus->knowsUSB()) display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower); // Display nodes status drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus); @@ -819,14 +819,16 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) // DEBUG_MSG("Screen got status update %d\n", arg->getStatusType()); switch (arg->getStatusType()) { case STATUS_TYPE_NODE: - if (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) - setFrames(); - prevFrame = -1; + if (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { + setFrames(); // Regen the list of screens + prevFrame = -1; // Force a GUI update + setPeriod(1); // Update the screen right away + } nodeDB.updateGUI = false; nodeDB.updateTextMessage = false; break; } - setPeriod(1); // Update the screen right away + return 0; } } // namespace graphics diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 26be9de3f..45a9fed75 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -68,6 +68,9 @@ void printPacket(const char *prefix, const MeshPacket *p) if (p->rx_time != 0) { DEBUG_MSG(" rxtime=%u", p->rx_time); } + if (p->rx_snr != 0.0) { + DEBUG_MSG(" rxSNR=%g", p->rx_snr); + } DEBUG_MSG(")\n"); } @@ -115,8 +118,6 @@ unsigned long hash(char *str) return hash; } - - #define POWER_DEFAULT 17 /** diff --git a/src/mesh/SX1262Interface.cpp b/src/mesh/SX1262Interface.cpp index 6350741e4..b7fe422f3 100644 --- a/src/mesh/SX1262Interface.cpp +++ b/src/mesh/SX1262Interface.cpp @@ -74,6 +74,10 @@ bool SX1262Interface::reconfigure() err = lora.setCodingRate(cr); assert(err == ERR_NONE); + // Hmm - seems to lower SNR when the signal levels are high. Leaving off for now... + //err = lora.setRxGain(true); + //assert(err == ERR_NONE); + err = lora.setSyncWord(syncWord); assert(err == ERR_NONE); @@ -123,6 +127,7 @@ void SX1262Interface::setStandby() */ void SX1262Interface::addReceiveMetadata(MeshPacket *mp) { + // DEBUG_MSG("PacketStatus %x\n", lora.getPacketStatus()); mp->rx_snr = lora.getSNR(); } diff --git a/src/sleep.cpp b/src/sleep.cpp index f7d61eb77..3bce72669 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -197,7 +197,7 @@ void doDeepSleep(uint64_t msecToWake) static const uint8_t rtcGpios[] = {/* 0, */ 2, /* 4, */ #ifndef USE_JTAG - 12, 13, + 13, /* 14, */ /* 15, */ #endif /* 25, */ 26, /* 27, */