diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 32f280a04..512dea311 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -7,7 +7,7 @@
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc...
- Please do not check in files that don't have real changes
- Please do not reformat lines that you didn't have to change the code on
-- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (WSL2 is required on windows),
+- We recommend using the [Visual Studio Code](https://platformio.org/install/ide?install=vscode) editor along with the ['Trunk Check' extension](https://marketplace.visualstudio.com/items?itemName=trunk.io) (In beta for windows, WSL2 for the linux version),
because it automatically follows our indentation rules and its auto reformatting will not cause spurious changes to lines.
- If your PR fixes a bug, mention "fixes #bugnum" somewhere in your pull request description.
- If your other co-developers have comments on your PR please tweak as needed.
diff --git a/.trunk/.gitignore b/.trunk/.gitignore
index 695b51906..1e2465290 100644
--- a/.trunk/.gitignore
+++ b/.trunk/.gitignore
@@ -2,7 +2,7 @@
*logs
*actions
*notifications
+*tools
plugins
user_trunk.yaml
user.yaml
-tools
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index 7e81046a7..9c1dcf707 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -1,53 +1,53 @@
version: 0.1
cli:
- version: 1.13.0
+ version: 1.17.0
plugins:
sources:
- id: trunk
- ref: v1.1.1
+ ref: v1.2.5
uri: https://github.com/trunk-io/plugins
lint:
enabled:
- bandit@1.7.5
- - checkov@2.4.1
+ - checkov@2.5.0
- terrascan@1.18.3
- - trivy@0.44.1
- - trufflehog@3.48.0
+ - trivy@0.45.1
+ - trufflehog@3.59.0
- taplo@0.8.1
- - ruff@0.0.284
+ - ruff@0.0.292
- yamllint@1.32.0
- isort@5.12.0
- - markdownlint@0.35.0
+ - markdownlint@0.37.0
- oxipng@8.0.0
- svgo@3.0.2
- - actionlint@1.6.25
+ - actionlint@1.6.26
- flake8@6.1.0
- hadolint@2.12.0
- shfmt@3.6.0
- shellcheck@0.9.0
- - black@23.7.0
+ - black@23.9.1
- git-diff-check
- - gitleaks@8.17.0
+ - gitleaks@8.18.0
- clang-format@16.0.3
- - prettier@3.0.2
+ - prettier@3.0.3
disabled:
- taplo@0.8.1
- shellcheck@0.9.0
- shfmt@3.6.0
- oxipng@8.0.0
- actionlint@1.6.22
- - markdownlint@0.35.0
+ - markdownlint@0.37.0
- hadolint@2.12.0
- svgo@3.0.2
runtimes:
enabled:
- python@3.10.8
- - go@1.19.5
+ - go@1.21.0
- node@18.12.1
actions:
disabled:
- trunk-announce
- - trunk-check-pre-push
- - trunk-fmt-pre-commit
enabled:
+ - trunk-fmt-pre-commit
+ - trunk-check-pre-push
- trunk-upgrade-available
diff --git a/README.md b/README.md
index d450b88d3..ca8a924fd 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,8 @@
This repository contains the device firmware for the Meshtastic project.
-**[Building Instructions](https://meshtastic.org/docs/development/firmware/build)**
-**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
+- **[Building Instructions](https://meshtastic.org/docs/development/firmware/build)**
+- **[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
## Stats
diff --git a/boards/tbeam-s3-core.json b/boards/tbeam-s3-core.json
index 767791d35..7bda2e5a0 100644
--- a/boards/tbeam-s3-core.json
+++ b/boards/tbeam-s3-core.json
@@ -15,7 +15,7 @@
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
- "hwids": [["0X303A", "0x1001"]],
+ "hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "tbeam-s3-core"
},
diff --git a/platformio.ini b/platformio.ini
index 0a5029f9d..a6ad6f873 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -70,7 +70,7 @@ lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306
https://github.com/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159
- https://github.com/meshtastic/TinyGPSPlus.git#127ad674ef85f0201cb68a065879653ed94792c4
+ https://github.com/meshtastic/TinyGPSPlus.git#076e8d2c8fb702d9be5b08c55b93ff76f8af7e61
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1
diff --git a/protobufs b/protobufs
index fb28d5935..6290ee0f6 160000
--- a/protobufs
+++ b/protobufs
@@ -1 +1 @@
-Subproject commit fb28d593526467977cf353959a66e11373928282
+Subproject commit 6290ee0f6aa15939ee582c3c59bc7a048cc0478f
diff --git a/src/DisplayFormatters.cpp b/src/DisplayFormatters.cpp
new file mode 100644
index 000000000..f15052de6
--- /dev/null
+++ b/src/DisplayFormatters.cpp
@@ -0,0 +1,34 @@
+#include "DisplayFormatters.h"
+
+const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName)
+{
+ switch (preset) {
+ case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
+ return useShortName ? "ShortS" : "ShortSlow";
+ break;
+ case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
+ return useShortName ? "ShortF" : "ShortFast";
+ break;
+ case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
+ return useShortName ? "MedS" : "MediumSlow";
+ break;
+ case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
+ return useShortName ? "MedF" : "MediumFast";
+ break;
+ case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
+ return useShortName ? "LongS" : "LongSlow";
+ break;
+ case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
+ return useShortName ? "LongF" : "LongFast";
+ break;
+ case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
+ return useShortName ? "LongM" : "LongMod";
+ break;
+ case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
+ return useShortName ? "VeryL" : "VLongSlow";
+ break;
+ default:
+ return useShortName ? "Custom" : "Invalid";
+ break;
+ }
+}
\ No newline at end of file
diff --git a/src/DisplayFormatters.h b/src/DisplayFormatters.h
new file mode 100644
index 000000000..f8ccfcbb6
--- /dev/null
+++ b/src/DisplayFormatters.h
@@ -0,0 +1,8 @@
+#pragma once
+#include "NodeDB.h"
+
+class DisplayFormatters
+{
+ public:
+ static const char *getModemPresetDisplayName(meshtastic_Config_LoRaConfig_ModemPreset preset, bool useShortName);
+};
diff --git a/src/Power.cpp b/src/Power.cpp
index dd9f70130..e6f7ac990 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -175,9 +175,21 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = 0;
#ifdef ARCH_ESP32
#ifndef BAT_MEASURE_ADC_UNIT // ADC1
+#ifdef ADC_CTRL
+ if (heltec_version == 5) {
+ pinMode(ADC_CTRL, OUTPUT);
+ digitalWrite(ADC_CTRL, HIGH);
+ delay(10);
+ }
+#endif
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel);
}
+#ifdef ADC_CTRL
+ if (heltec_version == 5) {
+ digitalWrite(ADC_CTRL, LOW);
+ }
+#endif
#else // ADC2
int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
@@ -269,9 +281,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
#if defined(HAS_TELEMETRY) && (HAS_TELEMETRY == 1) && !defined(ARCH_PORTDUINO)
uint16_t getINAVoltage()
{
- if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
+ if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {
return ina219Sensor.getBusVoltageMv();
- } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
+ } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first ==
+ config.power.device_battery_ina_address) {
return ina260Sensor.getBusVoltageMv();
}
return 0;
@@ -282,11 +295,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
if (!config.power.device_battery_ina_address) {
return false;
}
- if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219] == config.power.device_battery_ina_address) {
+ if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA219].first == config.power.device_battery_ina_address) {
if (!ina219Sensor.isInitialized())
return ina219Sensor.runOnce() > 0;
return ina219Sensor.isRunning();
- } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260] == config.power.device_battery_ina_address) {
+ } else if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_INA260].first ==
+ config.power.device_battery_ina_address) {
if (!ina260Sensor.isInitialized())
return ina260Sensor.runOnce() > 0;
return ina260Sensor.isRunning();
@@ -414,7 +428,7 @@ void Power::shutdown()
#ifdef PIN_LED3
ledOff(PIN_LED2);
#endif
- doDeepSleep(DELAY_FOREVER);
+ doDeepSleep(DELAY_FOREVER, false);
#endif
}
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index eceb545fe..c64599ce6 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -45,7 +45,7 @@ static void sdsEnter()
{
LOG_DEBUG("Enter state: SDS\n");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw
- doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs));
+ doDeepSleep(getConfiguredOrDefaultMs(config.power.sds_secs), false);
}
extern Power *power;
@@ -154,9 +154,6 @@ static void darkEnter()
{
setBluetoothEnable(true);
screen->setOn(false);
-#ifdef KB_POWERON
- digitalWrite(KB_POWERON, LOW);
-#endif
}
static void serialEnter()
@@ -184,9 +181,6 @@ static void powerEnter()
} else {
screen->setOn(true);
setBluetoothEnable(true);
-#ifdef KB_POWERON
- digitalWrite(KB_POWERON, HIGH);
-#endif
// within enter() the function getState() returns the state we came from
if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
strcmp(powerFSM.getState()->name, "DARK") != 0) {
@@ -217,9 +211,6 @@ static void onEnter()
LOG_DEBUG("Enter state: ON\n");
screen->setOn(true);
setBluetoothEnable(true);
-#ifdef KB_POWERON
- digitalWrite(KB_POWERON, HIGH);
-#endif
}
static void onIdle()
@@ -254,6 +245,8 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup()
{
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0);
+ bool isTrackerOrSensor = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
+ config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR;
bool hasPower = isPowered();
LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0);
@@ -357,12 +350,12 @@ void PowerFSM_setup()
getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout");
+// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
#ifdef ARCH_ESP32
- State *lowPowerState = &stateLS;
- // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
-
// See: https://github.com/meshtastic/firmware/issues/1071
- if (isRouter || config.power.is_power_saving) {
+ // Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiatiated through the
+ // modules
+ if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) {
powerFSM.add_timed_transition(&stateNB, &stateLS,
getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
"Min wake timeout");
diff --git a/src/concurrency/OSThread.h b/src/concurrency/OSThread.h
index 7957ee952..0fbfe2e17 100644
--- a/src/concurrency/OSThread.h
+++ b/src/concurrency/OSThread.h
@@ -67,6 +67,7 @@ class OSThread : public Thread
* Returns desired period for next invocation (or RUN_SAME for no change)
*/
virtual int32_t runOnce() = 0;
+ bool sleepOnNextExecution = false;
// Do not override this
virtual void run();
diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h
index 52c3cb085..9acd736d2 100644
--- a/src/detect/ScanI2CTwoWire.h
+++ b/src/detect/ScanI2CTwoWire.h
@@ -18,6 +18,8 @@ class ScanI2CTwoWire : public ScanI2C
ScanI2C::FoundDevice find(ScanI2C::DeviceType) const override;
+ TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
+
bool exists(ScanI2C::DeviceType) const override;
size_t countDevices() const override;
@@ -51,6 +53,4 @@ class ScanI2CTwoWire : public ScanI2C
uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const;
DeviceType probeOLED(ScanI2C::DeviceAddress) const;
-
- TwoWire *fetchI2CBus(ScanI2C::DeviceAddress) const;
};
diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp
index 13afaa3e6..ce5b18af8 100644
--- a/src/gps/GPS.cpp
+++ b/src/gps/GPS.cpp
@@ -20,7 +20,7 @@ HardwareSerial *GPS::_serial_gps = &Serial1;
HardwareSerial *GPS::_serial_gps = NULL;
#endif
-GPS *gps;
+GPS *gps = nullptr;
/// Multiple GPS instances might use the same serial port (in sequence), but we can
/// only init that port once.
@@ -76,28 +76,25 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
while (millis() < startTimeout) {
if (_serial_gps->available()) {
b = _serial_gps->read();
+#ifdef GPS_DEBUG
+ LOG_DEBUG("%02X", (char *)buffer);
+#endif
buffer[bytesRead] = b;
bytesRead++;
if ((bytesRead == 767) || (b == '\r')) {
if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
#ifdef GPS_DEBUG
- buffer[bytesRead] = '\0';
- LOG_DEBUG("%s\r", (char *)buffer);
+ LOG_DEBUG("\r");
#endif
return GNSS_RESPONSE_OK;
} else {
-#ifdef GPS_DEBUG
- buffer[bytesRead] = '\0';
- LOG_INFO("Bytes read:%s\n", (char *)buffer);
-#endif
bytesRead = 0;
}
}
}
}
#ifdef GPS_DEBUG
- buffer[bytesRead] = '\0';
- LOG_INFO("Bytes read:%s\n", (char *)buffer);
+ LOG_DEBUG("\n");
#endif
return GNSS_RESPONSE_NONE;
}
@@ -252,10 +249,18 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t
bool GPS::setup()
{
int msglen = 0;
+ bool isProblematicGPS = false;
if (!didSerialInit) {
#if !defined(GPS_UC6580)
- if (tx_gpio) {
+#ifdef HAS_PMU
+ // The T-Beam 1.2 has issues with the GPS
+ if (HW_VENDOR == meshtastic_HardwareModel_TBEAM && PMU->getChipModel() == XPOWERS_AXP2101) {
+ gnssModel = GNSS_MODEL_UBLOX;
+ isProblematicGPS = true;
+ }
+#endif
+ if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) {
LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]);
gnssModel = probe(serialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) {
@@ -390,32 +395,36 @@ bool GPS::setup()
LOG_WARN("Unable to enable powersaving for GPS.\n");
}
} else {
- if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware
- msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving mode for GPS.\n");
- }
- msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving details for GPS.\n");
- }
- } else {
- msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n");
+ if (!(isProblematicGPS)) {
+ if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware
+ msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
+ LOG_WARN("Unable to enable powersaving mode for GPS.\n");
+ }
+ msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) {
+ LOG_WARN("Unable to enable powersaving details for GPS.\n");
+ }
+ } else {
+ msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
+ LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n");
+ }
}
}
}
-
- msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
- _serial_gps->write(UBXscratch, msglen);
- if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) {
- LOG_WARN("Unable to save GNSS module configuration.\n");
- } else {
- LOG_INFO("GNSS module configuration saved!\n");
+ // The T-beam 1.2 has issues.
+ if (!(isProblematicGPS)) {
+ msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
+ _serial_gps->write(UBXscratch, msglen);
+ if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) {
+ LOG_WARN("Unable to save GNSS module configuration.\n");
+ } else {
+ LOG_INFO("GNSS module configuration saved!\n");
+ }
}
}
didSerialInit = true;
@@ -433,7 +442,7 @@ GPS::~GPS()
notifyGPSSleepObserver.observe(¬ifyGPSSleep);
}
-void GPS::setGPSPower(bool on, bool standbyOnly)
+void GPS::setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime)
{
LOG_INFO("Setting GPS power=%d\n", on);
if (on) {
@@ -483,6 +492,10 @@ void GPS::setGPSPower(bool on, bool standbyOnly)
if (!on) {
if (gnssModel == GNSS_MODEL_UBLOX) {
uint8_t msglen;
+ LOG_DEBUG("Sleep Time: %i\n", sleepTime);
+ for (int i = 0; i < 4; i++) {
+ gps->_message_PMREQ[0 + i] = sleepTime >> (i * 8); // Encode the sleep time in millis into the packet
+ }
msglen = gps->makeUBXPacket(0x02, 0x41, 0x08, gps->_message_PMREQ);
gps->_serial_gps->write(gps->UBXscratch, msglen);
}
@@ -514,7 +527,7 @@ void GPS::setAwake(bool on)
LOG_DEBUG("WANT GPS=%d\n", on);
isAwake = on;
if (!enabled) { // short circuit if the user has disabled GPS
- setGPSPower(false, false);
+ setGPSPower(false, false, 0);
return;
}
@@ -532,12 +545,12 @@ void GPS::setAwake(bool on)
}
if ((int32_t)getSleepTime() - averageLockTime >
15 * 60 * 1000) { // 15 minutes is probably long enough to make a complete poweroff worth it.
- setGPSPower(on, false);
+ setGPSPower(on, false, getSleepTime() - averageLockTime);
} else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby
#ifdef GPS_UC6580
- setGPSPower(on, false);
+ setGPSPower(on, false, getSleepTime() - averageLockTime);
#else
- setGPSPower(on, true);
+ setGPSPower(on, true, getSleepTime() - averageLockTime);
#endif
} else if (averageLockTime > 20000) {
averageLockTime -= 1000; // eventually want to sleep again.
@@ -598,7 +611,7 @@ int32_t GPS::runOnce()
return 2000; // Setup failed, re-run in two seconds
// We have now loaded our saved preferences from flash
- if (config.position.gps_enabled == false && config.position.fixed_position == false) {
+ if (config.position.gps_enabled == false) {
return disable();
}
// ONCE we will factory reset the GPS for bug #327
@@ -631,6 +644,11 @@ int32_t GPS::runOnce()
}
}
}
+ // At least one GPS has a bad habit of losing its mind from time to time
+ if (rebootsSeen > 2) {
+ rebootsSeen = 0;
+ gps->factoryReset();
+ }
// If we are overdue for an update, turn on the GPS and at least publish the current status
uint32_t now = millis();
@@ -685,8 +703,8 @@ int32_t GPS::runOnce()
// If state has changed do a publish
publishUpdate();
- if (config.position.gps_enabled == false) // This should trigger if GPS is disabled but fixed_position is true
- return disable();
+ if (config.position.fixed_position == true && hasValidLocation)
+ return disable(); // This should trigger when we have a fixed position, and get that first position
// 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.
@@ -899,9 +917,7 @@ GPS *GPS::createGps()
LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
#endif
- if (config.position.gps_enabled) {
- new_gps->setGPSPower(true, false);
- }
+ new_gps->setGPSPower(true, false, 0);
#ifdef PIN_GPS_RESET
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
@@ -956,11 +972,38 @@ bool GPS::factoryReset()
digitalWrite(PIN_GPS_REINIT, 1);
#endif
- // send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
- // Factory Reset
- byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
- _serial_gps->write(_message_reset, sizeof(_message_reset));
+ if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) {
+ byte _message_reset1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2};
+ _serial_gps->write(_message_reset1, sizeof(_message_reset1));
+ if (getACK(0x05, 0x01, 10000)) {
+ LOG_INFO("Get ack success!\n");
+ }
+ delay(100);
+ byte _message_reset2[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1B, 0xA1};
+ _serial_gps->write(_message_reset2, sizeof(_message_reset2));
+ if (getACK(0x05, 0x01, 10000)) {
+ LOG_INFO("Get ack success!\n");
+ }
+ delay(100);
+ byte _message_reset3[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x03, 0x1D, 0xB3};
+ _serial_gps->write(_message_reset3, sizeof(_message_reset3));
+ if (getACK(0x05, 0x01, 10000)) {
+ LOG_INFO("Get ack success!\n");
+ }
+ // Reset device ram to COLDSTART state
+ // byte _message_CFG_RST_COLDSTART[] = {0xB5, 0x62, 0x06, 0x04, 0x04, 0x00, 0xFF, 0xB9, 0x00, 0x00, 0xC6, 0x8B};
+ // _serial_gps->write(_message_CFG_RST_COLDSTART, sizeof(_message_CFG_RST_COLDSTART));
+ // delay(1000);
+ } else {
+ // send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX.
+ // Factory Reset
+ byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E};
+ _serial_gps->write(_message_reset, sizeof(_message_reset));
+ }
delay(1000);
return true;
}
@@ -1157,6 +1200,7 @@ bool GPS::hasFlow()
bool GPS::whileIdle()
{
+ int charsInBuf = 0;
bool isValid = false;
if (!isAwake) {
clearBuffer();
@@ -1173,10 +1217,20 @@ bool GPS::whileIdle()
// First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) {
int c = _serial_gps->read();
- // LOG_DEBUG("%c", c);
+ UBXscratch[charsInBuf] = c;
+#ifdef GPS_DEBUG
+ LOG_DEBUG("%c", c);
+#endif
isValid |= reader.encode(c);
+ if (charsInBuf > sizeof(UBXscratch) - 10 || c == '\r') {
+ if (strnstr((char *)UBXscratch, "$GPTXT,01,01,02,u-blox ag - www.u-blox.com*50", charsInBuf)) {
+ rebootsSeen++;
+ }
+ charsInBuf = 0;
+ } else {
+ charsInBuf++;
+ }
}
-
return isValid;
}
void GPS::enable()
diff --git a/src/gps/GPS.h b/src/gps/GPS.h
index 4269acf2d..d52c79182 100644
--- a/src/gps/GPS.h
+++ b/src/gps/GPS.h
@@ -94,7 +94,7 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_gps;
- static const uint8_t _message_PMREQ[];
+ static uint8_t _message_PMREQ[];
static const uint8_t _message_CFG_RXM_PSM[];
static const uint8_t _message_CFG_RXM_ECO[];
static const uint8_t _message_CFG_PM2[];
@@ -132,7 +132,7 @@ class GPS : private concurrency::OSThread
// Disable the thread
int32_t disable() override;
- void setGPSPower(bool on, bool standbyOnly);
+ void setGPSPower(bool on, bool standbyOnly, uint32_t sleepTime);
/// Returns true if we have acquired GPS lock.
virtual bool hasLock();
@@ -154,6 +154,8 @@ class GPS : private concurrency::OSThread
// scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0};
+ int rebootsSeen = 0;
+
int getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t requestedID, uint32_t waitMillis);
GPS_RESPONSE getACK(uint8_t c, uint8_t i, uint32_t waitMillis);
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
diff --git a/src/gps/ubx.h b/src/gps/ubx.h
index 6493b2ce7..bc839c41e 100644
--- a/src/gps/ubx.h
+++ b/src/gps/ubx.h
@@ -1,4 +1,4 @@
-const uint8_t GPS::_message_PMREQ[] PROGMEM = {
+uint8_t GPS::_message_PMREQ[] PROGMEM = {
0x00, 0x00, // 4 bytes duration of request task
0x00, 0x00, // (milliseconds)
0x02, 0x00, // Task flag bitfield
@@ -17,7 +17,7 @@ const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = {
const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
0x01, 0x06, 0x00, 0x00, // version, Reserved
- 0x0e, 0x81, 0x42, 0x01, // flags
+ 0x0E, 0x81, 0x43, 0x01, // flags
0xE8, 0x03, 0x00, 0x00, // update period 1000 ms
0x10, 0x27, 0x00, 0x00, // search period 10s
0x00, 0x00, 0x00, 0x00, // Grod offset 0
@@ -189,4 +189,4 @@ const uint8_t GPS::_message_SAVE[] = {
0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash
-};
\ No newline at end of file
+};
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 9ccd28aba..b626e393a 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -24,6 +24,7 @@ along with this program. If not, see .
#if HAS_SCREEN
#include
+#include "DisplayFormatters.h"
#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
@@ -160,17 +161,9 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
xstr(APP_VERSION_SHORT)); // Note: we don't bother printing region or now, it makes the string too long
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(buf), y + 0, buf);
screen->forceDisplay();
-
// FIXME - draw serial # somewhere?
}
-static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
-{
- // Draw region in upper left
- const char *region = myRegion ? myRegion->name : NULL;
- drawIconScreen(region, display, state, x, y);
-}
-
static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
// draw an xbm image.
@@ -220,6 +213,28 @@ static void drawOEMBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i
drawOEMIconScreen(region, display, state, x, y);
}
+static void drawFrameText(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y, const char *message)
+{
+ uint16_t x_offset = display->width() / 2;
+ display->setTextAlignment(TEXT_ALIGN_CENTER);
+ display->setFont(FONT_MEDIUM);
+ display->drawString(x_offset + x, 26 + y, message);
+}
+
+static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+{
+#ifdef ARCH_ESP32
+ if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) {
+ drawFrameText(display, state, x, y, "Resuming...");
+ } else
+#endif
+ {
+ // Draw region in upper left
+ const char *region = myRegion ? myRegion->name : NULL;
+ drawIconScreen(region, display, state, x, y);
+ }
+}
+
// Used on boot when a certificate is being created
static void drawSSLScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
@@ -320,22 +335,6 @@ static void drawFrameBluetooth(OLEDDisplay *display, OLEDDisplayUiState *state,
display->drawString(x_offset + x, y_offset + y, deviceName);
}
-static void drawFrameShutdown(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
-{
- uint16_t x_offset = display->width() / 2;
- display->setTextAlignment(TEXT_ALIGN_CENTER);
- display->setFont(FONT_MEDIUM);
- display->drawString(x_offset + x, 26 + y, "Shutting down...");
-}
-
-static void drawFrameReboot(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
-{
- uint16_t x_offset = display->width() / 2;
- display->setTextAlignment(TEXT_ALIGN_CENTER);
- display->setFont(FONT_MEDIUM);
- display->drawString(x_offset + x, 26 + y, "Rebooting...");
-}
-
static void drawFrameFirmware(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_CENTER);
@@ -906,20 +905,6 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_
drawColumns(display, x, y, fields);
}
-// #ifdef RAK4630
-// Screen::Screen(uint8_t address, int sda, int scl) : OSThread("Screen"), cmdQueue(32), dispdev(address, sda, scl),
-// dispdev_oled(address, sda, scl), ui(&dispdev)
-// {
-// address_found = address;
-// cmdQueue.setReader(this);
-// if (screen_found) {
-// (void)dispdev;
-// AutoOLEDWire dispdev = dispdev_oled;
-// (void)ui;
-// OLEDDisplayUi ui(&dispdev);
-// }
-// }
-// #else
Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_OledType screenType, OLEDDISPLAY_GEOMETRY geometry)
: concurrency::OSThread("Screen"), address_found(address), model(screenType), geometry(geometry), cmdQueue(32),
dispdev(address.address, -1, -1, geometry, (address.port == ScanI2C::I2CPort::WIRE1) ? HW_I2C::I2C_TWO : HW_I2C::I2C_ONE),
@@ -927,7 +912,7 @@ Screen::Screen(ScanI2C::DeviceAddress address, meshtastic_Config_DisplayConfig_O
{
cmdQueue.setReader(this);
}
-// #endif
+
/**
* Prepare the display for the unit going to the lowest power mode possible. Most screens will just
* poweroff, but eink screens will show a "I'm sleeping" graphic, possibly with a QR code
@@ -1244,11 +1229,8 @@ void Screen::setWelcomeFrames()
{
if (address_found.address) {
// LOG_DEBUG("showing Welcome frames\n");
- ui.disableAllIndicators();
-
- static FrameCallback welcomeFrames[] = {drawWelcomeScreen};
- ui.setFrames(welcomeFrames, 1);
- ui.update();
+ static FrameCallback frames[] = {drawWelcomeScreen};
+ setFrameImmediateDraw(frames);
}
}
@@ -1335,12 +1317,15 @@ void Screen::handleStartBluetoothPinScreen(uint32_t pin)
LOG_DEBUG("showing bluetooth screen\n");
showingNormalScreen = false;
- static FrameCallback btFrames[] = {drawFrameBluetooth};
-
+ static FrameCallback frames[] = {drawFrameBluetooth};
snprintf(btPIN, sizeof(btPIN), "%06u", pin);
+ setFrameImmediateDraw(frames);
+}
+void Screen::setFrameImmediateDraw(FrameCallback *drawFrames)
+{
ui.disableAllIndicators();
- ui.setFrames(btFrames, 1);
+ ui.setFrames(drawFrames, 1);
setFastFramerate();
}
@@ -1349,11 +1334,12 @@ void Screen::handleShutdownScreen()
LOG_DEBUG("showing shutdown screen\n");
showingNormalScreen = false;
- static FrameCallback shutdownFrames[] = {drawFrameShutdown};
+ auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
+ drawFrameText(display, state, x, y, "Shutting down...");
+ };
+ static FrameCallback frames[] = {frame};
- ui.disableAllIndicators();
- ui.setFrames(shutdownFrames, 1);
- setFastFramerate();
+ setFrameImmediateDraw(frames);
}
void Screen::handleRebootScreen()
@@ -1361,11 +1347,11 @@ void Screen::handleRebootScreen()
LOG_DEBUG("showing reboot screen\n");
showingNormalScreen = false;
- static FrameCallback rebootFrames[] = {drawFrameReboot};
-
- ui.disableAllIndicators();
- ui.setFrames(rebootFrames, 1);
- setFastFramerate();
+ auto frame = [](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void {
+ drawFrameText(display, state, x, y, "Rebooting...");
+ };
+ static FrameCallback frames[] = {frame};
+ setFrameImmediateDraw(frames);
}
void Screen::handleStartFirmwareUpdateScreen()
@@ -1373,11 +1359,8 @@ void Screen::handleStartFirmwareUpdateScreen()
LOG_DEBUG("showing firmware screen\n");
showingNormalScreen = false;
- static FrameCallback btFrames[] = {drawFrameFirmware};
-
- ui.disableAllIndicators();
- ui.setFrames(btFrames, 1);
- setFastFramerate();
+ static FrameCallback frames[] = {drawFrameFirmware};
+ setFrameImmediateDraw(frames);
}
void Screen::blink()
@@ -1638,65 +1621,8 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i
} else {
// Codes:
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
- if (getWifiDisconnectReason() == 2) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Authentication Invalid");
- } else if (getWifiDisconnectReason() == 3) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "De-authenticated");
- } else if (getWifiDisconnectReason() == 4) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated Expired");
- } else if (getWifiDisconnectReason() == 5) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP - Too Many Clients");
- } else if (getWifiDisconnectReason() == 6) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_AUTHED");
- } else if (getWifiDisconnectReason() == 7) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "NOT_ASSOCED");
- } else if (getWifiDisconnectReason() == 8) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Disassociated");
- } else if (getWifiDisconnectReason() == 9) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_NOT_AUTHED");
- } else if (getWifiDisconnectReason() == 10) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_PWRCAP_BAD");
- } else if (getWifiDisconnectReason() == 11) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "DISASSOC_SUPCHAN_BAD");
- } else if (getWifiDisconnectReason() == 13) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_INVALID");
- } else if (getWifiDisconnectReason() == 14) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "MIC_FAILURE");
- } else if (getWifiDisconnectReason() == 15) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Handshake Timeout");
- } else if (getWifiDisconnectReason() == 16) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "GROUP_KEY_UPDATE_TIMEOUT");
- } else if (getWifiDisconnectReason() == 17) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IE_IN_4WAY_DIFFERS");
- } else if (getWifiDisconnectReason() == 18) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Group Cipher");
- } else if (getWifiDisconnectReason() == 19) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Invalid Pairwise Cipher");
- } else if (getWifiDisconnectReason() == 20) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AKMP_INVALID");
- } else if (getWifiDisconnectReason() == 21) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "UNSUPP_RSN_IE_VERSION");
- } else if (getWifiDisconnectReason() == 22) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "INVALID_RSN_IE_CAP");
- } else if (getWifiDisconnectReason() == 23) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "802_1X_AUTH_FAILED");
- } else if (getWifiDisconnectReason() == 24) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "CIPHER_SUITE_REJECTED");
- } else if (getWifiDisconnectReason() == 200) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "BEACON_TIMEOUT");
- } else if (getWifiDisconnectReason() == 201) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AP Not Found");
- } else if (getWifiDisconnectReason() == 202) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "AUTH_FAIL");
- } else if (getWifiDisconnectReason() == 203) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "ASSOC_FAIL");
- } else if (getWifiDisconnectReason() == 204) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "HANDSHAKE_TIMEOUT");
- } else if (getWifiDisconnectReason() == 205) {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
- } else {
- display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unknown Status");
- }
+ display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
+ WiFi.disconnectReasonName(static_cast(getWifiDisconnectReason())));
}
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
@@ -1743,37 +1669,7 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
display->drawString(x + 1, y, String("USB"));
}
- auto mode = "";
-
- switch (config.lora.modem_preset) {
- case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
- mode = "ShortS";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
- mode = "ShortF";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
- mode = "MedS";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
- mode = "MedF";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
- mode = "LongS";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
- mode = "LongF";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
- mode = "LongM";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
- mode = "VeryL";
- break;
- default:
- mode = "Custom";
- break;
- }
+ auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
if (config.display.heading_bold)
@@ -1840,23 +1736,6 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat
heartbeat = !heartbeat;
#endif
}
-// adjust Brightness cycle through 1 to 254 as long as attachDuringLongPress is true
-void Screen::adjustBrightness()
-{
- if (!useDisplay)
- return;
-
- if (brightness == 254) {
- brightness = 0;
- } else {
- brightness++;
- }
- int width = brightness / (254.00 / SCREEN_WIDTH);
- dispdev.drawRect(0, 30, SCREEN_WIDTH, 4);
- dispdev.fillRect(0, 31, width, 2);
- dispdev.display();
- dispdev.setBrightness(brightness);
-}
int Screen::handleStatusUpdate(const meshtastic::Status *arg)
{
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index 8812b7c70..d6fb7b5d3 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -19,7 +19,6 @@ class Screen
void setup() {}
void setOn(bool) {}
void print(const char *) {}
- void adjustBrightness() {}
void doDeepSleep() {}
void forceDisplay() {}
void startBluetoothPinScreen(uint32_t pin) {}
@@ -161,7 +160,6 @@ class Screen : public concurrency::OSThread
void showNextFrame() { enqueueCmd(ScreenCmd{.cmd = Cmd::SHOW_NEXT_FRAME}); }
// Implementation to Adjust Brightness
- void adjustBrightness();
uint8_t brightness = BRIGHTNESS_DEFAULT;
/// Starts showing the Bluetooth PIN screen.
@@ -363,6 +361,9 @@ class Screen : public concurrency::OSThread
/// Try to start drawing ASAP
void setFastFramerate();
+ // Sets frame up for immediate drawing
+ void setFrameImmediateDraw(FrameCallback *drawFrames);
+
/// Called when debug screen is to be drawn, calls through to debugInfo.drawFrame.
static void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
diff --git a/src/graphics/TFTDisplay.cpp b/src/graphics/TFTDisplay.cpp
index 71ce35e82..5eec2b200 100644
--- a/src/graphics/TFTDisplay.cpp
+++ b/src/graphics/TFTDisplay.cpp
@@ -1,4 +1,5 @@
#include "configuration.h"
+#include "main.h"
#ifndef TFT_BACKLIGHT_ON
#define TFT_BACKLIGHT_ON HIGH
@@ -81,8 +82,16 @@ class LGFX : public lgfx::LGFX_Device
{
auto cfg = _light_instance.config(); // Gets a structure for backlight settings.
+#ifdef ST7735_BL_V03
+ if (heltec_version == 3) {
+ cfg.pin_bl = ST7735_BL_V03;
+ } else {
+ cfg.pin_bl = ST7735_BL_V05;
+ }
+#else
cfg.pin_bl = ST7735_BL; // Pin number to which the backlight is connected
- cfg.invert = true; // true to invert the brightness of the backlight
+#endif
+ cfg.invert = true; // true to invert the brightness of the backlight
// cfg.freq = 44100; // PWM frequency of backlight
// cfg.pwm_channel = 1; // PWM channel number to use
@@ -364,9 +373,23 @@ void TFTDisplay::sendCommand(uint8_t com)
// handle display on/off directly
switch (com) {
case DISPLAYON: {
+#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
+ if (heltec_version == 3) {
+ digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
+ } else {
+ digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
+ }
+#endif
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
#endif
+#ifdef VTFT_CTRL_V03
+ if (heltec_version == 3) {
+ digitalWrite(VTFT_CTRL_V03, LOW);
+ } else {
+ digitalWrite(VTFT_CTRL_V05, LOW);
+ }
+#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, LOW);
#endif
@@ -376,9 +399,23 @@ void TFTDisplay::sendCommand(uint8_t com)
break;
}
case DISPLAYOFF: {
+#if defined(ST7735_BACKLIGHT_EN_V03) && defined(TFT_BACKLIGHT_ON)
+ if (heltec_version == 3) {
+ digitalWrite(ST7735_BACKLIGHT_EN_V03, !TFT_BACKLIGHT_ON);
+ } else {
+ digitalWrite(ST7735_BACKLIGHT_EN_V05, !TFT_BACKLIGHT_ON);
+ }
+#endif
#if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
#endif
+#ifdef VTFT_CTRL_V03
+ if (heltec_version == 3) {
+ digitalWrite(VTFT_CTRL_V03, HIGH);
+ } else {
+ digitalWrite(VTFT_CTRL_V05, HIGH);
+ }
+#endif
#ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH);
#endif
@@ -436,6 +473,16 @@ bool TFTDisplay::connect()
pinMode(TFT_BL, OUTPUT);
#endif
+#ifdef ST7735_BACKLIGHT_EN_V03
+ if (heltec_version == 3) {
+ digitalWrite(ST7735_BACKLIGHT_EN_V03, TFT_BACKLIGHT_ON);
+ pinMode(ST7735_BACKLIGHT_EN_V03, OUTPUT);
+ } else {
+ digitalWrite(ST7735_BACKLIGHT_EN_V05, TFT_BACKLIGHT_ON);
+ pinMode(ST7735_BACKLIGHT_EN_V05, OUTPUT);
+ }
+#endif
+
tft.init();
#if defined(M5STACK)
tft.setRotation(0);
diff --git a/src/main.cpp b/src/main.cpp
index 1a42e6dda..6828bbcd1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -29,6 +29,7 @@
#include "target_specific.h"
#include
#include
+#include
// #include
#include "mesh/eth/ethClient.h"
@@ -122,9 +123,8 @@ uint32_t serialSinceMsec;
bool pmu_found;
-// Array map of sensor types (as array index) and i2c address as value we'll find in the i2c scan
-uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {
- 0}; // one is enough, missing elements will be initialized to 0 anyway.
+// Array map of sensor types with i2c address and wire as we'll find in the i2c scan
+std::pair nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1] = {};
Router *router = NULL; // Users of router don't care what sort of subclass implements that API
@@ -146,6 +146,25 @@ const char *getDeviceName()
return name;
}
+#ifdef VEXT_ENABLE_V03
+
+#include
+
+static uint32_t calibrate_one(rtc_cal_sel_t cal_clk, const char *name)
+{
+ const uint32_t cal_count = 1000;
+ uint32_t cali_val;
+ for (int i = 0; i < 5; ++i) {
+ cali_val = rtc_clk_cal(cal_clk, cal_count);
+ }
+ return cali_val;
+}
+
+int heltec_version = 3;
+
+#define CALIBRATE_ONE(cali_clk) calibrate_one(cali_clk, #cali_clk)
+#endif
+
static int32_t ledBlinker()
{
static bool ledOn;
@@ -216,11 +235,63 @@ void setup()
digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif
-#ifdef VEXT_ENABLE
+#ifdef ST7735_BL_V03 // Heltec Wireless Tracker PCB Change Detect/Hack
+
+ rtc_clk_32k_enable(true);
+ CALIBRATE_ONE(RTC_CAL_RTC_MUX);
+ if (CALIBRATE_ONE(RTC_CAL_32K_XTAL) != 0) {
+ rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
+ CALIBRATE_ONE(RTC_CAL_RTC_MUX);
+ CALIBRATE_ONE(RTC_CAL_32K_XTAL);
+ }
+
+ if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
+ heltec_version = 3;
+ } else {
+ heltec_version = 5;
+ }
+#endif
+
+#if defined(VEXT_ENABLE_V03)
+ if (heltec_version == 3) {
+ pinMode(VEXT_ENABLE_V03, OUTPUT);
+ digitalWrite(VEXT_ENABLE_V03, 0); // turn on the display power
+ LOG_DEBUG("HELTEC Detect Tracker V1.0\n");
+ } else {
+ pinMode(VEXT_ENABLE_V05, OUTPUT);
+ digitalWrite(VEXT_ENABLE_V05, 1); // turn on the display power
+ LOG_DEBUG("HELTEC Detect Tracker V1.1\n");
+ }
+#elif defined(VEXT_ENABLE)
pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, 0); // turn on the display power
#endif
+#if defined(VGNSS_CTRL_V03)
+ if (heltec_version == 3) {
+ pinMode(VGNSS_CTRL_V03, OUTPUT);
+ digitalWrite(VGNSS_CTRL_V03, LOW);
+ } else {
+ pinMode(VGNSS_CTRL_V05, OUTPUT);
+ digitalWrite(VGNSS_CTRL_V05, LOW);
+ }
+#endif
+
+#if defined(VTFT_CTRL_V03)
+ if (heltec_version == 3) {
+ pinMode(VTFT_CTRL_V03, OUTPUT);
+ digitalWrite(VTFT_CTRL_V03, LOW);
+ } else {
+ pinMode(VTFT_CTRL_V05, OUTPUT);
+ digitalWrite(VTFT_CTRL_V05, LOW);
+ }
+#endif
+
+#if defined(VGNSS_CTRL)
+ pinMode(VGNSS_CTRL, OUTPUT);
+ digitalWrite(VGNSS_CTRL, LOW);
+#endif
+
#if defined(VTFT_CTRL)
pinMode(VTFT_CTRL, OUTPUT);
digitalWrite(VTFT_CTRL, LOW);
@@ -420,7 +491,8 @@ void setup()
{ \
auto found = i2cScanner->find(SCANNER_T); \
if (found.type != ScanI2C::DeviceType::NONE) { \
- nodeTelemetrySensorsMap[PB_T] = found.address.address; \
+ nodeTelemetrySensorsMap[PB_T].first = found.address.address; \
+ nodeTelemetrySensorsMap[PB_T].second = i2cScanner->fetchI2CBus(found.address); \
LOG_DEBUG("found i2c sensor %s\n", STRING(PB_T)); \
} \
}
diff --git a/src/main.h b/src/main.h
index d7c9f8876..32e402a8c 100644
--- a/src/main.h
+++ b/src/main.h
@@ -64,6 +64,8 @@ extern uint32_t shutdownAtMsec;
extern uint32_t serialSinceMsec;
+extern int heltec_version;
+
// If a thread does something that might need for it to be rescheduled ASAP it can set this flag
// This will suppress the current delay and instead try to run ASAP.
extern bool runASAP;
diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp
index 2a0b5ee39..9974297fa 100644
--- a/src/mesh/Channels.cpp
+++ b/src/mesh/Channels.cpp
@@ -1,5 +1,6 @@
#include "Channels.h"
#include "CryptoEngine.h"
+#include "DisplayFormatters.h"
#include "NodeDB.h"
#include "configuration.h"
@@ -239,38 +240,9 @@ const char *Channels::getName(size_t chIndex)
const char *channelName = channelSettings.name;
if (!*channelName) { // emptystring
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
- // the app fucked up and forgot to set channelSettings.name
-
+ // the app effed up and forgot to set channelSettings.name
if (config.lora.use_preset) {
- switch (config.lora.modem_preset) {
- case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
- channelName = "ShortSlow";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
- channelName = "ShortFast";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
- channelName = "MediumSlow";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
- channelName = "MediumFast";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
- channelName = "LongSlow";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
- channelName = "LongFast";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
- channelName = "LongMod";
- break;
- case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
- channelName = "VLongSlow";
- break;
- default:
- channelName = "Invalid";
- break;
- }
+ channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
} else {
channelName = "Custom";
}
diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp
index fcb01cb36..7b2363106 100644
--- a/src/mesh/MeshService.cpp
+++ b/src/mesh/MeshService.cpp
@@ -267,14 +267,22 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
void MeshService::sendToPhone(meshtastic_MeshPacket *p)
{
+ perhapsDecode(p);
+
if (toPhoneQueue.numFree() == 0) {
- LOG_WARN("ToPhone queue is full, discarding oldest\n");
- meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
- if (d)
- releaseToPool(d);
+ if (p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP ||
+ p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) {
+ LOG_WARN("ToPhone queue is full, discarding oldest\n");
+ meshtastic_MeshPacket *d = toPhoneQueue.dequeuePtr(0);
+ if (d)
+ releaseToPool(d);
+ } else {
+ LOG_WARN("ToPhone queue is full, dropping packet.\n");
+ releaseToPool(p);
+ return;
+ }
}
- perhapsDecode(p);
assert(toPhoneQueue.enqueue(p, 0));
fromNum++;
}
@@ -335,7 +343,7 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *newStatus)
// Used fixed position if configured regalrdless of GPS lock
if (config.position.fixed_position) {
LOG_WARN("Using fixed position\n");
- pos = ConvertToPosition(node->position);
+ pos = TypeConversions::ConvertToPosition(node->position);
}
// Add a fresh timestamp
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index fb2e2bc98..8f4580a21 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -254,6 +254,8 @@ void NodeDB::installDefaultModuleConfig()
strncpy(moduleConfig.mqtt.address, default_mqtt_address, sizeof(moduleConfig.mqtt.address));
strncpy(moduleConfig.mqtt.username, default_mqtt_username, sizeof(moduleConfig.mqtt.username));
strncpy(moduleConfig.mqtt.password, default_mqtt_password, sizeof(moduleConfig.mqtt.password));
+ strncpy(moduleConfig.mqtt.root, default_mqtt_root, sizeof(moduleConfig.mqtt.root));
+ moduleConfig.mqtt.encryption_enabled = true;
moduleConfig.has_neighbor_info = true;
moduleConfig.neighbor_info.enabled = false;
@@ -285,6 +287,15 @@ void NodeDB::installRoleDefaults(meshtastic_Config_DeviceConfig_Role role)
} else if (role == meshtastic_Config_DeviceConfig_Role_SENSOR) {
moduleConfig.telemetry.environment_measurement_enabled = true;
moduleConfig.telemetry.environment_update_interval = 300;
+ } else if (role == meshtastic_Config_DeviceConfig_Role_TAK) {
+ config.device.node_info_broadcast_secs = ONE_DAY;
+ config.position.position_broadcast_smart_enabled = false;
+ config.position.position_broadcast_secs = ONE_DAY;
+ // Remove Altitude MSL from flags since CoTs use HAE (height above ellipsoid)
+ config.position.position_flags =
+ (meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE | meshtastic_Config_PositionConfig_PositionFlags_SPEED |
+ meshtastic_Config_PositionConfig_PositionFlags_HEADING | meshtastic_Config_PositionConfig_PositionFlags_DOP);
+ moduleConfig.telemetry.device_update_interval = ONE_DAY;
}
}
@@ -687,8 +698,8 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
LOG_INFO("updatePosition LOCAL pos@%x, time=%u, latI=%d, lonI=%d, alt=%d\n", p.timestamp, p.time, p.latitude_i,
p.longitude_i, p.altitude);
- info->position = ConvertToPositionLite(p);
- localPosition = p;
+ setLocalPosition(p);
+ info->position = TypeConversions::ConvertToPositionLite(p);
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) {
// FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900)
@@ -706,7 +717,7 @@ void NodeDB::updatePosition(uint32_t nodeId, const meshtastic_Position &p, RxSou
uint32_t tmp_time = info->position.time;
// Next, update atomically
- info->position = ConvertToPositionLite(p);
+ info->position = TypeConversions::ConvertToPositionLite(p);
// Last, restore any fields that may have been overwritten
if (!info->position.time)
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index 51c1b3043..5fca0e440 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -131,6 +131,13 @@ class NodeDB
meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
size_t getNumMeshNodes() { return *numMeshNodes; }
+ void setLocalPosition(meshtastic_Position position)
+ {
+ LOG_DEBUG("Setting local position: latitude=%i, longitude=%i, time=%i\n", position.latitude_i, position.longitude_i,
+ position.time);
+ localPosition = position;
+ }
+
private:
/// Find a node in our DB, create an empty NodeInfoLite if missing
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
@@ -192,11 +199,12 @@ extern NodeDB nodeDB;
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep
#define default_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)
#define default_min_wake_secs 10
-#define default_screen_on_secs 60 * 10
+#define default_screen_on_secs IF_ROUTER(1, 60 * 10)
#define default_mqtt_address "mqtt.meshtastic.org"
#define default_mqtt_username "meshdev"
#define default_mqtt_password "large4cats"
+#define default_mqtt_root "msh"
inline uint32_t getConfiguredOrDefaultMs(uint32_t configuredInterval)
{
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index 672c6871e..5abcc8a31 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -405,7 +405,7 @@ bool PhoneAPI::available()
if (nodeInfoForPhone.num == 0) {
auto nextNode = nodeDB.readNextMeshNode(readIndex);
if (nextNode) {
- nodeInfoForPhone = ConvertToNodeInfo(nextNode);
+ nodeInfoForPhone = TypeConversions::ConvertToNodeInfo(nextNode);
}
}
return true; // Always say we have something, because we might need to advance our state machine
diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp
index 03aa57351..b2d8d585d 100644
--- a/src/mesh/Router.cpp
+++ b/src/mesh/Router.cpp
@@ -249,29 +249,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it
- bool shouldActuallyEncrypt = true;
-
if (moduleConfig.mqtt.enabled) {
- // check if we should send decrypted packets to mqtt
- // truth table:
- /* mqtt_server mqtt_encryption_enabled should_encrypt
- * not set 0 1
- * not set 1 1
- * set 0 0
- * set 1 1
- *
- * => so we only decrypt mqtt if they have a custom mqtt server AND mqtt_encryption_enabled is FALSE
- */
-
- if (*moduleConfig.mqtt.address && !moduleConfig.mqtt.encryption_enabled) {
- shouldActuallyEncrypt = false;
- }
-
- LOG_INFO("Should encrypt MQTT?: %d\n", shouldActuallyEncrypt);
+ LOG_INFO("Should encrypt MQTT?: %d\n", moduleConfig.mqtt.encryption_enabled);
// the packet is currently in a decrypted state. send it now if they want decrypted packets
- if (mqtt && !shouldActuallyEncrypt)
+ if (mqtt && !moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex);
}
@@ -284,7 +267,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
if (moduleConfig.mqtt.enabled) {
// the packet is now encrypted.
// check if we should send encrypted packets to mqtt
- if (mqtt && shouldActuallyEncrypt)
+ if (mqtt && moduleConfig.mqtt.encryption_enabled)
mqtt->onSend(*p, chIndex);
}
}
diff --git a/src/mesh/TypeConversions.cpp b/src/mesh/TypeConversions.cpp
new file mode 100644
index 000000000..4e0fdd385
--- /dev/null
+++ b/src/mesh/TypeConversions.cpp
@@ -0,0 +1,55 @@
+#include "TypeConversions.h"
+#include "mesh/generated/meshtastic/deviceonly.pb.h"
+#include "mesh/generated/meshtastic/mesh.pb.h"
+
+meshtastic_NodeInfo TypeConversions::ConvertToNodeInfo(const meshtastic_NodeInfoLite *lite)
+{
+ meshtastic_NodeInfo info = meshtastic_NodeInfo_init_default;
+
+ info.num = lite->num;
+ info.snr = lite->snr;
+ info.last_heard = lite->last_heard;
+ info.channel = lite->channel;
+
+ if (lite->has_position) {
+ info.has_position = true;
+ info.position.latitude_i = lite->position.latitude_i;
+ info.position.longitude_i = lite->position.longitude_i;
+ info.position.altitude = lite->position.altitude;
+ info.position.location_source = lite->position.location_source;
+ info.position.time = lite->position.time;
+ }
+ if (lite->has_user) {
+ info.has_user = true;
+ info.user = lite->user;
+ }
+ if (lite->has_device_metrics) {
+ info.has_device_metrics = true;
+ info.device_metrics = lite->device_metrics;
+ }
+ return info;
+}
+
+meshtastic_PositionLite TypeConversions::ConvertToPositionLite(meshtastic_Position position)
+{
+ meshtastic_PositionLite lite = meshtastic_PositionLite_init_default;
+ lite.latitude_i = position.latitude_i;
+ lite.longitude_i = position.longitude_i;
+ lite.altitude = position.altitude;
+ lite.location_source = position.location_source;
+ lite.time = position.time;
+
+ return lite;
+}
+
+meshtastic_Position TypeConversions::ConvertToPosition(meshtastic_PositionLite lite)
+{
+ meshtastic_Position position = meshtastic_Position_init_default;
+ position.latitude_i = lite.latitude_i;
+ position.longitude_i = lite.longitude_i;
+ position.altitude = lite.altitude;
+ position.location_source = lite.location_source;
+ position.time = lite.time;
+
+ return position;
+}
\ No newline at end of file
diff --git a/src/mesh/TypeConversions.h b/src/mesh/TypeConversions.h
index bfc87102b..ffc3c12a7 100644
--- a/src/mesh/TypeConversions.h
+++ b/src/mesh/TypeConversions.h
@@ -1,54 +1,13 @@
#include "mesh/generated/meshtastic/deviceonly.pb.h"
#include "mesh/generated/meshtastic/mesh.pb.h"
-inline static meshtastic_NodeInfo ConvertToNodeInfo(const meshtastic_NodeInfoLite *lite)
+#pragma once
+#include "NodeDB.h"
+
+class TypeConversions
{
- meshtastic_NodeInfo info = meshtastic_NodeInfo_init_default;
-
- info.num = lite->num;
- info.snr = lite->snr;
- info.last_heard = lite->last_heard;
- info.channel = lite->channel;
-
- if (lite->has_position) {
- info.has_position = true;
- info.position.latitude_i = lite->position.latitude_i;
- info.position.longitude_i = lite->position.longitude_i;
- info.position.altitude = lite->position.altitude;
- info.position.location_source = lite->position.location_source;
- info.position.time = lite->position.time;
- }
- if (lite->has_user) {
- info.has_user = true;
- info.user = lite->user;
- }
- if (lite->has_device_metrics) {
- info.has_device_metrics = true;
- info.device_metrics = lite->device_metrics;
- }
- return info;
-}
-
-inline static meshtastic_PositionLite ConvertToPositionLite(meshtastic_Position position)
-{
- meshtastic_PositionLite lite = meshtastic_PositionLite_init_default;
- lite.latitude_i = position.latitude_i;
- lite.longitude_i = position.longitude_i;
- lite.altitude = position.altitude;
- lite.location_source = position.location_source;
- lite.time = position.time;
-
- return lite;
-}
-
-inline static meshtastic_Position ConvertToPosition(meshtastic_PositionLite lite)
-{
- meshtastic_Position position = meshtastic_Position_init_default;
- position.latitude_i = lite.latitude_i;
- position.longitude_i = lite.longitude_i;
- position.altitude = lite.altitude;
- position.location_source = lite.location_source;
- position.time = lite.time;
-
- return position;
-}
\ No newline at end of file
+ public:
+ static meshtastic_NodeInfo ConvertToNodeInfo(const meshtastic_NodeInfoLite *lite);
+ static meshtastic_PositionLite ConvertToPositionLite(meshtastic_Position position);
+ static meshtastic_Position ConvertToPosition(meshtastic_PositionLite lite);
+};
diff --git a/src/mesh/generated/meshtastic/config.pb.h b/src/mesh/generated/meshtastic/config.pb.h
index 4b8bef8a1..9dcc14940 100644
--- a/src/mesh/generated/meshtastic/config.pb.h
+++ b/src/mesh/generated/meshtastic/config.pb.h
@@ -30,11 +30,20 @@ typedef enum _meshtastic_Config_DeviceConfig_Role {
or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate. */
meshtastic_Config_DeviceConfig_Role_REPEATER = 4,
/* Tracker device role
- Position Mesh packets will be prioritized higher and sent more frequently by default. */
+ Position Mesh packets will be prioritized higher and sent more frequently by default.
+ When used in conjunction with power.is_power_saving = true, nodes will wake up,
+ send position, and then sleep for position.position_broadcast_secs seconds. */
meshtastic_Config_DeviceConfig_Role_TRACKER = 5,
/* Sensor device role
- Telemetry Mesh packets will be prioritized higher and sent more frequently by default. */
- meshtastic_Config_DeviceConfig_Role_SENSOR = 6
+ Telemetry Mesh packets will be prioritized higher and sent more frequently by default.
+ When used in conjunction with power.is_power_saving = true, nodes will wake up,
+ send environment telemetry, and then sleep for telemetry.environment_update_interval seconds. */
+ meshtastic_Config_DeviceConfig_Role_SENSOR = 6,
+ /* TAK device role
+ Used for nodes dedicated for connection to an ATAK EUD.
+ Turns off many of the routine broadcasts to favor CoT packet stream
+ from the Meshtastic ATAK plugin -> IMeshService -> Node */
+ meshtastic_Config_DeviceConfig_Role_TAK = 7
} meshtastic_Config_DeviceConfig_Role;
/* Defines the device's behavior for how messages are rebroadcast */
@@ -470,8 +479,8 @@ extern "C" {
/* Helper constants for enums */
#define _meshtastic_Config_DeviceConfig_Role_MIN meshtastic_Config_DeviceConfig_Role_CLIENT
-#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_SENSOR
-#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_SENSOR+1))
+#define _meshtastic_Config_DeviceConfig_Role_MAX meshtastic_Config_DeviceConfig_Role_TAK
+#define _meshtastic_Config_DeviceConfig_Role_ARRAYSIZE ((meshtastic_Config_DeviceConfig_Role)(meshtastic_Config_DeviceConfig_Role_TAK+1))
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MIN meshtastic_Config_DeviceConfig_RebroadcastMode_ALL
#define _meshtastic_Config_DeviceConfig_RebroadcastMode_MAX meshtastic_Config_DeviceConfig_RebroadcastMode_LOCAL_ONLY
diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h
index c32f55aab..dfaf693fc 100644
--- a/src/mesh/generated/meshtastic/mesh.pb.h
+++ b/src/mesh/generated/meshtastic/mesh.pb.h
@@ -113,6 +113,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_PICOMPUTER_S3 = 52,
/* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */
meshtastic_HardwareModel_HELTEC_HT62 = 53,
+ /* EBYTE SPI LoRa module and ESP32-S3 */
+ meshtastic_HardwareModel_EBYTE_ESP32_S3 = 54,
/* ------------------------------------------------------------------------------------------------------------------------------------------
Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
------------------------------------------------------------------------------------------------------------------------------------------ */
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index 27b539f38..f25e8db33 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -676,7 +676,7 @@ void AdminModule::handleSetHamMode(const meshtastic_HamParameters &p)
channels.onConfigChanged();
service.reloadOwner(false);
- service.reloadConfig(SEGMENT_CONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
+ saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE | SEGMENT_CHANNELS);
}
AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_APP, &meshtastic_AdminMessage_msg)
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index 1780a8528..4c3d7eb61 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -88,7 +88,7 @@ void setupModules()
#endif
#if HAS_SENSOR
new EnvironmentTelemetryModule();
- if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I] > 0) {
+ if (nodeTelemetrySensorsMap[meshtastic_TelemetrySensorType_PMSA003I].first > 0) {
new AirQualityTelemetryModule();
}
#endif
diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp
index 09819dab1..855ba9cde 100644
--- a/src/modules/NodeInfoModule.cpp
+++ b/src/modules/NodeInfoModule.cpp
@@ -40,7 +40,9 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
meshtastic_MeshPacket *p = allocReply();
if (p) { // Check whether we didn't ignore it
p->to = dest;
- p->decoded.want_response = wantReplies;
+ p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
+ config.device.role != meshtastic_Config_DeviceConfig_Role_SENSOR) &&
+ wantReplies;
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
if (channel > 0) {
LOG_DEBUG("sending ourNodeInfo to channel %d\n", channel);
diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp
index 39e467cda..69cd4848e 100644
--- a/src/modules/PositionModule.cpp
+++ b/src/modules/PositionModule.cpp
@@ -1,4 +1,5 @@
#include "PositionModule.h"
+#include "GPS.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "RTC.h"
@@ -7,6 +8,8 @@
#include "airtime.h"
#include "configuration.h"
#include "gps/GeoCoord.h"
+#include "sleep.h"
+#include "target_specific.h"
PositionModule *positionModule;
@@ -14,8 +17,25 @@ PositionModule::PositionModule()
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg),
concurrency::OSThread("PositionModule")
{
- isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
- setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
+ isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
+ if (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)
+ setIntervalFromNow(60 * 1000);
+
+ // Power saving trackers should clear their position on startup to avoid waking up and sending a stale position
+ if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving) {
+ clearPosition();
+ }
+}
+
+void PositionModule::clearPosition()
+{
+ LOG_DEBUG("Clearing position on startup for sleepy tracker (ー。ー) zzz\n");
+ meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
+ node->position.latitude_i = 0;
+ node->position.longitude_i = 0;
+ node->position.altitude = 0;
+ node->position.time = 0;
+ nodeDB.setLocalPosition(meshtastic_Position_init_default);
}
bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *pptr)
@@ -27,10 +47,11 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
+ bool isLocal = false;
if (nodeDB.getNodeNum() == getFrom(&mp)) {
LOG_DEBUG("Incoming update from MYSELF\n");
- // LOG_DEBUG("Ignored an incoming update from MYSELF\n");
- // return false;
+ isLocal = true;
+ nodeDB.setLocalPosition(p);
}
// Log packet size and data fields
@@ -47,7 +68,8 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
tv.tv_sec = secs;
tv.tv_usec = 0;
- perhapsSetRTC(RTCQualityFromNet, &tv);
+ // Set from phone RTC Quality to RTCQualityNTP since it should be approximately so
+ perhapsSetRTC(isLocal ? RTCQualityNTP : RTCQualityFromNet, &tv);
}
nodeDB.updatePosition(getFrom(&mp), p);
@@ -77,8 +99,9 @@ meshtastic_MeshPacket *PositionModule::allocReply()
// Populate a Position struct with ONLY the requested fields
meshtastic_Position p = meshtastic_Position_init_default; // Start with an empty structure
+ // if localPosition is totally empty, put our last saved position (lite) in there
if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0) {
- localPosition = ConvertToPosition(node->position);
+ nodeDB.setLocalPosition(TypeConversions::ConvertToPosition(node->position));
}
localPosition.seq_number++;
@@ -148,7 +171,7 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
}
p->to = dest;
- p->decoded.want_response = wantReplies;
+ p->decoded.want_response = config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ? false : wantReplies;
if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER)
p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
else
@@ -159,70 +182,83 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
p->channel = channel;
service.sendToMesh(p, RX_SRC_LOCAL, true);
+
+ if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER && config.power.is_power_saving) {
+ LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n");
+ sleepOnNextExecution = true;
+ setIntervalFromNow(5000);
+ }
}
+#define RUNONCE_INTERVAL 5000;
+
int32_t PositionModule::runOnce()
{
+ if (sleepOnNextExecution == true) {
+ sleepOnNextExecution = false;
+ uint32_t nightyNightMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs);
+ LOG_DEBUG("Sleeping for %ims, then awaking to send position again.\n", nightyNightMs);
+ doDeepSleep(nightyNightMs, false);
+ }
+
meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
// We limit our GPS broadcasts to a max rate
uint32_t now = millis();
uint32_t intervalMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs);
uint32_t msSinceLastSend = now - lastGpsSend;
+ // Only send packets if the channel util. is less than 25% utilized or we're a tracker with less than 40% utilized.
+ if (!airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) {
+ return RUNONCE_INTERVAL;
+ }
if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
- // Only send packets if the channel is less than 40% utilized.
- if (airTime->isTxAllowedChannelUtil()) {
- if (hasValidPosition(node)) {
- lastGpsSend = now;
+ if (hasValidPosition(node)) {
+ lastGpsSend = now;
- lastGpsLatitude = node->position.latitude_i;
- lastGpsLongitude = node->position.longitude_i;
+ lastGpsLatitude = node->position.latitude_i;
+ lastGpsLongitude = node->position.longitude_i;
- // If we changed channels, ask everyone else for their latest info
+ // If we changed channels, ask everyone else for their latest info
+ bool requestReplies = currentGeneration != radioGeneration;
+ currentGeneration = radioGeneration;
+
+ LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies);
+ sendOurPosition(NODENUM_BROADCAST, requestReplies);
+ }
+ } else if (config.position.position_broadcast_smart_enabled) {
+ const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
+
+ if (hasValidPosition(node2)) {
+ // The minimum time (in seconds) that would pass before we are able to send a new position packet.
+ const uint32_t minimumTimeThreshold =
+ getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
+
+ auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
+
+ if (smartPosition.hasTraveledOverThreshold && msSinceLastSend >= minimumTimeThreshold) {
bool requestReplies = currentGeneration != radioGeneration;
currentGeneration = radioGeneration;
- LOG_INFO("Sending pos@%x:6 to mesh (wantReplies=%d)\n", localPosition.timestamp, requestReplies);
+ LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, "
+ "minTimeInterval=%ims)\n",
+ localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold,
+ msSinceLastSend, minimumTimeThreshold);
sendOurPosition(NODENUM_BROADCAST, requestReplies);
- }
- }
- } else if (config.position.position_broadcast_smart_enabled) {
- // Only send packets if the channel is less than 25% utilized or we're a tracker.
- if (airTime->isTxAllowedChannelUtil(config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER)) {
- const meshtastic_NodeInfoLite *node2 = service.refreshLocalMeshNode(); // should guarantee there is now a position
- if (hasValidPosition(node2)) {
- // The minimum time (in seconds) that would pass before we are able to send a new position packet.
- const uint32_t minimumTimeThreshold =
- getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
+ // Set the current coords as our last ones, after we've compared distance with current and decided to send
+ lastGpsLatitude = node->position.latitude_i;
+ lastGpsLongitude = node->position.longitude_i;
- auto smartPosition = getDistanceTraveledSinceLastSend(node->position);
-
- if (smartPosition.hasTraveledOverThreshold && msSinceLastSend >= minimumTimeThreshold) {
- bool requestReplies = currentGeneration != radioGeneration;
- currentGeneration = radioGeneration;
-
- LOG_INFO("Sending smart pos@%x:6 to mesh (distanceTraveled=%fm, minDistanceThreshold=%im, timeElapsed=%ims, "
- "minTimeInterval=%ims)\n",
- localPosition.timestamp, smartPosition.distanceTraveled, smartPosition.distanceThreshold,
- msSinceLastSend, minimumTimeThreshold);
- sendOurPosition(NODENUM_BROADCAST, requestReplies);
-
- // Set the current coords as our last ones, after we've compared distance with current and decided to send
- lastGpsLatitude = node->position.latitude_i;
- lastGpsLongitude = node->position.longitude_i;
-
- /* Update lastGpsSend to now. This means if the device is stationary, then
- getPref_position_broadcast_secs will still apply.
- */
- lastGpsSend = now;
- }
+ /* Update lastGpsSend to now. This means if the device is stationary, then
+ getPref_position_broadcast_secs will still apply.
+ */
+ lastGpsSend = now;
}
}
}
- return 5000; // to save power only wake for our callback occasionally
+ return RUNONCE_INTERVAL; // to save power only wake for our callback occasionally
}
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
@@ -234,6 +270,23 @@ struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic
float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7);
+#ifdef GPS_EXTRAVERBOSE
+ LOG_DEBUG("--------LAST POSITION------------------------------------\n");
+ LOG_DEBUG("lastGpsLatitude=%i, lastGpsLatitude=%i\n", lastGpsLatitude, lastGpsLongitude);
+
+ LOG_DEBUG("--------CURRENT POSITION---------------------------------\n");
+ LOG_DEBUG("currentPosition.latitude_i=%i, currentPosition.longitude_i=%i\n", lastGpsLatitude, lastGpsLongitude);
+
+ LOG_DEBUG("--------SMART POSITION-----------------------------------\n");
+ LOG_DEBUG("hasTraveledOverThreshold=%i, distanceTraveled=%d, distanceThreshold=% u\n",
+ abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold, abs(distanceTraveledSinceLastSend),
+ distanceTravelThreshold);
+
+ if (abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold) {
+ LOG_DEBUG("\n\n\nSMART SEEEEEEEEENDING\n\n\n");
+ }
+#endif
+
return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend),
.distanceThreshold = distanceTravelThreshold,
.hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};
diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h
index 3114f31e1..1b7eca800 100644
--- a/src/modules/PositionModule.h
+++ b/src/modules/PositionModule.h
@@ -49,6 +49,9 @@ class PositionModule : public ProtobufModule, private concu
private:
struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition);
+
+ /** Only used in power saving trackers for now */
+ void clearPosition();
};
struct SmartPosition {
@@ -57,4 +60,4 @@ struct SmartPosition {
bool hasTraveledOverThreshold;
};
-extern PositionModule *positionModule;
+extern PositionModule *positionModule;
\ No newline at end of file
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 1f1a0cbf9..1047ade1d 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -8,6 +8,8 @@
#include "configuration.h"
#include "main.h"
#include "power.h"
+#include "sleep.h"
+#include "target_specific.h"
#include
#include
@@ -51,6 +53,13 @@ SHT31Sensor sht31Sensor;
int32_t EnvironmentTelemetryModule::runOnce()
{
+ if (sleepOnNextExecution == true) {
+ sleepOnNextExecution = false;
+ uint32_t nightyNightMs = getConfiguredOrDefaultMs(moduleConfig.telemetry.environment_update_interval);
+ LOG_DEBUG("Sleeping for %ims, then awaking to send metrics again.\n", nightyNightMs);
+ doDeepSleep(nightyNightMs, true);
+ }
+
uint32_t result = UINT32_MAX;
/*
Uncomment the preferences below if you want to use the module
@@ -266,6 +275,12 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
} else {
LOG_INFO("Sending packet to mesh\n");
service.sendToMesh(p, RX_SRC_LOCAL, true);
+
+ if (config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR && config.power.is_power_saving) {
+ LOG_DEBUG("Starting next execution in 5 seconds and then going to sleep.\n");
+ sleepOnNextExecution = true;
+ setIntervalFromNow(5000);
+ }
}
}
return valid;
diff --git a/src/modules/Telemetry/Sensor/BME280Sensor.cpp b/src/modules/Telemetry/Sensor/BME280Sensor.cpp
index 7bc65a418..a30614123 100644
--- a/src/modules/Telemetry/Sensor/BME280Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/BME280Sensor.cpp
@@ -13,7 +13,7 @@ int32_t BME280Sensor::runOnce()
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
- status = bme280.begin(nodeTelemetrySensorsMap[sensorType]);
+ status = bme280.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
bme280.setSampling(Adafruit_BME280::MODE_FORCED,
Adafruit_BME280::SAMPLING_X1, // Temp. oversampling
diff --git a/src/modules/Telemetry/Sensor/BME280Sensor.h b/src/modules/Telemetry/Sensor/BME280Sensor.h
index 780dcdb61..2034c0a82 100644
--- a/src/modules/Telemetry/Sensor/BME280Sensor.h
+++ b/src/modules/Telemetry/Sensor/BME280Sensor.h
@@ -2,7 +2,7 @@
#include "TelemetrySensor.h"
#include
-class BME280Sensor : virtual public TelemetrySensor
+class BME280Sensor : public TelemetrySensor
{
private:
Adafruit_BME280 bme280;
diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.cpp b/src/modules/Telemetry/Sensor/BME680Sensor.cpp
index 5b32645e6..323dce31f 100644
--- a/src/modules/Telemetry/Sensor/BME680Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/BME680Sensor.cpp
@@ -20,7 +20,7 @@ int32_t BME680Sensor::runOnce()
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
- if (!bme680.begin(nodeTelemetrySensorsMap[sensorType], Wire))
+ if (!bme680.begin(nodeTelemetrySensorsMap[sensorType].first, *nodeTelemetrySensorsMap[sensorType].second))
checkStatus("begin");
if (bme680.status == BSEC_OK) {
diff --git a/src/modules/Telemetry/Sensor/BME680Sensor.h b/src/modules/Telemetry/Sensor/BME680Sensor.h
index 06e24b1a9..4b7f84cf0 100644
--- a/src/modules/Telemetry/Sensor/BME680Sensor.h
+++ b/src/modules/Telemetry/Sensor/BME680Sensor.h
@@ -6,7 +6,7 @@
#include "bme680_iaq_33v_3s_4d/bsec_iaq.h"
-class BME680Sensor : virtual public TelemetrySensor
+class BME680Sensor : public TelemetrySensor
{
private:
Bsec2 bme680;
diff --git a/src/modules/Telemetry/Sensor/BMP280Sensor.cpp b/src/modules/Telemetry/Sensor/BMP280Sensor.cpp
index c0b5625de..408532388 100644
--- a/src/modules/Telemetry/Sensor/BMP280Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/BMP280Sensor.cpp
@@ -13,7 +13,8 @@ int32_t BMP280Sensor::runOnce()
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
- status = bmp280.begin(nodeTelemetrySensorsMap[sensorType]);
+ bmp280 = Adafruit_BMP280(nodeTelemetrySensorsMap[sensorType].second);
+ status = bmp280.begin(nodeTelemetrySensorsMap[sensorType].first);
bmp280.setSampling(Adafruit_BMP280::MODE_FORCED,
Adafruit_BMP280::SAMPLING_X1, // Temp. oversampling
diff --git a/src/modules/Telemetry/Sensor/BMP280Sensor.h b/src/modules/Telemetry/Sensor/BMP280Sensor.h
index cc8c0b9da..48581df8f 100644
--- a/src/modules/Telemetry/Sensor/BMP280Sensor.h
+++ b/src/modules/Telemetry/Sensor/BMP280Sensor.h
@@ -2,7 +2,7 @@
#include "TelemetrySensor.h"
#include
-class BMP280Sensor : virtual public TelemetrySensor
+class BMP280Sensor : public TelemetrySensor
{
private:
Adafruit_BMP280 bmp280;
diff --git a/src/modules/Telemetry/Sensor/INA219Sensor.cpp b/src/modules/Telemetry/Sensor/INA219Sensor.cpp
index 1dd7f7f2c..5a1faa99f 100644
--- a/src/modules/Telemetry/Sensor/INA219Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/INA219Sensor.cpp
@@ -13,8 +13,8 @@ int32_t INA219Sensor::runOnce()
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
if (!ina219.success()) {
- ina219 = Adafruit_INA219(nodeTelemetrySensorsMap[sensorType]);
- status = ina219.begin();
+ ina219 = Adafruit_INA219(nodeTelemetrySensorsMap[sensorType].first);
+ status = ina219.begin(nodeTelemetrySensorsMap[sensorType].second);
} else {
status = ina219.success();
}
diff --git a/src/modules/Telemetry/Sensor/INA219Sensor.h b/src/modules/Telemetry/Sensor/INA219Sensor.h
index f11a571cc..76f4613db 100644
--- a/src/modules/Telemetry/Sensor/INA219Sensor.h
+++ b/src/modules/Telemetry/Sensor/INA219Sensor.h
@@ -3,7 +3,7 @@
#include "VoltageSensor.h"
#include
-class INA219Sensor : virtual public TelemetrySensor, VoltageSensor
+class INA219Sensor : public TelemetrySensor, VoltageSensor
{
private:
Adafruit_INA219 ina219;
diff --git a/src/modules/Telemetry/Sensor/INA260Sensor.cpp b/src/modules/Telemetry/Sensor/INA260Sensor.cpp
index 034fecca0..89b7580d2 100644
--- a/src/modules/Telemetry/Sensor/INA260Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/INA260Sensor.cpp
@@ -14,7 +14,7 @@ int32_t INA260Sensor::runOnce()
}
if (!status) {
- status = ina260.begin(nodeTelemetrySensorsMap[sensorType]);
+ status = ina260.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
}
return initI2CSensor();
}
diff --git a/src/modules/Telemetry/Sensor/INA260Sensor.h b/src/modules/Telemetry/Sensor/INA260Sensor.h
index 8ea532697..28e8944bf 100644
--- a/src/modules/Telemetry/Sensor/INA260Sensor.h
+++ b/src/modules/Telemetry/Sensor/INA260Sensor.h
@@ -3,7 +3,7 @@
#include "VoltageSensor.h"
#include
-class INA260Sensor : virtual public TelemetrySensor, VoltageSensor
+class INA260Sensor : public TelemetrySensor, VoltageSensor
{
private:
Adafruit_INA260 ina260 = Adafruit_INA260();
diff --git a/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp b/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp
index 05f940656..6e30113cd 100644
--- a/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp
+++ b/src/modules/Telemetry/Sensor/LPS22HBSensor.cpp
@@ -13,7 +13,7 @@ int32_t LPS22HBSensor::runOnce()
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
- status = lps22hb.begin_I2C(nodeTelemetrySensorsMap[sensorType]);
+ status = lps22hb.begin_I2C(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
return initI2CSensor();
}
diff --git a/src/modules/Telemetry/Sensor/LPS22HBSensor.h b/src/modules/Telemetry/Sensor/LPS22HBSensor.h
index 556d161c4..5b86539b1 100644
--- a/src/modules/Telemetry/Sensor/LPS22HBSensor.h
+++ b/src/modules/Telemetry/Sensor/LPS22HBSensor.h
@@ -3,7 +3,7 @@
#include
#include
-class LPS22HBSensor : virtual public TelemetrySensor
+class LPS22HBSensor : public TelemetrySensor
{
private:
Adafruit_LPS22 lps22hb;
diff --git a/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp b/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp
index 28db3d8a9..c1d9bfa71 100644
--- a/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp
+++ b/src/modules/Telemetry/Sensor/MCP9808Sensor.cpp
@@ -12,7 +12,7 @@ int32_t MCP9808Sensor::runOnce()
if (!hasSensor()) {
return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS;
}
- status = mcp9808.begin(nodeTelemetrySensorsMap[sensorType]);
+ status = mcp9808.begin(nodeTelemetrySensorsMap[sensorType].first, nodeTelemetrySensorsMap[sensorType].second);
return initI2CSensor();
}
diff --git a/src/modules/Telemetry/Sensor/MCP9808Sensor.h b/src/modules/Telemetry/Sensor/MCP9808Sensor.h
index b70707477..c1029f8a7 100644
--- a/src/modules/Telemetry/Sensor/MCP9808Sensor.h
+++ b/src/modules/Telemetry/Sensor/MCP9808Sensor.h
@@ -2,7 +2,7 @@
#include "TelemetrySensor.h"
#include
-class MCP9808Sensor : virtual public TelemetrySensor
+class MCP9808Sensor : public TelemetrySensor
{
private:
Adafruit_MCP9808 mcp9808;
diff --git a/src/modules/Telemetry/Sensor/SHT31Sensor.h b/src/modules/Telemetry/Sensor/SHT31Sensor.h
index 60354aaea..940361325 100644
--- a/src/modules/Telemetry/Sensor/SHT31Sensor.h
+++ b/src/modules/Telemetry/Sensor/SHT31Sensor.h
@@ -2,7 +2,7 @@
#include "TelemetrySensor.h"
#include
-class SHT31Sensor : virtual public TelemetrySensor
+class SHT31Sensor : public TelemetrySensor
{
private:
Adafruit_SHT31 sht31 = Adafruit_SHT31();
diff --git a/src/modules/Telemetry/Sensor/SHTC3Sensor.h b/src/modules/Telemetry/Sensor/SHTC3Sensor.h
index c67047396..e5db417f5 100644
--- a/src/modules/Telemetry/Sensor/SHTC3Sensor.h
+++ b/src/modules/Telemetry/Sensor/SHTC3Sensor.h
@@ -2,7 +2,7 @@
#include "TelemetrySensor.h"
#include
-class SHTC3Sensor : virtual public TelemetrySensor
+class SHTC3Sensor : public TelemetrySensor
{
private:
Adafruit_SHTC3 shtc3 = Adafruit_SHTC3();
diff --git a/src/modules/Telemetry/Sensor/TelemetrySensor.h b/src/modules/Telemetry/Sensor/TelemetrySensor.h
index dec81e061..7282e6dfa 100644
--- a/src/modules/Telemetry/Sensor/TelemetrySensor.h
+++ b/src/modules/Telemetry/Sensor/TelemetrySensor.h
@@ -1,9 +1,12 @@
#pragma once
#include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "NodeDB.h"
+#include
+
+class TwoWire;
#define DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000
-extern uint8_t nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
+extern std::pair nodeTelemetrySensorsMap[_meshtastic_TelemetrySensorType_MAX + 1];
class TelemetrySensor
{
@@ -16,7 +19,7 @@ class TelemetrySensor
}
const char *sensorName;
- meshtastic_TelemetrySensorType sensorType;
+ meshtastic_TelemetrySensorType sensorType = meshtastic_TelemetrySensorType_SENSOR_UNSET;
unsigned status;
bool initialized = false;
@@ -24,9 +27,9 @@ class TelemetrySensor
{
if (!status) {
LOG_WARN("Could not connect to detected %s sensor.\n Removing from nodeTelemetrySensorsMap.\n", sensorName);
- nodeTelemetrySensorsMap[sensorType] = 0;
+ nodeTelemetrySensorsMap[sensorType].first = 0;
} else {
- LOG_INFO("Opened %s sensor on default i2c bus\n", sensorName);
+ LOG_INFO("Opened %s sensor on i2c bus\n", sensorName);
setup();
}
initialized = true;
@@ -35,7 +38,7 @@ class TelemetrySensor
virtual void setup();
public:
- bool hasSensor() { return sensorType < sizeof(nodeTelemetrySensorsMap) && nodeTelemetrySensorsMap[sensorType] > 0; }
+ bool hasSensor() { return nodeTelemetrySensorsMap[sensorType].first > 0; }
virtual int32_t runOnce() = 0;
virtual bool isInitialized() { return initialized; }
diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp
index 791a4194b..a9e80c947 100644
--- a/src/mqtt/MQTT.cpp
+++ b/src/mqtt/MQTT.cpp
@@ -133,10 +133,16 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length)
if (strcmp(e.gateway_id, owner.id) == 0)
LOG_INFO("Ignoring downlink message we originally sent.\n");
else {
- if (e.packet) {
+ // Find channel by channel_id and check downlink_enabled
+ meshtastic_Channel ch = channels.getByName(e.channel_id);
+ if (strcmp(e.channel_id, channels.getGlobalId(ch.index)) == 0 && e.packet && ch.settings.downlink_enabled) {
LOG_INFO("Received MQTT topic %s, len=%u\n", topic, length);
meshtastic_MeshPacket *p = packetPool.allocCopy(*e.packet);
+ if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ p->channel = ch.index;
+ }
+
// ignore messages sent by us or if we don't have the channel key
if (router && p->from != nodeDB.getNodeNum() && perhapsDecode(p))
router->enqueueReceivedMessage(p);
@@ -516,34 +522,34 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
JSONObject msgPayload;
JSONObject jsonObj;
- switch (mp->decoded.portnum) {
- case meshtastic_PortNum_TEXT_MESSAGE_APP: {
- msgType = "text";
- // convert bytes to string
- LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size);
- char payloadStr[(mp->decoded.payload.size) + 1];
- memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
- payloadStr[mp->decoded.payload.size] = 0; // null terminated string
- // check if this is a JSON payload
- JSONValue *json_value = JSON::Parse(payloadStr);
- if (json_value != NULL) {
- LOG_INFO("text message payload is of type json\n");
- // if it is, then we can just use the json object
- jsonObj["payload"] = json_value;
- } else {
- // if it isn't, then we need to create a json object
- // with the string as the value
- LOG_INFO("text message payload is of type plaintext\n");
- msgPayload["text"] = new JSONValue(payloadStr);
- jsonObj["payload"] = new JSONValue(msgPayload);
+ if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ switch (mp->decoded.portnum) {
+ case meshtastic_PortNum_TEXT_MESSAGE_APP: {
+ msgType = "text";
+ // convert bytes to string
+ LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size);
+ char payloadStr[(mp->decoded.payload.size) + 1];
+ memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
+ payloadStr[mp->decoded.payload.size] = 0; // null terminated string
+ // check if this is a JSON payload
+ JSONValue *json_value = JSON::Parse(payloadStr);
+ if (json_value != NULL) {
+ LOG_INFO("text message payload is of type json\n");
+ // if it is, then we can just use the json object
+ jsonObj["payload"] = json_value;
+ } else {
+ // if it isn't, then we need to create a json object
+ // with the string as the value
+ LOG_INFO("text message payload is of type plaintext\n");
+ msgPayload["text"] = new JSONValue(payloadStr);
+ jsonObj["payload"] = new JSONValue(msgPayload);
+ }
+ break;
}
- break;
- }
- case meshtastic_PortNum_TELEMETRY_APP: {
- msgType = "telemetry";
- meshtastic_Telemetry scratch;
- meshtastic_Telemetry *decoded = NULL;
- if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ case meshtastic_PortNum_TELEMETRY_APP: {
+ msgType = "telemetry";
+ meshtastic_Telemetry scratch;
+ meshtastic_Telemetry *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
decoded = &scratch;
@@ -564,14 +570,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else {
LOG_ERROR("Error decoding protobuf for telemetry message!\n");
}
- };
- break;
- }
- case meshtastic_PortNum_NODEINFO_APP: {
- msgType = "nodeinfo";
- meshtastic_User scratch;
- meshtastic_User *decoded = NULL;
- if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ break;
+ }
+ case meshtastic_PortNum_NODEINFO_APP: {
+ msgType = "nodeinfo";
+ meshtastic_User scratch;
+ meshtastic_User *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
decoded = &scratch;
@@ -583,14 +587,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else {
LOG_ERROR("Error decoding protobuf for nodeinfo message!\n");
}
- };
- break;
- }
- case meshtastic_PortNum_POSITION_APP: {
- msgType = "position";
- meshtastic_Position scratch;
- meshtastic_Position *decoded = NULL;
- if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ break;
+ }
+ case meshtastic_PortNum_POSITION_APP: {
+ msgType = "position";
+ meshtastic_Position scratch;
+ meshtastic_Position *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
decoded = &scratch;
@@ -627,15 +629,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else {
LOG_ERROR("Error decoding protobuf for position message!\n");
}
- };
- break;
- }
-
- case meshtastic_PortNum_WAYPOINT_APP: {
- msgType = "position";
- meshtastic_Waypoint scratch;
- meshtastic_Waypoint *decoded = NULL;
- if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ break;
+ }
+ case meshtastic_PortNum_WAYPOINT_APP: {
+ msgType = "position";
+ meshtastic_Waypoint scratch;
+ meshtastic_Waypoint *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
decoded = &scratch;
@@ -650,14 +649,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else {
LOG_ERROR("Error decoding protobuf for position message!\n");
}
- };
- break;
- }
- case meshtastic_PortNum_NEIGHBORINFO_APP: {
- msgType = "neighborinfo";
- meshtastic_NeighborInfo scratch;
- meshtastic_NeighborInfo *decoded = NULL;
- if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
+ break;
+ }
+ case meshtastic_PortNum_NEIGHBORINFO_APP: {
+ msgType = "neighborinfo";
+ meshtastic_NeighborInfo scratch;
+ meshtastic_NeighborInfo *decoded = NULL;
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
&scratch)) {
@@ -678,12 +675,14 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else {
LOG_ERROR("Error decoding protobuf for neighborinfo message!\n");
}
- };
- break;
- }
- // add more packet types here if needed
- default:
- break;
+ break;
+ }
+ // add more packet types here if needed
+ default:
+ break;
+ }
+ } else {
+ LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n");
}
jsonObj["id"] = new JSONValue((uint)mp->id);
@@ -693,6 +692,10 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
jsonObj["channel"] = new JSONValue((uint)mp->channel);
jsonObj["type"] = new JSONValue(msgType.c_str());
jsonObj["sender"] = new JSONValue(owner.id);
+ if (mp->rx_rssi != 0)
+ jsonObj["rssi"] = new JSONValue((int)mp->rx_rssi);
+ if (mp->rx_snr != 0)
+ jsonObj["snr"] = new JSONValue((float)mp->rx_snr);
// serialize and write it to the stream
JSONValue *value = new JSONValue(jsonObj);
diff --git a/src/platform/esp32/main-esp32.cpp b/src/platform/esp32/main-esp32.cpp
index 17a312664..833e058d8 100644
--- a/src/platform/esp32/main-esp32.cpp
+++ b/src/platform/esp32/main-esp32.cpp
@@ -193,16 +193,12 @@ void cpuDeepSleep(uint32_t msecToWake)
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
#endif
- // FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
- // to detect wake and in normal operation the external part drives them hard.
-
- // We want RTC peripherals to stay on
- esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
-
+ // FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using
+ // to detect wake and in normal operation the external part drives them hard.
#ifdef BUTTON_PIN
- // Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
+ // Only GPIOs which are have RTC functionality can be used in this bit map: 0,2,4,12-15,25-27,32-39.
#if SOC_RTCIO_HOLD_SUPPORTED
- uint64_t gpioMask = (1ULL << config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN);
+ uint64_t gpioMask = (1ULL << (config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
#endif
#ifdef BUTTON_NEED_PULLUP
@@ -218,6 +214,9 @@ void cpuDeepSleep(uint32_t msecToWake)
#endif
#endif
+ // We want RTC peripherals to stay on
+ esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
+
esp_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
esp_deep_sleep_start(); // TBD mA sleep current (battery)
}
\ No newline at end of file
diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h
index 904ab908d..e6eebc45b 100644
--- a/src/platform/nrf52/architecture.h
+++ b/src/platform/nrf52/architecture.h
@@ -46,6 +46,8 @@
#define HW_VENDOR meshtastic_HardwareModel_RAK4631
#elif defined(TTGO_T_ECHO)
#define HW_VENDOR meshtastic_HardwareModel_T_ECHO
+#elif defined(NANO_G2_ULTRA)
+#define HW_VENDOR meshtastic_HardwareModel_NANO_G2_ULTRA
#elif defined(NORDIC_PCA10059)
#define HW_VENDOR meshtastic_HardwareModel_NRF52840_PCA10059
#elif defined(PRIVATE_HW) || defined(FEATHER_DIY)
diff --git a/src/platform/nrf52/main-nrf52.cpp b/src/platform/nrf52/main-nrf52.cpp
index fd6fe2cc2..65b45f1e9 100644
--- a/src/platform/nrf52/main-nrf52.cpp
+++ b/src/platform/nrf52/main-nrf52.cpp
@@ -180,14 +180,24 @@ void cpuDeepSleep(uint32_t msecToWake)
digitalWrite(AQ_SET_PIN, LOW);
#endif
#endif
- // FIXME, use system off mode with ram retention for key state?
- // FIXME, use non-init RAM per
- // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
-
- auto ok = sd_power_system_off();
- if (ok != NRF_SUCCESS) {
- LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n");
- NRF_POWER->SYSTEMOFF = 1;
+ // Sleepy trackers or sensors can low power "sleep"
+ // Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
+ if (msecToWake != portMAX_DELAY &&
+ (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
+ config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) &&
+ config.power.is_power_saving == true) {
+ sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
+ delay(msecToWake);
+ NVIC_SystemReset();
+ } else {
+ // FIXME, use system off mode with ram retention for key state?
+ // FIXME, use non-init RAM per
+ // https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled
+ auto ok = sd_power_system_off();
+ if (ok != NRF_SUCCESS) {
+ LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n");
+ NRF_POWER->SYSTEMOFF = 1;
+ }
}
// The following code should not be run, because we are off
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 62ce0064f..b0f4aec88 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -95,7 +95,29 @@ void initDeepSleep()
{
#ifdef ARCH_ESP32
bootCount++;
+ const char *reason;
wakeCause = esp_sleep_get_wakeup_cause();
+
+ switch (wakeCause) {
+ case ESP_SLEEP_WAKEUP_EXT0:
+ reason = "ext0 RTC_IO";
+ break;
+ case ESP_SLEEP_WAKEUP_EXT1:
+ reason = "ext1 RTC_CNTL";
+ break;
+ case ESP_SLEEP_WAKEUP_TIMER:
+ reason = "timer";
+ break;
+ case ESP_SLEEP_WAKEUP_TOUCHPAD:
+ reason = "touchpad";
+ break;
+ case ESP_SLEEP_WAKEUP_ULP:
+ reason = "ULP program";
+ break;
+ default:
+ reason = "reset";
+ break;
+ }
/*
Not using yet because we are using wake on all buttons being low
@@ -106,7 +128,6 @@ void initDeepSleep()
#ifdef DEBUG_PORT
// If we booted because our timer ran out or the user pressed reset, send those as fake events
- const char *reason = "reset"; // our best guess
RESET_REASON hwReason = rtc_get_reset_reason(0);
if (hwReason == RTCWDT_BROWN_OUT_RESET)
@@ -118,9 +139,6 @@ void initDeepSleep()
if (hwReason == TG1WDT_SYS_RESET)
reason = "intWatchdog";
- if (wakeCause == ESP_SLEEP_WAKEUP_TIMER)
- reason = "timeout";
-
LOG_INFO("Booted, wake cause %d (boot count %d), reset_reason=%s\n", wakeCause, bootCount, reason);
#endif
#endif
@@ -135,16 +153,18 @@ bool doPreflightSleep()
}
/// Tell devices we are going to sleep and wait for them to handle things
-static void waitEnterSleep()
+static void waitEnterSleep(bool skipPreflight = false)
{
- uint32_t now = millis();
- while (!doPreflightSleep()) {
- delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
+ if (!skipPreflight) {
+ uint32_t now = millis();
+ while (!doPreflightSleep()) {
+ delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives)
- if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
- RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_SLEEP_ENTER_WAIT);
- assert(0); // FIXME - for now we just restart, need to fix bug #167
- break;
+ if (millis() - now > 30 * 1000) { // If we wait too long just report an error and go to sleep
+ RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_SLEEP_ENTER_WAIT);
+ assert(0); // FIXME - for now we just restart, need to fix bug #167
+ break;
+ }
}
}
@@ -155,7 +175,7 @@ static void waitEnterSleep()
notifySleep.notifyObservers(NULL);
}
-void doDeepSleep(uint32_t msecToWake)
+void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
{
if (INCLUDE_vTaskSuspend && (msecToWake == portMAX_DELAY)) {
LOG_INFO("Entering deep sleep forever\n");
@@ -165,7 +185,7 @@ void doDeepSleep(uint32_t msecToWake)
// not using wifi yet, but once we are this is needed to shutoff the radio hw
// esp_wifi_stop();
- waitEnterSleep();
+ waitEnterSleep(skipPreflight);
notifyDeepSleep.notifyObservers(NULL);
screen->doDeepSleep(); // datasheet says this will draw only 10ua
@@ -173,7 +193,8 @@ void doDeepSleep(uint32_t msecToWake)
nodeDB.saveToDisk();
// Kill GPS power completely (even if previously we just had it in sleep mode)
- gps->setGPSPower(false, false);
+ if (gps)
+ gps->setGPSPower(false, false, 0);
setLed(false);
@@ -181,7 +202,13 @@ void doDeepSleep(uint32_t msecToWake)
digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power
#endif
-#ifdef VEXT_ENABLE
+#if defined(VEXT_ENABLE_V03)
+ if (heltec_version == 3) {
+ digitalWrite(VEXT_ENABLE_V03, 1); // turn off the display power
+ } else {
+ digitalWrite(VEXT_ENABLE_V05, 0); // turn off the display power
+ }
+#elif defined(VEXT_ENABLE)
digitalWrite(VEXT_ENABLE, 1); // turn off the display power
#endif
@@ -227,7 +254,7 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r
{
// LOG_DEBUG("Enter light sleep\n");
- waitEnterSleep();
+ waitEnterSleep(false);
uint64_t sleepUsec = sleepMsec * 1000LL;
diff --git a/src/sleep.h b/src/sleep.h
index 8ff81035c..a592ad2c1 100644
--- a/src/sleep.h
+++ b/src/sleep.h
@@ -4,7 +4,7 @@
#include "Observer.h"
#include "configuration.h"
-void doDeepSleep(uint32_t msecToWake), cpuDeepSleep(uint32_t msecToWake);
+void doDeepSleep(uint32_t msecToWake, bool skipPreflight), cpuDeepSleep(uint32_t msecToWake);
#ifdef ARCH_ESP32
#include "esp_sleep.h"
diff --git a/variants/MakePython_nRF52840_eink/platformio.ini b/variants/MakePython_nRF52840_eink/platformio.ini
index 2b08ec9a1..3ac18bcf0 100644
--- a/variants/MakePython_nRF52840_eink/platformio.ini
+++ b/variants/MakePython_nRF52840_eink/platformio.ini
@@ -11,4 +11,4 @@ lib_deps =
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
zinggjm/GxEPD2@^1.4.9
debug_tool = jlink
-upload_port = /dev/ttyACM4
+;upload_port = /dev/ttyACM4
diff --git a/variants/betafpv_2400_tx_micro/platformio.ini b/variants/betafpv_2400_tx_micro/platformio.ini
index decdb390e..82fe2a9e4 100644
--- a/variants/betafpv_2400_tx_micro/platformio.ini
+++ b/variants/betafpv_2400_tx_micro/platformio.ini
@@ -11,7 +11,7 @@ build_flags =
-I variants/betafpv_2400_tx_micro
board_build.f_cpu = 240000000L
upload_protocol = esptool
-upload_port = /dev/ttyUSB0
+;upload_port = /dev/ttyUSB0
upload_speed = 460800
lib_deps =
${esp32_base.lib_deps}
diff --git a/variants/betafpv_900_tx_nano/platformio.ini b/variants/betafpv_900_tx_nano/platformio.ini
index e4c945cab..68e1a469b 100644
--- a/variants/betafpv_900_tx_nano/platformio.ini
+++ b/variants/betafpv_900_tx_nano/platformio.ini
@@ -10,7 +10,7 @@ build_flags =
-I variants/betafpv_900_tx_nano
board_build.f_cpu = 240000000L
upload_protocol = esptool
-upload_port = /dev/ttyUSB0
+;upload_port = /dev/ttyUSB0
upload_speed = 460800
lib_deps =
${esp32_base.lib_deps}
diff --git a/variants/bpi_picow_esp32_s3/platformio.ini b/variants/bpi_picow_esp32_s3/platformio.ini
index 27c420df5..7e94cc97e 100644
--- a/variants/bpi_picow_esp32_s3/platformio.ini
+++ b/variants/bpi_picow_esp32_s3/platformio.ini
@@ -6,7 +6,7 @@ board_level = extra
;upload_protocol = esp-builtin
;Normal method
upload_protocol = esptool
-upload_port = /dev/ttyACM2
+;upload_port = /dev/ttyACM2
lib_deps =
${esp32_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
diff --git a/variants/diy/hydra/variant.h b/variants/diy/hydra/variant.h
index 98c1c2ae1..64bdd73f7 100644
--- a/variants/diy/hydra/variant.h
+++ b/variants/diy/hydra/variant.h
@@ -2,13 +2,11 @@
#define I2C_SDA 21
#define I2C_SCL 22
-// GPS
-#undef GPS_RX_PIN
-#undef GPS_TX_PIN
-#define GPS_RX_PIN 12
+// For GPS, 'undef's not needed
#define GPS_TX_PIN 15
-#define GPS_UBLOX
+#define GPS_RX_PIN 12
#define PIN_GPS_EN 4
+#define GPS_POWER_TOGGLE // Moved definition from platformio.ini to here
#define BUTTON_PIN 39 // The middle button GPIO on the T-Beam
#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
@@ -18,28 +16,25 @@
#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Module (#975).
#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets)
-#define LORA_DIO0 26 // a No connect on the SX1262/SX1268 module
-#define LORA_RESET 23 // RST for SX1276, and for SX1262/SX1268
-#define LORA_DIO1 33 // IRQ for SX1262/SX1268
-#define LORA_DIO2 32 // BUSY for SX1262/SX1268
-#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262/SX1268, if DIO3 is high the TXCO is enabled
+// Radio
+#define USE_SX1262 // E22-900M30S uses SX1262
+#define SX126X_MAX_POWER \
+ 22 // Outputting 22dBm from SX1262 results in ~30dBm E22-900M30S output (module only uses last stage of the YP2233W PA)
+#define SX126X_DIO3_TCXO_VOLTAGE 1.8 // E22 series TCXO reference voltage is 1.8V
-#define RF95_SCK 5
-#define RF95_MISO 19
-#define RF95_MOSI 27
-#define RF95_NSS 18
+#define SX126X_CS 18 // EBYTE module's NSS pin
+#define SX126X_SCK 5 // EBYTE module's SCK pin
+#define SX126X_MOSI 27 // EBYTE module's MOSI pin
+#define SX126X_MISO 19 // EBYTE module's MISO pin
+#define SX126X_RESET 23 // EBYTE module's NRST pin
+#define SX126X_BUSY 32 // EBYTE module's BUSY pin
+#define SX126X_DIO1 33 // EBYTE module's DIO1 pin
-#define USE_SX1262
+#define SX126X_TXEN 13 // Schematic connects EBYTE module's TXEN pin to MCU
+#define SX126X_RXEN 14 // Schematic connects EBYTE module's RXEN pin to MCU
-#define SX126X_CS 18 // NSS for SX126X
-#define SX126X_DIO1 LORA_DIO1
-#define SX126X_BUSY LORA_DIO2
-#define SX126X_RESET LORA_RESET
-#define SX126X_RXEN 14
-#define SX126X_TXEN RADIOLIB_NC
-#define SX126X_DIO2_AS_RF_SWITCH
-
-// Set lora.tx_power to 13 for Hydra or other E22 900M30S target due to PA
-#define SX126X_MAX_POWER 13
-
-#define SX126X_DIO3_TCXO_VOLTAGE 1.8
+#define RF95_NSS SX126X_CS // Compatibility with variant file configuration structure
+#define RF95_SCK SX126X_SCK // Compatibility with variant file configuration structure
+#define RF95_MOSI SX126X_MOSI // Compatibility with variant file configuration structure
+#define RF95_MISO SX126X_MISO // Compatibility with variant file configuration structure
+#define LORA_DIO1 SX126X_DIO1 // Compatibility with variant file configuration structure
diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini
index cb031f266..e7d72d13f 100644
--- a/variants/diy/platformio.ini
+++ b/variants/diy/platformio.ini
@@ -43,6 +43,4 @@ board_level = extra
build_flags =
${esp32_base.build_flags}
-D DIY_V1
- -D EBYTE_E22
- -D GPS_POWER_TOGGLE
-I variants/diy/hydra
diff --git a/variants/heltec_esp32c3/platformio.ini b/variants/heltec_esp32c3/platformio.ini
index a9843ef85..c9c80213e 100644
--- a/variants/heltec_esp32c3/platformio.ini
+++ b/variants/heltec_esp32c3/platformio.ini
@@ -8,5 +8,5 @@ build_flags =
-I variants/heltec_esp32c3
monitor_speed = 115200
upload_protocol = esptool
-upload_port = /dev/ttyUSB0
-upload_speed = 921600
+;upload_port = /dev/ttyUSB0
+upload_speed = 921600
\ No newline at end of file
diff --git a/variants/heltec_wireless_tracker/variant.h b/variants/heltec_wireless_tracker/variant.h
index cfb752d03..4a1b61038 100644
--- a/variants/heltec_wireless_tracker/variant.h
+++ b/variants/heltec_wireless_tracker/variant.h
@@ -9,9 +9,11 @@
#define ST7735_RESET 39
#define ST7735_MISO -1
#define ST7735_BUSY -1
-#define ST7735_BL 45
+#define ST7735_BL_V03 45
+#define ST7735_BL_V05 21 /* V1.1 PCB marking */
#define ST7735_SPI_HOST SPI3_HOST
-#define ST7735_BACKLIGHT_EN 45
+#define ST7735_BACKLIGHT_EN_V03 45
+#define ST7735_BACKLIGHT_EN_V05 21
#define SPI_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000
#define SCREEN_ROTATE
@@ -19,17 +21,20 @@
#define TFT_WIDTH 80
#define TFT_OFFSET_X 26
#define TFT_OFFSET_Y 0
-#define VTFT_CTRL 46 // Heltec Tracker needs this pulled low for TFT
+#define VTFT_CTRL_V03 46 // Heltec Tracker needs this pulled low for TFT
+#define VTFT_CTRL_V05 -1
#define SCREEN_TRANSITION_FRAMERATE 1 // fps
#define DISPLAY_FORCE_SMALL_FONTS
-#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
+#define VEXT_ENABLE_V03 Vext // active low, powers the oled display and the lora antenna boost
+#define VEXT_ENABLE_V05 3 // active HIGH, powers the oled display
#define BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
#define ADC_MULTIPLIER 4.9
+#define ADC_CTRL 2 // active HIGH, powers the voltage divider. Only on 1.1
#undef GPS_RX_PIN
#undef GPS_TX_PIN
@@ -37,9 +42,12 @@
#define GPS_TX_PIN 34
#define PIN_GPS_RESET 35
#define PIN_GPS_PPS 36
-#define VGNSS_CTRL 37 // Heltec Tracker needs this pulled low for GPS
-#define PIN_GPS_EN VGNSS_CTRL
+
+#define VGNSS_CTRL_V03 37 // Heltec Tracker needs this pulled low for GPS
+#define VGNSS_CTRL_V05 -1 // Heltec Tracker needs this pulled low for GPS
+#define PIN_GPS_EN VGNSS_CTRL_V03
#define GPS_EN_ACTIVE LOW
+
#define GPS_RESET_MODE LOW
#define GPS_UC6580
diff --git a/variants/heltec_wsl_v3/variant.h b/variants/heltec_wsl_v3/variant.h
index 240a482f7..417abf34d 100644
--- a/variants/heltec_wsl_v3/variant.h
+++ b/variants/heltec_wsl_v3/variant.h
@@ -8,8 +8,6 @@
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
#define BUTTON_PIN 0
-#define PIN_GPS_EN 46 // GPS power enable pin
-
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
diff --git a/variants/m5stack-stamp-c3/platformio.ini b/variants/m5stack-stamp-c3/platformio.ini
index b7cec5552..bab65b621 100644
--- a/variants/m5stack-stamp-c3/platformio.ini
+++ b/variants/m5stack-stamp-c3/platformio.ini
@@ -8,5 +8,5 @@ build_flags =
-I variants/m5stack-stamp-c3
monitor_speed = 115200
upload_protocol = esptool
-upload_port = /dev/ttyACM2
+;upload_port = /dev/ttyACM2
upload_speed = 921600
diff --git a/variants/m5stack_coreink/platformio.ini b/variants/m5stack_coreink/platformio.ini
index 1a7926d7e..e6aef380c 100644
--- a/variants/m5stack_coreink/platformio.ini
+++ b/variants/m5stack_coreink/platformio.ini
@@ -23,4 +23,4 @@ lib_ignore =
monitor_filters = esp32_exception_decoder
board_build.f_cpu = 240000000L
upload_protocol = esptool
-upload_port = /dev/ttyACM0
+;upload_port = /dev/ttyACM0
diff --git a/variants/my_esp32s3_diy_eink/platformio.ini b/variants/my_esp32s3_diy_eink/platformio.ini
index 8405f784e..d3c55afda 100644
--- a/variants/my_esp32s3_diy_eink/platformio.ini
+++ b/variants/my_esp32s3_diy_eink/platformio.ini
@@ -6,7 +6,7 @@ board_build.arduino.memory_type = dio_opi
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
upload_protocol = esptool
-upload_port = /dev/ttyACM1
+;upload_port = /dev/ttyACM1
upload_speed = 921600
platform_packages =
tool-esptoolpy@^1.40500.0
diff --git a/variants/my_esp32s3_diy_oled/platformio.ini b/variants/my_esp32s3_diy_oled/platformio.ini
index 1430dfd96..9b8b09f7f 100644
--- a/variants/my_esp32s3_diy_oled/platformio.ini
+++ b/variants/my_esp32s3_diy_oled/platformio.ini
@@ -6,7 +6,7 @@ board_build.arduino.memory_type = dio_opi
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
upload_protocol = esptool
-upload_port = /dev/ttyACM0
+;upload_port = /dev/ttyACM0
upload_speed = 921600
platform_packages =
tool-esptoolpy@^1.40500.0
diff --git a/variants/rak4631_epaper_onrxtx/platformio.ini b/variants/rak4631_epaper_onrxtx/platformio.ini
index 08c55d129..0a4f05344 100644
--- a/variants/rak4631_epaper_onrxtx/platformio.ini
+++ b/variants/rak4631_epaper_onrxtx/platformio.ini
@@ -15,4 +15,4 @@ lib_deps =
debug_tool = jlink
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
;upload_protocol = jlink
-upload_port = /dev/ttyACM3
+;upload_port = /dev/ttyACM3
diff --git a/variants/tbeam/variant.h b/variants/tbeam/variant.h
index 84a3477d4..a0ba70bfd 100644
--- a/variants/tbeam/variant.h
+++ b/variants/tbeam/variant.h
@@ -42,3 +42,4 @@
#define GPS_UBLOX
#define GPS_RX_PIN 34
#define GPS_TX_PIN 12
+// #define GPS_DEBUG
\ No newline at end of file
diff --git a/variants/trackerd/platformio.ini b/variants/trackerd/platformio.ini
new file mode 100644
index 000000000..23868ffb4
--- /dev/null
+++ b/variants/trackerd/platformio.ini
@@ -0,0 +1,13 @@
+[env:trackerd]
+extends = esp32_base
+;platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
+platform = espressif32
+board = pico32
+board_build.f_flash = 80000000L
+board_level = extra
+build_flags =
+ ${esp32_base.build_flags} -D PRIVATE_HW -I variants/trackerd -D BSFILE=\"boards/dragino_lbt2.h\"
+;board_build.partitions = no_ota.csv
+;platform_packages =
+; platformio/framework-arduinoespressif32@3
+;platformio/framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.1-RC1
\ No newline at end of file
diff --git a/variants/trackerd/variant.h b/variants/trackerd/variant.h
new file mode 100644
index 000000000..b3fca367f
--- /dev/null
+++ b/variants/trackerd/variant.h
@@ -0,0 +1,46 @@
+// Initialize i2c bus on sd_dat and esp_led pins, respectively. We need a bus to not hang on boot
+#define HAS_SCREEN 0
+#define I2C_SDA 21
+#define I2C_SCL 22
+
+#undef GPS_RX_PIN
+#undef GPS_TX_PIN
+#define GPS_RX_PIN 9
+#define GPS_TX_PIN 10
+
+#define LED_PIN 13 // 13 red, 2 blue, 15 red
+
+//#define HAS_BUTTON 0
+#define BUTTON_PIN 0
+#define BUTTON_NEED_PULLUP
+
+#define USE_RF95
+#define LORA_DIO0 26 // a No connect on the SX1262 module
+#define LORA_RESET 23
+#define LORA_DIO1 33
+#define LORA_DIO2 32 // Not really used
+
+#define BATTERY_PIN 35 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+
+// Battery
+// The battery sense is hooked to pin A0 (4)
+// it is defined in the anlaolgue pin section of this file
+// and has 12 bit resolution
+#define BATTERY_SENSE_RESOLUTION_BITS 12
+#define BATTERY_SENSE_RESOLUTION 4096.0
+// Definition of milliVolt per LSB => 3.0V ADC range and 12-bit ADC resolution = 3000mV/4096
+#define VBAT_MV_PER_LSB (0.73242188F)
+// Voltage divider value => 100K + 100K voltage divider on VBAT = (100K / (100K + 100K))
+#define VBAT_DIVIDER (0.5F)
+// Compensation factor for the VBAT divider
+#define VBAT_DIVIDER_COMP (2.0)
+// Fixed calculation of milliVolt from compensation value
+#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
+#undef AREF_VOLTAGE
+#define AREF_VOLTAGE 3.0
+#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
+#define ADC_MULTIPLIER VBAT_DIVIDER_COMP
+#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
+
+//#define BATTERY_SENSE_SAMPLES 15 // Set the number of samples, It has an effect of increasing sensitivity.
+//#define ADC_MULTIPLIER 3.3
\ No newline at end of file
diff --git a/version.properties b/version.properties
index fc48509e1..006a90013 100644
--- a/version.properties
+++ b/version.properties
@@ -1,4 +1,4 @@
[VERSION]
major = 2
minor = 2
-build = 10
+build = 13