Merge branch 'master' into raspi-portduino

This commit is contained in:
Ben Meadors
2023-10-09 19:45:08 -05:00
committed by GitHub
co-authored by GitHub
33 changed files with 577 additions and 259 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
is appreciated." This will allow other devs to potentially save you time by not accidentially duplicating work etc... 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 check in files that don't have real changes
- Please do not reformat lines that you didn't have to change the code on - 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. 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 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. - If your other co-developers have comments on your PR please tweak as needed.
+1 -1
View File
@@ -2,7 +2,7 @@
*logs *logs
*actions *actions
*notifications *notifications
*tools
plugins plugins
user_trunk.yaml user_trunk.yaml
user.yaml user.yaml
tools
+15 -15
View File
@@ -1,53 +1,53 @@
version: 0.1 version: 0.1
cli: cli:
version: 1.13.0 version: 1.16.2
plugins: plugins:
sources: sources:
- id: trunk - id: trunk
ref: v1.1.1 ref: v1.2.5
uri: https://github.com/trunk-io/plugins uri: https://github.com/trunk-io/plugins
lint: lint:
enabled: enabled:
- bandit@1.7.5 - bandit@1.7.5
- checkov@2.4.1 - checkov@2.5.0
- terrascan@1.18.3 - terrascan@1.18.3
- trivy@0.44.1 - trivy@0.45.1
- trufflehog@3.48.0 - trufflehog@3.59.0
- taplo@0.8.1 - taplo@0.8.1
- ruff@0.0.284 - ruff@0.0.292
- yamllint@1.32.0 - yamllint@1.32.0
- isort@5.12.0 - isort@5.12.0
- markdownlint@0.35.0 - markdownlint@0.37.0
- oxipng@8.0.0 - oxipng@8.0.0
- svgo@3.0.2 - svgo@3.0.2
- actionlint@1.6.25 - actionlint@1.6.26
- flake8@6.1.0 - flake8@6.1.0
- hadolint@2.12.0 - hadolint@2.12.0
- shfmt@3.6.0 - shfmt@3.6.0
- shellcheck@0.9.0 - shellcheck@0.9.0
- black@23.7.0 - black@23.9.1
- git-diff-check - git-diff-check
- gitleaks@8.17.0 - gitleaks@8.18.0
- clang-format@16.0.3 - clang-format@16.0.3
- prettier@3.0.2 - prettier@3.0.3
disabled: disabled:
- taplo@0.8.1 - taplo@0.8.1
- shellcheck@0.9.0 - shellcheck@0.9.0
- shfmt@3.6.0 - shfmt@3.6.0
- oxipng@8.0.0 - oxipng@8.0.0
- actionlint@1.6.22 - actionlint@1.6.22
- markdownlint@0.35.0 - markdownlint@0.37.0
- hadolint@2.12.0 - hadolint@2.12.0
- svgo@3.0.2 - svgo@3.0.2
runtimes: runtimes:
enabled: enabled:
- python@3.10.8 - python@3.10.8
- go@1.19.5 - go@1.21.0
- node@18.12.1 - node@18.12.1
actions: actions:
disabled: disabled:
- trunk-announce - trunk-announce
- trunk-check-pre-push
- trunk-fmt-pre-commit
enabled: enabled:
- trunk-fmt-pre-commit
- trunk-check-pre-push
- trunk-upgrade-available - trunk-upgrade-available
+2 -2
View File
@@ -10,8 +10,8 @@
This repository contains the device firmware for the Meshtastic project. This repository contains the device firmware for the Meshtastic project.
**[Building Instructions](https://meshtastic.org/docs/development/firmware/build)** - **[Building Instructions](https://meshtastic.org/docs/development/firmware/build)**
**[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)** - **[Flashing Instructions](https://meshtastic.org/docs/getting-started/flashing-firmware/)**
## Stats ## Stats
+1 -1
View File
@@ -70,7 +70,7 @@ lib_deps =
https://github.com/meshtastic/esp8266-oled-ssd1306.git#b38094e03dfa964fbc0e799bc374e91a605c1223 ; ESP8266_SSD1306 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/mathertel/OneButton#2.1.0 ; OneButton library for non-blocking button debounce
https://github.com/meshtastic/arduino-fsm.git#7db3702bf0cfe97b783d6c72595e3f38e0b19159 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 https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.7 nanopb/Nanopb@^0.4.7
erriez/ErriezCRC32@^1.0.1 erriez/ErriezCRC32@^1.0.1
+13 -1
View File
@@ -175,9 +175,21 @@ class AnalogBatteryLevel : public HasBatteryLevel
uint32_t raw = 0; uint32_t raw = 0;
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
#ifndef BAT_MEASURE_ADC_UNIT // ADC1 #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++) { for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
raw += adc1_get_raw(adc_channel); raw += adc1_get_raw(adc_channel);
} }
#ifdef ADC_CTRL
if (heltec_version == 5) {
digitalWrite(ADC_CTRL, LOW);
}
#endif
#else // ADC2 #else // ADC2
int32_t adc_buf = 0; int32_t adc_buf = 0;
for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) { for (int i = 0; i < BATTERY_SENSE_SAMPLES; i++) {
@@ -414,7 +426,7 @@ void Power::shutdown()
#ifdef PIN_LED3 #ifdef PIN_LED3
ledOff(PIN_LED2); ledOff(PIN_LED2);
#endif #endif
doDeepSleep(DELAY_FOREVER); doDeepSleep(DELAY_FOREVER, false);
#endif #endif
} }
+7 -14
View File
@@ -45,7 +45,7 @@ static void sdsEnter()
{ {
LOG_DEBUG("Enter state: SDS\n"); LOG_DEBUG("Enter state: SDS\n");
// FIXME - make sure GPS and LORA radio are off first - because we want close to zero current draw // 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; extern Power *power;
@@ -154,9 +154,6 @@ static void darkEnter()
{ {
setBluetoothEnable(true); setBluetoothEnable(true);
screen->setOn(false); screen->setOn(false);
#ifdef KB_POWERON
digitalWrite(KB_POWERON, LOW);
#endif
} }
static void serialEnter() static void serialEnter()
@@ -184,9 +181,6 @@ static void powerEnter()
} else { } else {
screen->setOn(true); screen->setOn(true);
setBluetoothEnable(true); setBluetoothEnable(true);
#ifdef KB_POWERON
digitalWrite(KB_POWERON, HIGH);
#endif
// within enter() the function getState() returns the state we came from // within enter() the function getState() returns the state we came from
if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 && if (strcmp(powerFSM.getState()->name, "BOOT") != 0 && strcmp(powerFSM.getState()->name, "POWER") != 0 &&
strcmp(powerFSM.getState()->name, "DARK") != 0) { strcmp(powerFSM.getState()->name, "DARK") != 0) {
@@ -217,9 +211,6 @@ static void onEnter()
LOG_DEBUG("Enter state: ON\n"); LOG_DEBUG("Enter state: ON\n");
screen->setOn(true); screen->setOn(true);
setBluetoothEnable(true); setBluetoothEnable(true);
#ifdef KB_POWERON
digitalWrite(KB_POWERON, HIGH);
#endif
} }
static void onIdle() static void onIdle()
@@ -254,6 +245,8 @@ Fsm powerFSM(&stateBOOT);
void PowerFSM_setup() void PowerFSM_setup()
{ {
bool isRouter = (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ? 1 : 0); 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(); bool hasPower = isPowered();
LOG_INFO("PowerFSM init, USB power=%d\n", hasPower ? 1 : 0); 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, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL,
"Screen-on timeout"); "Screen-on timeout");
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
#ifdef ARCH_ESP32 #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 // 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, powerFSM.add_timed_transition(&stateNB, &stateLS,
getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL,
"Min wake timeout"); "Min wake timeout");
+1
View File
@@ -67,6 +67,7 @@ class OSThread : public Thread
* Returns desired period for next invocation (or RUN_SAME for no change) * Returns desired period for next invocation (or RUN_SAME for no change)
*/ */
virtual int32_t runOnce() = 0; virtual int32_t runOnce() = 0;
bool sleepOnNextExecution = false;
// Do not override this // Do not override this
virtual void run(); virtual void run();
+105 -51
View File
@@ -20,7 +20,7 @@ HardwareSerial *GPS::_serial_gps = &Serial1;
HardwareSerial *GPS::_serial_gps = NULL; HardwareSerial *GPS::_serial_gps = NULL;
#endif #endif
GPS *gps; GPS *gps = nullptr;
/// Multiple GPS instances might use the same serial port (in sequence), but we can /// Multiple GPS instances might use the same serial port (in sequence), but we can
/// only init that port once. /// only init that port once.
@@ -76,28 +76,25 @@ GPS_RESPONSE GPS::getACK(const char *message, uint32_t waitMillis)
while (millis() < startTimeout) { while (millis() < startTimeout) {
if (_serial_gps->available()) { if (_serial_gps->available()) {
b = _serial_gps->read(); b = _serial_gps->read();
#ifdef GPS_DEBUG
LOG_DEBUG("%02X", (char *)buffer);
#endif
buffer[bytesRead] = b; buffer[bytesRead] = b;
bytesRead++; bytesRead++;
if ((bytesRead == 767) || (b == '\r')) { if ((bytesRead == 767) || (b == '\r')) {
if (strnstr((char *)buffer, message, bytesRead) != nullptr) { if (strnstr((char *)buffer, message, bytesRead) != nullptr) {
#ifdef GPS_DEBUG #ifdef GPS_DEBUG
buffer[bytesRead] = '\0'; LOG_DEBUG("\r");
LOG_DEBUG("%s\r", (char *)buffer);
#endif #endif
return GNSS_RESPONSE_OK; return GNSS_RESPONSE_OK;
} else { } else {
#ifdef GPS_DEBUG
buffer[bytesRead] = '\0';
LOG_INFO("Bytes read:%s\n", (char *)buffer);
#endif
bytesRead = 0; bytesRead = 0;
} }
} }
} }
} }
#ifdef GPS_DEBUG #ifdef GPS_DEBUG
buffer[bytesRead] = '\0'; LOG_DEBUG("\n");
LOG_INFO("Bytes read:%s\n", (char *)buffer);
#endif #endif
return GNSS_RESPONSE_NONE; 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() bool GPS::setup()
{ {
int msglen = 0; int msglen = 0;
bool isProblematicGPS = false;
if (!didSerialInit) { if (!didSerialInit) {
#if !defined(GPS_UC6580) #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]); LOG_DEBUG("Probing for GPS at %d \n", serialSpeeds[speedSelect]);
gnssModel = probe(serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]);
if (gnssModel == GNSS_MODEL_UNKNOWN) { if (gnssModel == GNSS_MODEL_UNKNOWN) {
@@ -390,32 +395,36 @@ bool GPS::setup()
LOG_WARN("Unable to enable powersaving for GPS.\n"); LOG_WARN("Unable to enable powersaving for GPS.\n");
} }
} else { } else {
if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware if (!(isProblematicGPS)) {
msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM); if (strncmp(info.hwVersion, "00040007", 8) == 0) { // This PSM mode has only been tested on this hardware
_serial_gps->write(UBXscratch, msglen); msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_PSM);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to enable powersaving mode for GPS.\n"); 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); msglen = makeUBXPacket(0x06, 0x3B, 44, _message_CFG_PM2);
if (getACK(0x06, 0x3B, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to enable powersaving details for GPS.\n"); 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); } else {
_serial_gps->write(UBXscratch, msglen); msglen = makeUBXPacket(0x06, 0x11, 0x2, _message_CFG_RXM_ECO);
if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n"); if (getACK(0x06, 0x11, 300) != GNSS_RESPONSE_OK) {
LOG_WARN("Unable to enable powersaving ECO mode for GPS.\n");
}
} }
} }
} }
// The T-beam 1.2 has issues.
msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE); if (!(isProblematicGPS)) {
_serial_gps->write(UBXscratch, msglen); msglen = makeUBXPacket(0x06, 0x09, sizeof(_message_SAVE), _message_SAVE);
if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) { _serial_gps->write(UBXscratch, msglen);
LOG_WARN("Unable to save GNSS module configuration.\n"); if (getACK(0x06, 0x09, 300) != GNSS_RESPONSE_OK) {
} else { LOG_WARN("Unable to save GNSS module configuration.\n");
LOG_INFO("GNSS module configuration saved!\n"); } else {
LOG_INFO("GNSS module configuration saved!\n");
}
} }
} }
didSerialInit = true; didSerialInit = true;
@@ -433,7 +442,7 @@ GPS::~GPS()
notifyGPSSleepObserver.observe(&notifyGPSSleep); notifyGPSSleepObserver.observe(&notifyGPSSleep);
} }
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); LOG_INFO("Setting GPS power=%d\n", on);
if (on) { if (on) {
@@ -483,6 +492,10 @@ void GPS::setGPSPower(bool on, bool standbyOnly)
if (!on) { if (!on) {
if (gnssModel == GNSS_MODEL_UBLOX) { if (gnssModel == GNSS_MODEL_UBLOX) {
uint8_t msglen; 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); msglen = gps->makeUBXPacket(0x02, 0x41, 0x08, gps->_message_PMREQ);
gps->_serial_gps->write(gps->UBXscratch, msglen); gps->_serial_gps->write(gps->UBXscratch, msglen);
} }
@@ -514,7 +527,7 @@ void GPS::setAwake(bool on)
LOG_DEBUG("WANT GPS=%d\n", on); LOG_DEBUG("WANT GPS=%d\n", on);
isAwake = on; isAwake = on;
if (!enabled) { // short circuit if the user has disabled GPS if (!enabled) { // short circuit if the user has disabled GPS
setGPSPower(false, false); setGPSPower(false, false, 0);
return; return;
} }
@@ -532,12 +545,12 @@ void GPS::setAwake(bool on)
} }
if ((int32_t)getSleepTime() - averageLockTime > if ((int32_t)getSleepTime() - averageLockTime >
15 * 60 * 1000) { // 15 minutes is probably long enough to make a complete poweroff worth it. 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 } else if ((int32_t)getSleepTime() - averageLockTime > 10000) { // 10 seconds is enough for standby
#ifdef GPS_UC6580 #ifdef GPS_UC6580
setGPSPower(on, false); setGPSPower(on, false, getSleepTime() - averageLockTime);
#else #else
setGPSPower(on, true); setGPSPower(on, true, getSleepTime() - averageLockTime);
#endif #endif
} else if (averageLockTime > 20000) { } else if (averageLockTime > 20000) {
averageLockTime -= 1000; // eventually want to sleep again. averageLockTime -= 1000; // eventually want to sleep again.
@@ -598,7 +611,7 @@ int32_t GPS::runOnce()
return 2000; // Setup failed, re-run in two seconds return 2000; // Setup failed, re-run in two seconds
// We have now loaded our saved preferences from flash // 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(); return disable();
} }
// ONCE we will factory reset the GPS for bug #327 // 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 // If we are overdue for an update, turn on the GPS and at least publish the current status
uint32_t now = millis(); uint32_t now = millis();
@@ -685,8 +703,8 @@ int32_t GPS::runOnce()
// If state has changed do a publish // If state has changed do a publish
publishUpdate(); publishUpdate();
if (config.position.gps_enabled == false) // This should trigger if GPS is disabled but fixed_position is true if (config.position.fixed_position == true && hasValidLocation)
return disable(); 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 // 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. // 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"); LOG_DEBUG("Using " NMEA_MSG_GXGSA " for 3DFIX and PDOP\n");
#endif #endif
if (config.position.gps_enabled) { new_gps->setGPSPower(true, false, 0);
new_gps->setGPSPower(true, false);
}
#ifdef PIN_GPS_RESET #ifdef PIN_GPS_RESET
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE); // assert for 10ms
@@ -956,11 +972,38 @@ bool GPS::factoryReset()
digitalWrite(PIN_GPS_REINIT, 1); digitalWrite(PIN_GPS_REINIT, 1);
#endif #endif
// send the UBLOX Factory Reset Command regardless of detect state, something is very wrong, just assume it's UBLOX. if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) {
// Factory Reset byte _message_reset1[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
byte _message_reset[] = {0xB5, 0x62, 0x06, 0x09, 0x0D, 0x00, 0xFF, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1C, 0xA2};
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x17, 0x2B, 0x7E}; _serial_gps->write(_message_reset1, sizeof(_message_reset1));
_serial_gps->write(_message_reset, sizeof(_message_reset)); 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); delay(1000);
return true; return true;
} }
@@ -1157,6 +1200,7 @@ bool GPS::hasFlow()
bool GPS::whileIdle() bool GPS::whileIdle()
{ {
int charsInBuf = 0;
bool isValid = false; bool isValid = false;
if (!isAwake) { if (!isAwake) {
clearBuffer(); clearBuffer();
@@ -1173,10 +1217,20 @@ bool GPS::whileIdle()
// First consume any chars that have piled up at the receiver // First consume any chars that have piled up at the receiver
while (_serial_gps->available() > 0) { while (_serial_gps->available() > 0) {
int c = _serial_gps->read(); int c = _serial_gps->read();
// LOG_DEBUG("%c", c); UBXscratch[charsInBuf] = c;
#ifdef GPS_DEBUG
LOG_DEBUG("%c", c);
#endif
isValid |= reader.encode(c); 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; return isValid;
} }
void GPS::enable() void GPS::enable()
+4 -2
View File
@@ -94,7 +94,7 @@ class GPS : private concurrency::OSThread
/** If !NULL we will use this serial port to construct our GPS */ /** If !NULL we will use this serial port to construct our GPS */
static HardwareSerial *_serial_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_PSM[];
static const uint8_t _message_CFG_RXM_ECO[]; static const uint8_t _message_CFG_RXM_ECO[];
static const uint8_t _message_CFG_PM2[]; static const uint8_t _message_CFG_PM2[];
@@ -132,7 +132,7 @@ class GPS : private concurrency::OSThread
// Disable the thread // Disable the thread
int32_t disable() override; 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. /// Returns true if we have acquired GPS lock.
virtual bool hasLock(); virtual bool hasLock();
@@ -154,6 +154,8 @@ class GPS : private concurrency::OSThread
// scratch space for creating ublox packets // scratch space for creating ublox packets
uint8_t UBXscratch[250] = {0}; 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); 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(uint8_t c, uint8_t i, uint32_t waitMillis);
GPS_RESPONSE getACK(const char *message, uint32_t waitMillis); GPS_RESPONSE getACK(const char *message, uint32_t waitMillis);
+3 -3
View File
@@ -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, // 4 bytes duration of request task
0x00, 0x00, // (milliseconds) 0x00, 0x00, // (milliseconds)
0x02, 0x00, // Task flag bitfield 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 = { const uint8_t GPS::_message_CFG_PM2[] PROGMEM = {
0x01, 0x06, 0x00, 0x00, // version, Reserved 0x01, 0x06, 0x00, 0x00, // version, Reserved
0x0e, 0x81, 0x42, 0x01, // flags 0x0E, 0x81, 0x43, 0x01, // flags
0xE8, 0x03, 0x00, 0x00, // update period 1000 ms 0xE8, 0x03, 0x00, 0x00, // update period 1000 ms
0x10, 0x27, 0x00, 0x00, // search period 10s 0x10, 0x27, 0x00, 0x00, // search period 10s
0x00, 0x00, 0x00, 0x00, // Grod offset 0 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 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections
0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded
0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash 0x0F // deviceMask: BBR, Flash, EEPROM, and SPI Flash
}; };
+20 -3
View File
@@ -164,11 +164,28 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
// FIXME - draw serial # somewhere? // FIXME - draw serial # somewhere?
} }
#ifdef ARCH_ESP32
static void drawFrameResume(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, "Resuming...");
}
#endif
static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) static void drawBootScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{ {
// Draw region in upper left #ifdef ARCH_ESP32
const char *region = myRegion ? myRegion->name : NULL; if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) {
drawIconScreen(region, display, state, x, y); drawFrameResume(display, state, x, y);
} else
#endif
{
// 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) static void drawOEMIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
+48 -1
View File
@@ -1,4 +1,5 @@
#include "configuration.h" #include "configuration.h"
#include "main.h"
#ifndef TFT_BACKLIGHT_ON #ifndef TFT_BACKLIGHT_ON
#define TFT_BACKLIGHT_ON HIGH #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. 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.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.freq = 44100; // PWM frequency of backlight
// cfg.pwm_channel = 1; // PWM channel number to use // cfg.pwm_channel = 1; // PWM channel number to use
@@ -364,9 +373,23 @@ void TFTDisplay::sendCommand(uint8_t com)
// handle display on/off directly // handle display on/off directly
switch (com) { switch (com) {
case DISPLAYON: { 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) #if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, TFT_BACKLIGHT_ON); digitalWrite(TFT_BL, TFT_BACKLIGHT_ON);
#endif #endif
#ifdef VTFT_CTRL_V03
if (heltec_version == 3) {
digitalWrite(VTFT_CTRL_V03, LOW);
} else {
digitalWrite(VTFT_CTRL_V05, LOW);
}
#endif
#ifdef VTFT_CTRL #ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, LOW); digitalWrite(VTFT_CTRL, LOW);
#endif #endif
@@ -376,9 +399,23 @@ void TFTDisplay::sendCommand(uint8_t com)
break; break;
} }
case DISPLAYOFF: { 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) #if defined(TFT_BL) && defined(TFT_BACKLIGHT_ON)
digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON); digitalWrite(TFT_BL, !TFT_BACKLIGHT_ON);
#endif #endif
#ifdef VTFT_CTRL_V03
if (heltec_version == 3) {
digitalWrite(VTFT_CTRL_V03, HIGH);
} else {
digitalWrite(VTFT_CTRL_V05, HIGH);
}
#endif
#ifdef VTFT_CTRL #ifdef VTFT_CTRL
digitalWrite(VTFT_CTRL, HIGH); digitalWrite(VTFT_CTRL, HIGH);
#endif #endif
@@ -436,6 +473,16 @@ bool TFTDisplay::connect()
pinMode(TFT_BL, OUTPUT); pinMode(TFT_BL, OUTPUT);
#endif #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(); tft.init();
#if defined(M5STACK) #if defined(M5STACK)
tft.setRotation(0); tft.setRotation(0);
+72 -1
View File
@@ -146,6 +146,25 @@ const char *getDeviceName()
return name; return name;
} }
#ifdef VEXT_ENABLE_V03
#include <soc/rtc.h>
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 int32_t ledBlinker()
{ {
static bool ledOn; static bool ledOn;
@@ -216,11 +235,63 @@ void setup()
digitalWrite(PIN_EINK_PWR_ON, HIGH); digitalWrite(PIN_EINK_PWR_ON, HIGH);
#endif #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); pinMode(VEXT_ENABLE, OUTPUT);
digitalWrite(VEXT_ENABLE, 0); // turn on the display power digitalWrite(VEXT_ENABLE, 0); // turn on the display power
#endif #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) #if defined(VTFT_CTRL)
pinMode(VTFT_CTRL, OUTPUT); pinMode(VTFT_CTRL, OUTPUT);
digitalWrite(VTFT_CTRL, LOW); digitalWrite(VTFT_CTRL, LOW);
+2
View File
@@ -64,6 +64,8 @@ extern uint32_t shutdownAtMsec;
extern uint32_t serialSinceMsec; 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 // 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. // This will suppress the current delay and instead try to run ASAP.
extern bool runASAP; extern bool runASAP;
+1 -1
View File
@@ -687,8 +687,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, 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); p.longitude_i, p.altitude);
setLocalPosition(p);
info->position = ConvertToPositionLite(p); info->position = ConvertToPositionLite(p);
localPosition = p;
} else if ((p.time > 0) && !p.latitude_i && !p.longitude_i && !p.timestamp && !p.location_source) { } 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 // FIXME SPECIAL TIME SETTING PACKET FROM EUD TO RADIO
// (stop-gap fix for issue #900) // (stop-gap fix for issue #900)
+8 -1
View File
@@ -131,6 +131,13 @@ class NodeDB
meshtastic_NodeInfoLite *getMeshNode(NodeNum n); meshtastic_NodeInfoLite *getMeshNode(NodeNum n);
size_t getNumMeshNodes() { return *numMeshNodes; } 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: private:
/// Find a node in our DB, create an empty NodeInfoLite if missing /// Find a node in our DB, create an empty NodeInfoLite if missing
meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n); meshtastic_NodeInfoLite *getOrCreateMeshNode(NodeNum n);
@@ -192,7 +199,7 @@ extern NodeDB nodeDB;
#define default_sds_secs IF_ROUTER(ONE_DAY, UINT32_MAX) // Default to forever super deep sleep #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_ls_secs IF_ROUTER(ONE_DAY, 5 * 60)
#define default_min_wake_secs 10 #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_address "mqtt.meshtastic.org"
#define default_mqtt_username "meshdev" #define default_mqtt_username "meshdev"
+6 -2
View File
@@ -30,10 +30,14 @@ 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. */ 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, meshtastic_Config_DeviceConfig_Role_REPEATER = 4,
/* Tracker device role /* 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, meshtastic_Config_DeviceConfig_Role_TRACKER = 5,
/* Sensor device role /* Sensor device role
Telemetry Mesh packets will be prioritized higher and sent more frequently by default. */ 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 meshtastic_Config_DeviceConfig_Role_SENSOR = 6
} meshtastic_Config_DeviceConfig_Role; } meshtastic_Config_DeviceConfig_Role;
+2
View File
@@ -113,6 +113,8 @@ typedef enum _meshtastic_HardwareModel {
meshtastic_HardwareModel_PICOMPUTER_S3 = 52, meshtastic_HardwareModel_PICOMPUTER_S3 = 52,
/* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */ /* Heltec HT-CT62 with ESP32-C3 CPU and SX1262 LoRa */
meshtastic_HardwareModel_HELTEC_HT62 = 53, meshtastic_HardwareModel_HELTEC_HT62 = 53,
/* E22-900M series modules with ESP32-S3 */
meshtastic_HardwareModel_E22_900M_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. 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.
------------------------------------------------------------------------------------------------------------------------------------------ */ ------------------------------------------------------------------------------------------------------------------------------------------ */
+3 -1
View File
@@ -40,7 +40,9 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
meshtastic_MeshPacket *p = allocReply(); meshtastic_MeshPacket *p = allocReply();
if (p) { // Check whether we didn't ignore it if (p) { // Check whether we didn't ignore it
p->to = dest; 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; p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
if (channel > 0) { if (channel > 0) {
LOG_DEBUG("sending ourNodeInfo to channel %d\n", channel); LOG_DEBUG("sending ourNodeInfo to channel %d\n", channel);
+97 -47
View File
@@ -1,4 +1,5 @@
#include "PositionModule.h" #include "PositionModule.h"
#include "GPS.h"
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "RTC.h" #include "RTC.h"
@@ -7,6 +8,8 @@
#include "airtime.h" #include "airtime.h"
#include "configuration.h" #include "configuration.h"
#include "gps/GeoCoord.h" #include "gps/GeoCoord.h"
#include "sleep.h"
#include "target_specific.h"
PositionModule *positionModule; PositionModule *positionModule;
@@ -14,8 +17,22 @@ PositionModule::PositionModule()
: ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg), : ProtobufModule("position", meshtastic_PortNum_POSITION_APP, &meshtastic_Position_msg),
concurrency::OSThread("PositionModule") concurrency::OSThread("PositionModule")
{ {
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others 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) 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;
} }
bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *pptr) bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Position *pptr)
@@ -27,10 +44,11 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER) // 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) // to set fixed location, EUD-GPS location or just the time (see also issue #900)
bool isLocal = false;
if (nodeDB.getNodeNum() == getFrom(&mp)) { if (nodeDB.getNodeNum() == getFrom(&mp)) {
LOG_DEBUG("Incoming update from MYSELF\n"); LOG_DEBUG("Incoming update from MYSELF\n");
// LOG_DEBUG("Ignored an incoming update from MYSELF\n"); isLocal = true;
// return false; nodeDB.setLocalPosition(p);
} }
// Log packet size and data fields // Log packet size and data fields
@@ -47,7 +65,8 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
tv.tv_sec = secs; tv.tv_sec = secs;
tv.tv_usec = 0; 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); nodeDB.updatePosition(getFrom(&mp), p);
@@ -77,8 +96,9 @@ meshtastic_MeshPacket *PositionModule::allocReply()
// Populate a Position struct with ONLY the requested fields // Populate a Position struct with ONLY the requested fields
meshtastic_Position p = meshtastic_Position_init_default; // Start with an empty structure 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) { if (localPosition.latitude_i == 0 && localPosition.longitude_i == 0) {
localPosition = ConvertToPosition(node->position); nodeDB.setLocalPosition(ConvertToPosition(node->position));
} }
localPosition.seq_number++; localPosition.seq_number++;
@@ -148,7 +168,7 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
} }
p->to = dest; 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) if (config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER)
p->priority = meshtastic_MeshPacket_Priority_RELIABLE; p->priority = meshtastic_MeshPacket_Priority_RELIABLE;
else else
@@ -159,70 +179,83 @@ void PositionModule::sendOurPosition(NodeNum dest, bool wantReplies, uint8_t cha
p->channel = channel; p->channel = channel;
service.sendToMesh(p, RX_SRC_LOCAL, true); 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() 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()); meshtastic_NodeInfoLite *node = nodeDB.getMeshNode(nodeDB.getNodeNum());
// We limit our GPS broadcasts to a max rate // We limit our GPS broadcasts to a max rate
uint32_t now = millis(); uint32_t now = millis();
uint32_t intervalMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs); uint32_t intervalMs = getConfiguredOrDefaultMs(config.position.position_broadcast_secs, default_broadcast_interval_secs);
uint32_t msSinceLastSend = now - lastGpsSend; 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) { if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) {
// Only send packets if the channel is less than 40% utilized. if (hasValidPosition(node)) {
if (airTime->isTxAllowedChannelUtil()) { lastGpsSend = now;
if (hasValidPosition(node)) {
lastGpsSend = now;
lastGpsLatitude = node->position.latitude_i; lastGpsLatitude = node->position.latitude_i;
lastGpsLongitude = node->position.longitude_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; bool requestReplies = currentGeneration != radioGeneration;
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); 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)) { // Set the current coords as our last ones, after we've compared distance with current and decided to send
// The minimum time (in seconds) that would pass before we are able to send a new position packet. lastGpsLatitude = node->position.latitude_i;
const uint32_t minimumTimeThreshold = lastGpsLongitude = node->position.longitude_i;
getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30);
auto smartPosition = getDistanceTraveledSinceLastSend(node->position); /* Update lastGpsSend to now. This means if the device is stationary, then
getPref_position_broadcast_secs will still apply.
if (smartPosition.hasTraveledOverThreshold && msSinceLastSend >= minimumTimeThreshold) { */
bool requestReplies = currentGeneration != radioGeneration; lastGpsSend = now;
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;
}
} }
} }
} }
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) struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
@@ -234,6 +267,23 @@ struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic
float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter( float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7); 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), return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend),
.distanceThreshold = distanceTravelThreshold, .distanceThreshold = distanceTravelThreshold,
.hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold}; .hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};
+4 -1
View File
@@ -49,6 +49,9 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, private concu
private: private:
struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition); struct SmartPosition getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition);
/** Only used in power saving trackers for now */
void clearPosition();
}; };
struct SmartPosition { struct SmartPosition {
@@ -57,4 +60,4 @@ struct SmartPosition {
bool hasTraveledOverThreshold; bool hasTraveledOverThreshold;
}; };
extern PositionModule *positionModule; extern PositionModule *positionModule;
@@ -8,6 +8,8 @@
#include "configuration.h" #include "configuration.h"
#include "main.h" #include "main.h"
#include "power.h" #include "power.h"
#include "sleep.h"
#include "target_specific.h"
#include <OLEDDisplay.h> #include <OLEDDisplay.h>
#include <OLEDDisplayUi.h> #include <OLEDDisplayUi.h>
@@ -51,6 +53,13 @@ SHT31Sensor sht31Sensor;
int32_t EnvironmentTelemetryModule::runOnce() 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; uint32_t result = UINT32_MAX;
/* /*
Uncomment the preferences below if you want to use the module Uncomment the preferences below if you want to use the module
@@ -266,6 +275,12 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
} else { } else {
LOG_INFO("Sending packet to mesh\n"); LOG_INFO("Sending packet to mesh\n");
service.sendToMesh(p, RX_SRC_LOCAL, true); 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; return valid;
+59 -66
View File
@@ -516,34 +516,34 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
JSONObject msgPayload; JSONObject msgPayload;
JSONObject jsonObj; JSONObject jsonObj;
switch (mp->decoded.portnum) { if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
case meshtastic_PortNum_TEXT_MESSAGE_APP: { switch (mp->decoded.portnum) {
msgType = "text"; case meshtastic_PortNum_TEXT_MESSAGE_APP: {
// convert bytes to string msgType = "text";
LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size); // convert bytes to string
char payloadStr[(mp->decoded.payload.size) + 1]; LOG_DEBUG("got text message of size %u\n", mp->decoded.payload.size);
memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size); char payloadStr[(mp->decoded.payload.size) + 1];
payloadStr[mp->decoded.payload.size] = 0; // null terminated string memcpy(payloadStr, mp->decoded.payload.bytes, mp->decoded.payload.size);
// check if this is a JSON payload payloadStr[mp->decoded.payload.size] = 0; // null terminated string
JSONValue *json_value = JSON::Parse(payloadStr); // check if this is a JSON payload
if (json_value != NULL) { JSONValue *json_value = JSON::Parse(payloadStr);
LOG_INFO("text message payload is of type json\n"); if (json_value != NULL) {
// if it is, then we can just use the json object LOG_INFO("text message payload is of type json\n");
jsonObj["payload"] = json_value; // if it is, then we can just use the json object
} else { jsonObj["payload"] = json_value;
// if it isn't, then we need to create a json object } else {
// with the string as the value // if it isn't, then we need to create a json object
LOG_INFO("text message payload is of type plaintext\n"); // with the string as the value
msgPayload["text"] = new JSONValue(payloadStr); LOG_INFO("text message payload is of type plaintext\n");
jsonObj["payload"] = new JSONValue(msgPayload); msgPayload["text"] = new JSONValue(payloadStr);
jsonObj["payload"] = new JSONValue(msgPayload);
}
break;
} }
break; case meshtastic_PortNum_TELEMETRY_APP: {
} msgType = "telemetry";
case meshtastic_PortNum_TELEMETRY_APP: { meshtastic_Telemetry scratch;
msgType = "telemetry"; meshtastic_Telemetry *decoded = NULL;
meshtastic_Telemetry scratch;
meshtastic_Telemetry *decoded = NULL;
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Telemetry_msg, &scratch)) {
decoded = &scratch; decoded = &scratch;
@@ -564,14 +564,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else { } else {
LOG_ERROR("Error decoding protobuf for telemetry message!\n"); LOG_ERROR("Error decoding protobuf for telemetry message!\n");
} }
}; break;
break; }
} case meshtastic_PortNum_NODEINFO_APP: {
case meshtastic_PortNum_NODEINFO_APP: { msgType = "nodeinfo";
msgType = "nodeinfo"; meshtastic_User scratch;
meshtastic_User scratch; meshtastic_User *decoded = NULL;
meshtastic_User *decoded = NULL;
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_User_msg, &scratch)) {
decoded = &scratch; decoded = &scratch;
@@ -583,14 +581,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else { } else {
LOG_ERROR("Error decoding protobuf for nodeinfo message!\n"); LOG_ERROR("Error decoding protobuf for nodeinfo message!\n");
} }
}; break;
break; }
} case meshtastic_PortNum_POSITION_APP: {
case meshtastic_PortNum_POSITION_APP: { msgType = "position";
msgType = "position"; meshtastic_Position scratch;
meshtastic_Position scratch; meshtastic_Position *decoded = NULL;
meshtastic_Position *decoded = NULL;
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Position_msg, &scratch)) {
decoded = &scratch; decoded = &scratch;
@@ -627,15 +623,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else { } else {
LOG_ERROR("Error decoding protobuf for position message!\n"); LOG_ERROR("Error decoding protobuf for position message!\n");
} }
}; break;
break; }
} case meshtastic_PortNum_WAYPOINT_APP: {
msgType = "position";
case meshtastic_PortNum_WAYPOINT_APP: { meshtastic_Waypoint scratch;
msgType = "position"; meshtastic_Waypoint *decoded = NULL;
meshtastic_Waypoint scratch;
meshtastic_Waypoint *decoded = NULL;
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) { if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_Waypoint_msg, &scratch)) {
decoded = &scratch; decoded = &scratch;
@@ -650,14 +643,12 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else { } else {
LOG_ERROR("Error decoding protobuf for position message!\n"); LOG_ERROR("Error decoding protobuf for position message!\n");
} }
}; break;
break; }
} case meshtastic_PortNum_NEIGHBORINFO_APP: {
case meshtastic_PortNum_NEIGHBORINFO_APP: { msgType = "neighborinfo";
msgType = "neighborinfo"; meshtastic_NeighborInfo scratch;
meshtastic_NeighborInfo scratch; meshtastic_NeighborInfo *decoded = NULL;
meshtastic_NeighborInfo *decoded = NULL;
if (mp->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
memset(&scratch, 0, sizeof(scratch)); memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg, if (pb_decode_from_bytes(mp->decoded.payload.bytes, mp->decoded.payload.size, &meshtastic_NeighborInfo_msg,
&scratch)) { &scratch)) {
@@ -678,12 +669,14 @@ std::string MQTT::meshPacketToJson(meshtastic_MeshPacket *mp)
} else { } else {
LOG_ERROR("Error decoding protobuf for neighborinfo message!\n"); LOG_ERROR("Error decoding protobuf for neighborinfo message!\n");
} }
}; break;
break; }
} // add more packet types here if needed
// add more packet types here if needed default:
default: break;
break; }
} else {
LOG_WARN("Couldn't convert encrypted payload of MeshPacket to JSON\n");
} }
jsonObj["id"] = new JSONValue((uint)mp->id); jsonObj["id"] = new JSONValue((uint)mp->id);
+7 -8
View File
@@ -193,16 +193,12 @@ void cpuDeepSleep(uint32_t msecToWake)
rtc_gpio_isolate((gpio_num_t)rtcGpios[i]); rtc_gpio_isolate((gpio_num_t)rtcGpios[i]);
#endif #endif
// FIXME, disable internal rtc pullups/pulldowns on the non isolated pins. for inputs that we aren't using // 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. // 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);
#ifdef BUTTON_PIN #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 #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 #endif
#ifdef BUTTON_NEED_PULLUP #ifdef BUTTON_NEED_PULLUP
@@ -218,6 +214,9 @@ void cpuDeepSleep(uint32_t msecToWake)
#endif #endif
#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_sleep_enable_timer_wakeup(msecToWake * 1000ULL); // call expects usecs
esp_deep_sleep_start(); // TBD mA sleep current (battery) esp_deep_sleep_start(); // TBD mA sleep current (battery)
} }
+18 -8
View File
@@ -180,14 +180,24 @@ void cpuDeepSleep(uint32_t msecToWake)
digitalWrite(AQ_SET_PIN, LOW); digitalWrite(AQ_SET_PIN, LOW);
#endif #endif
#endif #endif
// FIXME, use system off mode with ram retention for key state? // Sleepy trackers or sensors can low power "sleep"
// FIXME, use non-init RAM per // Don't enter this if we're sleeping portMAX_DELAY, since that's a shutdown event
// https://devzone.nordicsemi.com/f/nordic-q-a/48919/ram-retention-settings-with-softdevice-enabled if (msecToWake != portMAX_DELAY &&
(config.device.role == meshtastic_Config_DeviceConfig_Role_TRACKER ||
auto ok = sd_power_system_off(); config.device.role == meshtastic_Config_DeviceConfig_Role_SENSOR) &&
if (ok != NRF_SUCCESS) { config.power.is_power_saving == true) {
LOG_ERROR("FIXME: Ignoring soft device (EasyDMA pending?) and forcing system-off!\n"); sd_power_mode_set(NRF_POWER_MODE_LOWPWR);
NRF_POWER->SYSTEMOFF = 1; 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 // The following code should not be run, because we are off
+44 -17
View File
@@ -95,7 +95,29 @@ void initDeepSleep()
{ {
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
bootCount++; bootCount++;
const char *reason;
wakeCause = esp_sleep_get_wakeup_cause(); 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 Not using yet because we are using wake on all buttons being low
@@ -106,7 +128,6 @@ void initDeepSleep()
#ifdef DEBUG_PORT #ifdef DEBUG_PORT
// If we booted because our timer ran out or the user pressed reset, send those as fake events // 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); RESET_REASON hwReason = rtc_get_reset_reason(0);
if (hwReason == RTCWDT_BROWN_OUT_RESET) if (hwReason == RTCWDT_BROWN_OUT_RESET)
@@ -118,9 +139,6 @@ void initDeepSleep()
if (hwReason == TG1WDT_SYS_RESET) if (hwReason == TG1WDT_SYS_RESET)
reason = "intWatchdog"; 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); LOG_INFO("Booted, wake cause %d (boot count %d), reset_reason=%s\n", wakeCause, bootCount, reason);
#endif #endif
#endif #endif
@@ -135,16 +153,18 @@ bool doPreflightSleep()
} }
/// Tell devices we are going to sleep and wait for them to handle things /// 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(); if (!skipPreflight) {
while (!doPreflightSleep()) { uint32_t now = millis();
delay(100); // Kinda yucky - wait until radio says say we can shutdown (finished in process sends/receives) 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 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); RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_SLEEP_ENTER_WAIT);
assert(0); // FIXME - for now we just restart, need to fix bug #167 assert(0); // FIXME - for now we just restart, need to fix bug #167
break; break;
}
} }
} }
@@ -155,7 +175,7 @@ static void waitEnterSleep()
notifySleep.notifyObservers(NULL); notifySleep.notifyObservers(NULL);
} }
void doDeepSleep(uint32_t msecToWake) void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false)
{ {
if (INCLUDE_vTaskSuspend && (msecToWake == portMAX_DELAY)) { if (INCLUDE_vTaskSuspend && (msecToWake == portMAX_DELAY)) {
LOG_INFO("Entering deep sleep forever\n"); 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 // not using wifi yet, but once we are this is needed to shutoff the radio hw
// esp_wifi_stop(); // esp_wifi_stop();
waitEnterSleep(); waitEnterSleep(skipPreflight);
notifyDeepSleep.notifyObservers(NULL); notifyDeepSleep.notifyObservers(NULL);
screen->doDeepSleep(); // datasheet says this will draw only 10ua screen->doDeepSleep(); // datasheet says this will draw only 10ua
@@ -173,7 +193,8 @@ void doDeepSleep(uint32_t msecToWake)
nodeDB.saveToDisk(); nodeDB.saveToDisk();
// Kill GPS power completely (even if previously we just had it in sleep mode) // 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); setLed(false);
@@ -181,7 +202,13 @@ void doDeepSleep(uint32_t msecToWake)
digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power
#endif #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 digitalWrite(VEXT_ENABLE, 1); // turn off the display power
#endif #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"); // LOG_DEBUG("Enter light sleep\n");
waitEnterSleep(); waitEnterSleep(false);
uint64_t sleepUsec = sleepMsec * 1000LL; uint64_t sleepUsec = sleepMsec * 1000LL;
+1 -1
View File
@@ -4,7 +4,7 @@
#include "Observer.h" #include "Observer.h"
#include "configuration.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 #ifdef ARCH_ESP32
#include "esp_sleep.h" #include "esp_sleep.h"
+14 -6
View File
@@ -9,9 +9,11 @@
#define ST7735_RESET 39 #define ST7735_RESET 39
#define ST7735_MISO -1 #define ST7735_MISO -1
#define ST7735_BUSY -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_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_FREQUENCY 40000000
#define SPI_READ_FREQUENCY 16000000 #define SPI_READ_FREQUENCY 16000000
#define SCREEN_ROTATE #define SCREEN_ROTATE
@@ -19,17 +21,20 @@
#define TFT_WIDTH 80 #define TFT_WIDTH 80
#define TFT_OFFSET_X 26 #define TFT_OFFSET_X 26
#define TFT_OFFSET_Y 0 #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 SCREEN_TRANSITION_FRAMERATE 1 // fps
#define DISPLAY_FORCE_SMALL_FONTS #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 BUTTON_PIN 0
#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage #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_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
#define ADC_MULTIPLIER 4.9 #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_RX_PIN
#undef GPS_TX_PIN #undef GPS_TX_PIN
@@ -37,9 +42,12 @@
#define GPS_TX_PIN 34 #define GPS_TX_PIN 34
#define PIN_GPS_RESET 35 #define PIN_GPS_RESET 35
#define PIN_GPS_PPS 36 #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_EN_ACTIVE LOW
#define GPS_RESET_MODE LOW #define GPS_RESET_MODE LOW
#define GPS_UC6580 #define GPS_UC6580
-2
View File
@@ -8,8 +8,6 @@
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost #define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
#define BUTTON_PIN 0 #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 BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
#define ADC_CHANNEL ADC1_GPIO1_CHANNEL #define ADC_CHANNEL ADC1_GPIO1_CHANNEL
#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider #define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider
+1
View File
@@ -42,3 +42,4 @@
#define GPS_UBLOX #define GPS_UBLOX
#define GPS_RX_PIN 34 #define GPS_RX_PIN 34
#define GPS_TX_PIN 12 #define GPS_TX_PIN 12
// #define GPS_DEBUG
+1 -1
View File
@@ -1,4 +1,4 @@
[VERSION] [VERSION]
major = 2 major = 2
minor = 2 minor = 2
build = 10 build = 11