mirror of
https://github.com/meshtastic/firmware.git
synced 2025-08-03 04:15:53 +00:00
Merge branch 'master' into raspi-portduino
This commit is contained in:
commit
b388f8edcd
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -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.
|
||||
|
2
.trunk/.gitignore
vendored
2
.trunk/.gitignore
vendored
@ -2,7 +2,7 @@
|
||||
*logs
|
||||
*actions
|
||||
*notifications
|
||||
*tools
|
||||
plugins
|
||||
user_trunk.yaml
|
||||
user.yaml
|
||||
tools
|
||||
|
@ -1,53 +1,53 @@
|
||||
version: 0.1
|
||||
cli:
|
||||
version: 1.13.0
|
||||
version: 1.16.2
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit fb28d593526467977cf353959a66e11373928282
|
||||
Subproject commit 175a5c97fb608b28f100551d302603efd0c22185
|
@ -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++) {
|
||||
@ -414,7 +426,7 @@ void Power::shutdown()
|
||||
#ifdef PIN_LED3
|
||||
ledOff(PIN_LED2);
|
||||
#endif
|
||||
doDeepSleep(DELAY_FOREVER);
|
||||
doDeepSleep(DELAY_FOREVER, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
156
src/gps/GPS.cpp
156
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()
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
};
|
||||
|
@ -164,11 +164,28 @@ static void drawIconScreen(const char *upperMsg, OLEDDisplay *display, OLEDDispl
|
||||
// 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)
|
||||
{
|
||||
// Draw region in upper left
|
||||
const char *region = myRegion ? myRegion->name : NULL;
|
||||
drawIconScreen(region, display, state, x, y);
|
||||
#ifdef ARCH_ESP32
|
||||
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER || wakeCause == ESP_SLEEP_WAKEUP_EXT1) {
|
||||
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)
|
||||
|
@ -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);
|
||||
|
73
src/main.cpp
73
src/main.cpp
@ -146,6 +146,25 @@ const char *getDeviceName()
|
||||
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 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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
p.longitude_i, p.altitude);
|
||||
|
||||
setLocalPosition(p);
|
||||
info->position = ConvertToPositionLite(p);
|
||||
localPosition = 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)
|
||||
|
@ -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,7 +199,7 @@ 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"
|
||||
|
@ -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. */
|
||||
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. */
|
||||
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;
|
||||
|
||||
|
@ -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,
|
||||
/* 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.
|
||||
------------------------------------------------------------------------------------------------------------------------------------------ */
|
||||
|
@ -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);
|
||||
|
@ -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,22 @@ 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;
|
||||
}
|
||||
|
||||
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)
|
||||
// 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 +65,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 +96,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(ConvertToPosition(node->position));
|
||||
}
|
||||
localPosition.seq_number++;
|
||||
|
||||
@ -148,7 +168,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 +179,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 +267,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};
|
||||
|
@ -49,6 +49,9 @@ class PositionModule : public ProtobufModule<meshtastic_Position>, 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;
|
@ -8,6 +8,8 @@
|
||||
#include "configuration.h"
|
||||
#include "main.h"
|
||||
#include "power.h"
|
||||
#include "sleep.h"
|
||||
#include "target_specific.h"
|
||||
#include <OLEDDisplay.h>
|
||||
#include <OLEDDisplayUi.h>
|
||||
|
||||
@ -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;
|
||||
|
@ -516,34 +516,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 +564,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 +581,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 +623,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 +643,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 +669,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);
|
||||
|
@ -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)
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -42,3 +42,4 @@
|
||||
#define GPS_UBLOX
|
||||
#define GPS_RX_PIN 34
|
||||
#define GPS_TX_PIN 12
|
||||
// #define GPS_DEBUG
|
@ -1,4 +1,4 @@
|
||||
[VERSION]
|
||||
major = 2
|
||||
minor = 2
|
||||
build = 10
|
||||
build = 11
|
||||
|
Loading…
Reference in New Issue
Block a user