mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-25 11:17:25 +00:00
Compare commits
30 Commits
evicted-ag
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57a3ff8dfc | ||
|
|
6cff13623f | ||
|
|
b312f226b4 | ||
|
|
7221fc4d4b | ||
|
|
6b88d37b73 | ||
|
|
d407ec1975 | ||
|
|
6d6a0734b0 | ||
|
|
0157a769c3 | ||
|
|
73932dd1c3 | ||
|
|
bc2abf3db4 | ||
|
|
073eb2c672 | ||
|
|
4744010295 | ||
|
|
d8d02cd6ec | ||
|
|
3e3299f549 | ||
|
|
eefc08087d | ||
|
|
fb6d199d36 | ||
|
|
fb3bf783dd | ||
|
|
fc268d43d0 | ||
|
|
c38aff7e52 | ||
|
|
7d4600f8c2 | ||
|
|
ff50ba4002 | ||
|
|
5c401b8e34 | ||
|
|
c96ebf15fd | ||
|
|
3e4239daf8 | ||
|
|
ab97c0126f | ||
|
|
d34d694731 | ||
|
|
e545897d4e | ||
|
|
caa6ec0e8a | ||
|
|
afbd9e2180 | ||
|
|
64116cd0d3 |
@@ -9,14 +9,14 @@ plugins:
|
|||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.497
|
- checkov@3.2.497
|
||||||
- renovate@42.81.8
|
- renovate@42.84.2
|
||||||
- prettier@3.8.0
|
- prettier@3.8.0
|
||||||
- trufflehog@3.92.4
|
- trufflehog@3.92.5
|
||||||
- yamllint@1.38.0
|
- yamllint@1.38.0
|
||||||
- bandit@1.9.2
|
- bandit@1.9.3
|
||||||
- trivy@0.68.2
|
- trivy@0.68.2
|
||||||
- taplo@0.10.0
|
- taplo@0.10.0
|
||||||
- ruff@0.14.11
|
- ruff@0.14.13
|
||||||
- isort@7.0.0
|
- isort@7.0.0
|
||||||
- markdownlint@0.47.0
|
- markdownlint@0.47.0
|
||||||
- oxipng@10.0.0
|
- oxipng@10.0.0
|
||||||
@@ -26,7 +26,7 @@ lint:
|
|||||||
- hadolint@2.14.0
|
- hadolint@2.14.0
|
||||||
- shfmt@3.6.0
|
- shfmt@3.6.0
|
||||||
- shellcheck@0.11.0
|
- shellcheck@0.11.0
|
||||||
- black@25.12.0
|
- black@26.1.0
|
||||||
- git-diff-check
|
- git-diff-check
|
||||||
- gitleaks@8.30.0
|
- gitleaks@8.30.0
|
||||||
- clang-format@16.0.3
|
- clang-format@16.0.3
|
||||||
|
|||||||
@@ -32,6 +32,19 @@ if ! command -v jq >/dev/null 2>&1; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# esptool v5 supports commands with dashes and deprecates commands with
|
||||||
|
# underscores. Prior versions only support commands with underscores
|
||||||
|
if ${ESPTOOL_CMD} | grep --quiet write-flash
|
||||||
|
then
|
||||||
|
ESPTOOL_WRITE_FLASH=write-flash
|
||||||
|
ESPTOOL_ERASE_FLASH=erase-flash
|
||||||
|
ESPTOOL_READ_FLASH_STATUS=read-flash-status
|
||||||
|
else
|
||||||
|
ESPTOOL_WRITE_FLASH=write_flash
|
||||||
|
ESPTOOL_ERASE_FLASH=erase_flash
|
||||||
|
ESPTOOL_READ_FLASH_STATUS=read_flash_status
|
||||||
|
fi
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Usage info
|
# Usage info
|
||||||
@@ -83,8 +96,8 @@ while [ $# -gt 0 ]; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [[ $BPS_RESET == true ]]; then
|
if [[ $BPS_RESET == true ]]; then
|
||||||
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset read_flash_status
|
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset ${ESPTOOL_READ_FLASH_STATUS}
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[ -z "$FILENAME" ] && [ -n "$1" ] && {
|
[ -z "$FILENAME" ] && [ -n "$1" ] && {
|
||||||
@@ -144,12 +157,12 @@ if [[ -f "$FILENAME" && "$FILENAME" == *.factory.bin ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
echo "Trying to flash ${FILENAME}, but first erasing and writing system information"
|
||||||
$ESPTOOL_CMD erase-flash
|
$ESPTOOL_CMD ${ESPTOOL_ERASE_FLASH}
|
||||||
$ESPTOOL_CMD write-flash $FIRMWARE_OFFSET "${FILENAME}"
|
$ESPTOOL_CMD ${ESPTOOL_WRITE_FLASH} $FIRMWARE_OFFSET "${FILENAME}"
|
||||||
echo "Trying to flash ${OTAFILE} at offset ${OTA_OFFSET}"
|
echo "Trying to flash ${OTAFILE} at offset ${OTA_OFFSET}"
|
||||||
$ESPTOOL_CMD write_flash $OTA_OFFSET "${OTAFILE}"
|
$ESPTOOL_CMD ${ESPTOOL_WRITE_FLASH} $OTA_OFFSET "${OTAFILE}"
|
||||||
echo "Trying to flash ${SPIFFSFILE}, at offset ${OFFSET}"
|
echo "Trying to flash ${SPIFFSFILE}, at offset ${OFFSET}"
|
||||||
$ESPTOOL_CMD write_flash $OFFSET "${SPIFFSFILE}"
|
$ESPTOOL_CMD ${ESPTOOL_WRITE_FLASH} $OFFSET "${SPIFFSFILE}"
|
||||||
|
|
||||||
else
|
else
|
||||||
show_help
|
show_help
|
||||||
|
|||||||
@@ -20,6 +20,17 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# esptool v5 supports commands with dashes and deprecates commands with
|
||||||
|
# underscores. Prior versions only support commands with underscores
|
||||||
|
if ${ESPTOOL_CMD} | grep --quiet write-flash
|
||||||
|
then
|
||||||
|
ESPTOOL_WRITE_FLASH=write-flash
|
||||||
|
ESPTOOL_READ_FLASH_STATUS=read-flash-status
|
||||||
|
else
|
||||||
|
ESPTOOL_WRITE_FLASH=write_flash
|
||||||
|
ESPTOOL_READ_FLASH_STATUS=read_flash_status
|
||||||
|
fi
|
||||||
|
|
||||||
# Usage info
|
# Usage info
|
||||||
show_help() {
|
show_help() {
|
||||||
cat << EOF
|
cat << EOF
|
||||||
@@ -69,7 +80,7 @@ done
|
|||||||
shift "$((OPTIND-1))"
|
shift "$((OPTIND-1))"
|
||||||
|
|
||||||
if [ "$CHANGE_MODE" = true ]; then
|
if [ "$CHANGE_MODE" = true ]; then
|
||||||
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset read_flash_status
|
$ESPTOOL_CMD --baud $RESET_BAUD --after no_reset ${ESPTOOL_READ_FLASH_STATUS}
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -80,7 +91,7 @@ fi
|
|||||||
|
|
||||||
if [[ -f "$FILENAME" && "$FILENAME" != *.factory.bin ]]; then
|
if [[ -f "$FILENAME" && "$FILENAME" != *.factory.bin ]]; then
|
||||||
echo "Trying to flash update ${FILENAME}"
|
echo "Trying to flash update ${FILENAME}"
|
||||||
$ESPTOOL_CMD --baud $FLASH_BAUD write-flash $UPDATE_OFFSET "${FILENAME}"
|
$ESPTOOL_CMD --baud $FLASH_BAUD ${ESPTOOL_WRITE_FLASH} $UPDATE_OFFSET "${FILENAME}"
|
||||||
else
|
else
|
||||||
show_help
|
show_help
|
||||||
echo "Invalid file: ${FILENAME}"
|
echo "Invalid file: ${FILENAME}"
|
||||||
|
|||||||
@@ -87,6 +87,9 @@
|
|||||||
</screenshots>
|
</screenshots>
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.7.19" date="2026-01-22">
|
||||||
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.19</url>
|
||||||
|
</release>
|
||||||
<release version="2.7.18" date="2026-01-02">
|
<release version="2.7.18" date="2026-01-02">
|
||||||
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.18</url>
|
<url type="details">https://github.com/meshtastic/firmware/releases?q=tag%3Av2.7.18</url>
|
||||||
</release>
|
</release>
|
||||||
|
|||||||
50
boards/minimesh_lite.json
Normal file
50
boards/minimesh_lite.json
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"build": {
|
||||||
|
"arduino": {
|
||||||
|
"ldscript": "nrf52840_s140_v6.ld"
|
||||||
|
},
|
||||||
|
"core": "nRF5",
|
||||||
|
"cpu": "cortex-m4",
|
||||||
|
"extra_flags": "-DMINIMESH_LITE -DNRF52840_XXAA",
|
||||||
|
"f_cpu": "64000000L",
|
||||||
|
"hwids": [
|
||||||
|
["0x239A", "0x8029"],
|
||||||
|
["0x239A", "0x0029"],
|
||||||
|
["0x239A", "0x002A"]
|
||||||
|
],
|
||||||
|
"usb_product": "Minimesh Lite",
|
||||||
|
"mcu": "nrf52840",
|
||||||
|
"variant": "dls_Minimesh_Lite",
|
||||||
|
"bsp": {
|
||||||
|
"name": "adafruit"
|
||||||
|
},
|
||||||
|
"softdevice": {
|
||||||
|
"sd_flags": "-DS140",
|
||||||
|
"sd_name": "s140",
|
||||||
|
"sd_version": "6.1.1",
|
||||||
|
"sd_fwid": "0x00B6"
|
||||||
|
},
|
||||||
|
"bootloader": {
|
||||||
|
"settings_addr": "0xFF000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"connectivity": ["bluetooth"],
|
||||||
|
"debug": {
|
||||||
|
"jlink_device": "nRF52840_xxAA",
|
||||||
|
"svd_path": "nrf52840.svd"
|
||||||
|
},
|
||||||
|
"frameworks": ["arduino"],
|
||||||
|
"name": "Minimesh Lite",
|
||||||
|
"upload": {
|
||||||
|
"maximum_ram_size": 248832,
|
||||||
|
"maximum_size": 815104,
|
||||||
|
"speed": 115200,
|
||||||
|
"protocol": "nrfutil",
|
||||||
|
"protocols": ["nrfutil", "jlink", "nrfjprog", "stlink"],
|
||||||
|
"use_1200bps_touch": true,
|
||||||
|
"require_upload_port": true,
|
||||||
|
"wait_for_upload_port": true
|
||||||
|
},
|
||||||
|
"url": "https://deeplabstudio.com",
|
||||||
|
"vendor": "Deeplab Studio"
|
||||||
|
}
|
||||||
6
debian/changelog
vendored
6
debian/changelog
vendored
@@ -1,3 +1,9 @@
|
|||||||
|
meshtasticd (2.7.19.0) unstable; urgency=medium
|
||||||
|
|
||||||
|
* Version 2.7.19
|
||||||
|
|
||||||
|
-- GitHub Actions <github-actions[bot]@users.noreply.github.com> Thu, 22 Jan 2026 22:17:40 +0000
|
||||||
|
|
||||||
meshtasticd (2.7.18.0) unstable; urgency=medium
|
meshtasticd (2.7.18.0) unstable; urgency=medium
|
||||||
|
|
||||||
* Version 2.7.18
|
* Version 2.7.18
|
||||||
|
|||||||
@@ -43,13 +43,11 @@ class Esp32C3ExceptionDecoder(DeviceMonitorFilterBase):
|
|||||||
self.enabled = self.setup_paths()
|
self.enabled = self.setup_paths()
|
||||||
|
|
||||||
if self.config.get("env:" + self.environment, "build_type") != "debug":
|
if self.config.get("env:" + self.environment, "build_type") != "debug":
|
||||||
print(
|
print("""
|
||||||
"""
|
|
||||||
Please build project in debug configuration to get more details about an exception.
|
Please build project in debug configuration to get more details about an exception.
|
||||||
See https://docs.platformio.org/page/projectconf/build_configurations.html
|
See https://docs.platformio.org/page/projectconf/build_configurations.html
|
||||||
|
|
||||||
"""
|
""")
|
||||||
)
|
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ lib_deps =
|
|||||||
[device-ui_base]
|
[device-ui_base]
|
||||||
lib_deps =
|
lib_deps =
|
||||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||||
https://github.com/meshtastic/device-ui/archive/5a870c623a4e9ab7a7abe3d02950536f107d1a31.zip
|
https://github.com/meshtastic/device-ui/archive/613c0953313bbd236f4ddc5ede447e9edf8e890a.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
@@ -212,3 +212,30 @@ lib_deps =
|
|||||||
sensirion/Sensirion Core@0.7.2
|
sensirion/Sensirion Core@0.7.2
|
||||||
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
||||||
sensirion/Sensirion I2C SCD4x@1.1.0
|
sensirion/Sensirion I2C SCD4x@1.1.0
|
||||||
|
; Same as environmental_extra but without BSEC (saves ~3.5KB DRAM for original ESP32 targets)
|
||||||
|
[environmental_extra_no_bsec]
|
||||||
|
lib_deps =
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit BMP3XX packageName=adafruit/library/Adafruit BMP3XX Library
|
||||||
|
adafruit/Adafruit BMP3XX Library@2.1.6
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit MAX1704X packageName=adafruit/library/Adafruit MAX1704X
|
||||||
|
adafruit/Adafruit MAX1704X@1.0.3
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit SHTC3 packageName=adafruit/library/Adafruit SHTC3 Library
|
||||||
|
adafruit/Adafruit SHTC3 Library@1.0.2
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit LPS2X packageName=adafruit/library/Adafruit LPS2X
|
||||||
|
adafruit/Adafruit LPS2X@2.0.6
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit SHT31 packageName=adafruit/library/Adafruit SHT31 Library
|
||||||
|
adafruit/Adafruit SHT31 Library@2.2.2
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit VEML7700 packageName=adafruit/library/Adafruit VEML7700 Library
|
||||||
|
adafruit/Adafruit VEML7700 Library@2.1.6
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit SHT4x packageName=adafruit/library/Adafruit SHT4x Library
|
||||||
|
adafruit/Adafruit SHT4x Library@1.0.5
|
||||||
|
# renovate: datasource=custom.pio depName=SparkFun Qwiic Scale NAU7802 packageName=sparkfun/library/SparkFun Qwiic Scale NAU7802 Arduino Library
|
||||||
|
sparkfun/SparkFun Qwiic Scale NAU7802 Arduino Library@1.0.6
|
||||||
|
# renovate: datasource=custom.pio depName=ClosedCube OPT3001 packageName=closedcube/library/ClosedCube OPT3001
|
||||||
|
closedcube/ClosedCube OPT3001@1.1.2
|
||||||
|
# renovate: datasource=git-refs depName=meshtastic-DFRobot_LarkWeatherStation packageName=https://github.com/meshtastic/DFRobot_LarkWeatherStation gitBranch=master
|
||||||
|
https://github.com/meshtastic/DFRobot_LarkWeatherStation/archive/4de3a9cadef0f6a5220a8a906cf9775b02b0040d.zip
|
||||||
|
# renovate: datasource=custom.pio depName=Sensirion Core packageName=sensirion/library/Sensirion Core
|
||||||
|
sensirion/Sensirion Core@0.7.2
|
||||||
|
# renovate: datasource=custom.pio depName=Sensirion I2C SCD4x packageName=sensirion/library/Sensirion I2C SCD4x
|
||||||
|
sensirion/Sensirion I2C SCD4x@1.1.0
|
||||||
Submodule protobufs updated: 4b9f104a18...77c8329a59
204
src/Power.cpp
204
src/Power.cpp
@@ -1,11 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* @file Power.cpp
|
* @file Power.cpp
|
||||||
* @brief This file contains the implementation of the Power class, which is responsible for managing power-related functionality
|
* @brief This file contains the implementation of the Power class, which is
|
||||||
* of the device. It includes battery level sensing, power management unit (PMU) control, and power state machine management. The
|
* responsible for managing power-related functionality of the device. It
|
||||||
* Power class is used by the main device class to manage power-related functionality.
|
* includes battery level sensing, power management unit (PMU) control, and
|
||||||
|
* power state machine management. The Power class is used by the main device
|
||||||
|
* class to manage power-related functionality.
|
||||||
*
|
*
|
||||||
* The file also includes implementations of various battery level sensors, such as the AnalogBatteryLevel class, which assumes
|
* The file also includes implementations of various battery level sensors, such
|
||||||
* the battery voltage is attached via a voltage-divider to an analog input.
|
* as the AnalogBatteryLevel class, which assumes the battery voltage is
|
||||||
|
* attached via a voltage-divider to an analog input.
|
||||||
*
|
*
|
||||||
* This file is part of the Meshtastic project.
|
* This file is part of the Meshtastic project.
|
||||||
* For more information, see: https://meshtastic.org/
|
* For more information, see: https://meshtastic.org/
|
||||||
@@ -19,6 +22,7 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
|
#include "power/PowerHAL.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
|
|
||||||
#if defined(ARCH_PORTDUINO)
|
#if defined(ARCH_PORTDUINO)
|
||||||
@@ -171,22 +175,12 @@ Power *power;
|
|||||||
|
|
||||||
using namespace meshtastic;
|
using namespace meshtastic;
|
||||||
|
|
||||||
#ifndef AREF_VOLTAGE
|
// NRF52 has AREF_VOLTAGE defined in architecture.h but
|
||||||
#if defined(ARCH_NRF52)
|
// make sure it's included. If something is wrong with NRF52
|
||||||
/*
|
// definition - compilation will fail on missing definition
|
||||||
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
|
#if !defined(AREF_VOLTAGE) && !defined(ARCH_NRF52)
|
||||||
* 1/3, 1/2 or 1, meaning 3.6, 3.0, 2.4, 1.8, 1.2 or 0.6V for the ADC levels.
|
|
||||||
*
|
|
||||||
* External Reference is VDD/4, with an adjustable gain of 1, 2 or 4, meaning
|
|
||||||
* VDD/4, VDD/2 or VDD for the ADC levels.
|
|
||||||
*
|
|
||||||
* Default settings are internal reference with 1/6 gain (GND..3.6V ADC range)
|
|
||||||
*/
|
|
||||||
#define AREF_VOLTAGE 3.6
|
|
||||||
#else
|
|
||||||
#define AREF_VOLTAGE 3.3
|
#define AREF_VOLTAGE 3.3
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this board has a battery level sensor, set this to a valid implementation
|
* If this board has a battery level sensor, set this to a valid implementation
|
||||||
@@ -233,7 +227,8 @@ static void battery_adcDisable()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple battery level sensor that assumes the battery voltage is attached via a voltage-divider to an analog input
|
* A simple battery level sensor that assumes the battery voltage is attached
|
||||||
|
* via a voltage-divider to an analog input
|
||||||
*/
|
*/
|
||||||
class AnalogBatteryLevel : public HasBatteryLevel
|
class AnalogBatteryLevel : public HasBatteryLevel
|
||||||
{
|
{
|
||||||
@@ -311,7 +306,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
|
|
||||||
#ifndef BATTERY_SENSE_SAMPLES
|
#ifndef BATTERY_SENSE_SAMPLES
|
||||||
#define BATTERY_SENSE_SAMPLES \
|
#define BATTERY_SENSE_SAMPLES \
|
||||||
15 // Set the number of samples, it has an effect of increasing sensitivity in complex electromagnetic environment.
|
15 // Set the number of samples, it has an effect of increasing sensitivity in
|
||||||
|
// complex electromagnetic environment.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef BATTERY_PIN
|
#ifdef BATTERY_PIN
|
||||||
@@ -341,7 +337,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
battery_adcDisable();
|
battery_adcDisable();
|
||||||
|
|
||||||
if (!initial_read_done) {
|
if (!initial_read_done) {
|
||||||
// Flush the smoothing filter with an ADC reading, if the reading is plausibly correct
|
// Flush the smoothing filter with an ADC reading, if the reading is
|
||||||
|
// plausibly correct
|
||||||
if (scaled > last_read_value)
|
if (scaled > last_read_value)
|
||||||
last_read_value = scaled;
|
last_read_value = scaled;
|
||||||
initial_read_done = true;
|
initial_read_done = true;
|
||||||
@@ -350,8 +347,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF
|
last_read_value += (scaled - last_read_value) * 0.5; // Virtual LPF
|
||||||
}
|
}
|
||||||
|
|
||||||
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u", BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t)
|
// LOG_DEBUG("battery gpio %d raw val=%u scaled=%u filtered=%u",
|
||||||
// (last_read_value));
|
// BATTERY_PIN, raw, (uint32_t)(scaled), (uint32_t) (last_read_value));
|
||||||
}
|
}
|
||||||
return last_read_value;
|
return last_read_value;
|
||||||
#endif // BATTERY_PIN
|
#endif // BATTERY_PIN
|
||||||
@@ -420,7 +417,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
/**
|
/**
|
||||||
* return true if there is a battery installed in this unit
|
* return true if there is a battery installed in this unit
|
||||||
*/
|
*/
|
||||||
// if we have a integrated device with a battery, we can assume that the battery is always connected
|
// if we have a integrated device with a battery, we can assume that the
|
||||||
|
// battery is always connected
|
||||||
#ifdef BATTERY_IMMUTABLE
|
#ifdef BATTERY_IMMUTABLE
|
||||||
virtual bool isBatteryConnect() override { return true; }
|
virtual bool isBatteryConnect() override { return true; }
|
||||||
#elif defined(ADC_V)
|
#elif defined(ADC_V)
|
||||||
@@ -441,10 +439,10 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
|
virtual bool isBatteryConnect() override { return getBatteryPercent() != -1; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
/// If we see a battery voltage higher than physics allows - assume charger is
|
||||||
/// in power
|
/// pumping in power On some boards we don't have the power management chip
|
||||||
/// On some boards we don't have the power management chip (like AXPxxxx)
|
/// (like AXPxxxx) so we use EXT_PWR_DETECT GPIO pin to detect external power
|
||||||
/// so we use EXT_PWR_DETECT GPIO pin to detect external power source
|
/// source
|
||||||
virtual bool isVbusIn() override
|
virtual bool isVbusIn() override
|
||||||
{
|
{
|
||||||
#ifdef EXT_PWR_DETECT
|
#ifdef EXT_PWR_DETECT
|
||||||
@@ -461,8 +459,12 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
}
|
}
|
||||||
// if it's not HIGH - check the battery
|
// if it's not HIGH - check the battery
|
||||||
#endif
|
#endif
|
||||||
#elif defined(MUZI_BASE)
|
|
||||||
return NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk;
|
// technically speaking this should work for all(?) NRF52 boards
|
||||||
|
// but needs testing across multiple devices. NRF52 USB would not even work if
|
||||||
|
// VBUS was not properly connected and detected by the CPU
|
||||||
|
#elif defined(MUZI_BASE) || defined(PROMICRO_DIY_TCXO)
|
||||||
|
return powerHAL_isVBUSConnected();
|
||||||
#endif
|
#endif
|
||||||
return getBattVoltage() > chargingVolt;
|
return getBattVoltage() > chargingVolt;
|
||||||
}
|
}
|
||||||
@@ -485,8 +487,9 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
#else
|
#else
|
||||||
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(DISABLE_INA_CHARGING_DETECTION)
|
#if HAS_TELEMETRY && !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && !defined(DISABLE_INA_CHARGING_DETECTION)
|
||||||
if (hasINA()) {
|
if (hasINA()) {
|
||||||
// get current flow from INA sensor - negative value means power flowing into the battery
|
// get current flow from INA sensor - negative value means power flowing
|
||||||
// default assuming BATTERY+ <--> INA_VIN+ <--> SHUNT RESISTOR <--> INA_VIN- <--> LOAD
|
// into the battery default assuming BATTERY+ <--> INA_VIN+ <--> SHUNT
|
||||||
|
// RESISTOR <--> INA_VIN- <--> LOAD
|
||||||
LOG_DEBUG("Using INA on I2C addr 0x%x for charging detection", config.power.device_battery_ina_address);
|
LOG_DEBUG("Using INA on I2C addr 0x%x for charging detection", config.power.device_battery_ina_address);
|
||||||
#if defined(INA_CHARGING_DETECTION_INVERT)
|
#if defined(INA_CHARGING_DETECTION_INVERT)
|
||||||
return getINACurrent() > 0;
|
return getINACurrent() > 0;
|
||||||
@@ -502,8 +505,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// If we see a battery voltage higher than physics allows - assume charger is pumping
|
/// If we see a battery voltage higher than physics allows - assume charger is
|
||||||
/// in power
|
/// pumping in power
|
||||||
|
|
||||||
/// For heltecs with no battery connected, the measured voltage is 2204, so
|
/// For heltecs with no battery connected, the measured voltage is 2204, so
|
||||||
// need to be higher than that, in this case is 2500mV (3000-500)
|
// need to be higher than that, in this case is 2500mV (3000-500)
|
||||||
@@ -512,7 +515,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
|
|||||||
const float noBatVolt = (OCV[NUM_OCV_POINTS - 1] - 500) * NUM_CELLS;
|
const float noBatVolt = (OCV[NUM_OCV_POINTS - 1] - 500) * NUM_CELLS;
|
||||||
// Start value from minimum voltage for the filter to not start from 0
|
// Start value from minimum voltage for the filter to not start from 0
|
||||||
// that could trigger some events.
|
// that could trigger some events.
|
||||||
// This value is over-written by the first ADC reading, it the voltage seems reasonable.
|
// This value is over-written by the first ADC reading, it the voltage seems
|
||||||
|
// reasonable.
|
||||||
bool initial_read_done = false;
|
bool initial_read_done = false;
|
||||||
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
|
float last_read_value = (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS);
|
||||||
uint32_t last_read_time_ms = 0;
|
uint32_t last_read_time_ms = 0;
|
||||||
@@ -654,7 +658,8 @@ bool Power::analogInit()
|
|||||||
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
#ifdef CONFIG_IDF_TARGET_ESP32S3
|
||||||
// ESP32S3
|
// ESP32S3
|
||||||
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP_FIT) {
|
else if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP_FIT) {
|
||||||
LOG_INFO("ADC config based on Two Point values and fitting curve coefficients stored in eFuse");
|
LOG_INFO("ADC config based on Two Point values and fitting curve "
|
||||||
|
"coefficients stored in eFuse");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else {
|
else {
|
||||||
@@ -662,13 +667,7 @@ bool Power::analogInit()
|
|||||||
}
|
}
|
||||||
#endif // ARCH_ESP32
|
#endif // ARCH_ESP32
|
||||||
|
|
||||||
#ifdef ARCH_NRF52
|
// NRF52 ADC init moved to powerHAL_init in nrf52 platform
|
||||||
#ifdef VBAT_AR_INTERNAL
|
|
||||||
analogReference(VBAT_AR_INTERNAL);
|
|
||||||
#else
|
|
||||||
analogReference(AR_INTERNAL); // 3.6V
|
|
||||||
#endif
|
|
||||||
#endif // ARCH_NRF52
|
|
||||||
|
|
||||||
#ifndef ARCH_ESP32
|
#ifndef ARCH_ESP32
|
||||||
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS);
|
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS);
|
||||||
@@ -723,6 +722,16 @@ bool Power::setup()
|
|||||||
runASAP = true;
|
runASAP = true;
|
||||||
},
|
},
|
||||||
CHANGE);
|
CHANGE);
|
||||||
|
#endif
|
||||||
|
#ifdef EXT_CHRG_DETECT
|
||||||
|
attachInterrupt(
|
||||||
|
EXT_CHRG_DETECT,
|
||||||
|
[]() {
|
||||||
|
power->setIntervalFromNow(0);
|
||||||
|
runASAP = true;
|
||||||
|
BaseType_t higherWake = 0;
|
||||||
|
},
|
||||||
|
CHANGE);
|
||||||
#endif
|
#endif
|
||||||
enabled = found;
|
enabled = found;
|
||||||
low_voltage_counter = 0;
|
low_voltage_counter = 0;
|
||||||
@@ -769,7 +778,8 @@ void Power::reboot()
|
|||||||
HAL_NVIC_SystemReset();
|
HAL_NVIC_SystemReset();
|
||||||
#else
|
#else
|
||||||
rebootAtMsec = -1;
|
rebootAtMsec = -1;
|
||||||
LOG_WARN("FIXME implement reboot for this platform. Note that some settings require a restart to be applied");
|
LOG_WARN("FIXME implement reboot for this platform. Note that some settings "
|
||||||
|
"require a restart to be applied");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -779,9 +789,12 @@ void Power::shutdown()
|
|||||||
#if HAS_SCREEN
|
#if HAS_SCREEN
|
||||||
if (screen) {
|
if (screen) {
|
||||||
#ifdef T_DECK_PRO
|
#ifdef T_DECK_PRO
|
||||||
screen->showSimpleBanner("Device is powered off.\nConnect USB to start!", 0); // T-Deck Pro has no power button
|
screen->showSimpleBanner("Device is powered off.\nConnect USB to start!",
|
||||||
|
0); // T-Deck Pro has no power button
|
||||||
#elif defined(USE_EINK)
|
#elif defined(USE_EINK)
|
||||||
screen->showSimpleBanner("Shutting Down...", 2250); // dismiss after 3 seconds to avoid the banner on the sleep screen
|
screen->showSimpleBanner("Shutting Down...",
|
||||||
|
2250); // dismiss after 3 seconds to avoid the
|
||||||
|
// banner on the sleep screen
|
||||||
#else
|
#else
|
||||||
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
|
screen->showSimpleBanner("Shutting Down...", 0); // stays on screen
|
||||||
#endif
|
#endif
|
||||||
@@ -820,7 +833,8 @@ void Power::readPowerStatus()
|
|||||||
int32_t batteryVoltageMv = -1; // Assume unknown
|
int32_t batteryVoltageMv = -1; // Assume unknown
|
||||||
int8_t batteryChargePercent = -1;
|
int8_t batteryChargePercent = -1;
|
||||||
OptionalBool usbPowered = OptUnknown;
|
OptionalBool usbPowered = OptUnknown;
|
||||||
OptionalBool hasBattery = OptUnknown; // These must be static because NRF_APM code doesn't run every time
|
OptionalBool hasBattery = OptUnknown; // These must be static because NRF_APM
|
||||||
|
// code doesn't run every time
|
||||||
OptionalBool isChargingNow = OptUnknown;
|
OptionalBool isChargingNow = OptUnknown;
|
||||||
|
|
||||||
if (batteryLevel) {
|
if (batteryLevel) {
|
||||||
@@ -833,9 +847,10 @@ void Power::readPowerStatus()
|
|||||||
if (batteryLevel->getBatteryPercent() >= 0) {
|
if (batteryLevel->getBatteryPercent() >= 0) {
|
||||||
batteryChargePercent = batteryLevel->getBatteryPercent();
|
batteryChargePercent = batteryLevel->getBatteryPercent();
|
||||||
} else {
|
} else {
|
||||||
// If the AXP192 returns a percentage less than 0, the feature is either not supported or there is an error
|
// If the AXP192 returns a percentage less than 0, the feature is either
|
||||||
// In that case, we compute an estimate of the charge percent based on open circuit voltage table defined
|
// not supported or there is an error In that case, we compute an
|
||||||
// in power.h
|
// estimate of the charge percent based on open circuit voltage table
|
||||||
|
// defined in power.h
|
||||||
batteryChargePercent = clamp((int)(((batteryVoltageMv - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS)) * 1e2) /
|
batteryChargePercent = clamp((int)(((batteryVoltageMv - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS)) * 1e2) /
|
||||||
((OCV[0] * NUM_CELLS) - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS))),
|
((OCV[0] * NUM_CELLS) - (OCV[NUM_OCV_POINTS - 1] * NUM_CELLS))),
|
||||||
0, 100);
|
0, 100);
|
||||||
@@ -843,12 +858,12 @@ void Power::readPowerStatus()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: IMO we shouldn't be littering our code with all these ifdefs. Way better instead to make a Nrf52IsUsbPowered subclass
|
// FIXME: IMO we shouldn't be littering our code with all these ifdefs. Way
|
||||||
// (which shares a superclass with the BatteryLevel stuff)
|
// better instead to make a Nrf52IsUsbPowered subclass (which shares a
|
||||||
// that just provides a few methods. But in the interest of fixing this bug I'm going to follow current
|
// superclass with the BatteryLevel stuff) that just provides a few methods. But
|
||||||
// practice.
|
// in the interest of fixing this bug I'm going to follow current practice.
|
||||||
#ifdef NRF_APM // Section of code detects USB power on the RAK4631 and updates the power states. Takes 20 seconds or so to detect
|
#ifdef NRF_APM // Section of code detects USB power on the RAK4631 and updates
|
||||||
// changes.
|
// the power states. Takes 20 seconds or so to detect changes.
|
||||||
|
|
||||||
nrfx_power_usb_state_t nrf_usb_state = nrfx_power_usbstatus_get();
|
nrfx_power_usb_state_t nrf_usb_state = nrfx_power_usbstatus_get();
|
||||||
// LOG_DEBUG("NRF Power %d", nrf_usb_state);
|
// LOG_DEBUG("NRF Power %d", nrf_usb_state);
|
||||||
@@ -922,8 +937,9 @@ void Power::readPowerStatus()
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If we have a battery at all and it is less than 0%, force deep sleep if we have more than 10 low readings in
|
// If we have a battery at all and it is less than 0%, force deep sleep if we
|
||||||
// a row. NOTE: min LiIon/LiPo voltage is 2.0 to 2.5V, current OCV min is set to 3100 that is large enough.
|
// have more than 10 low readings in a row. NOTE: min LiIon/LiPo voltage
|
||||||
|
// is 2.0 to 2.5V, current OCV min is set to 3100 that is large enough.
|
||||||
//
|
//
|
||||||
|
|
||||||
if (batteryLevel && powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
|
if (batteryLevel && powerStatus2.getHasBattery() && !powerStatus2.getHasUSB()) {
|
||||||
@@ -945,8 +961,8 @@ int32_t Power::runOnce()
|
|||||||
readPowerStatus();
|
readPowerStatus();
|
||||||
|
|
||||||
#ifdef HAS_PMU
|
#ifdef HAS_PMU
|
||||||
// WE no longer use the IRQ line to wake the CPU (due to false wakes from sleep), but we do poll
|
// WE no longer use the IRQ line to wake the CPU (due to false wakes from
|
||||||
// the IRQ status by reading the registers over I2C
|
// sleep), but we do poll the IRQ status by reading the registers over I2C
|
||||||
if (PMU) {
|
if (PMU) {
|
||||||
|
|
||||||
PMU->getIrqStatus();
|
PMU->getIrqStatus();
|
||||||
@@ -988,7 +1004,8 @@ int32_t Power::runOnce()
|
|||||||
PMU->clearIrqStatus();
|
PMU->clearIrqStatus();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Only read once every 20 seconds once the power status for the app has been initialized
|
// Only read once every 20 seconds once the power status for the app has been
|
||||||
|
// initialized
|
||||||
return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME;
|
return (statusHandler && statusHandler->isInitialized()) ? (1000 * 20) : RUN_SAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -996,10 +1013,12 @@ int32_t Power::runOnce()
|
|||||||
* Init the power manager chip
|
* Init the power manager chip
|
||||||
*
|
*
|
||||||
* axp192 power
|
* axp192 power
|
||||||
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose comms to the axp192 because the OLED and the
|
DCDC1 0.7-3.5V @ 1200mA max -> OLED // If you turn this off you'll lose
|
||||||
axp192 share the same i2c bus, instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max -> ESP32 (keep this
|
comms to the axp192 because the OLED and the axp192 share the same i2c bus,
|
||||||
on!) LDO1 30mA -> charges GPS backup battery // charges the tiny J13 battery by the GPS to power the GPS ram (for a couple of
|
instead use ssd1306 sleep mode DCDC2 -> unused DCDC3 0.7-3.5V @ 700mA max ->
|
||||||
days), can not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
ESP32 (keep this on!) LDO1 30mA -> charges GPS backup battery // charges the
|
||||||
|
tiny J13 battery by the GPS to power the GPS ram (for a couple of days), can
|
||||||
|
not be turned off LDO2 200mA -> LORA LDO3 200mA -> GPS
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
bool Power::axpChipInit()
|
bool Power::axpChipInit()
|
||||||
@@ -1044,9 +1063,10 @@ bool Power::axpChipInit()
|
|||||||
|
|
||||||
if (!PMU) {
|
if (!PMU) {
|
||||||
/*
|
/*
|
||||||
* In XPowersLib, if the XPowersAXPxxx object is released, Wire.end() will be called at the same time.
|
* In XPowersLib, if the XPowersAXPxxx object is released, Wire.end() will
|
||||||
* In order not to affect other devices, if the initialization of the PMU fails, Wire needs to be re-initialized once,
|
* be called at the same time. In order not to affect other devices, if the
|
||||||
* if there are multiple devices sharing the bus.
|
* initialization of the PMU fails, Wire needs to be re-initialized once, if
|
||||||
|
* there are multiple devices sharing the bus.
|
||||||
* * */
|
* * */
|
||||||
#ifndef PMU_USE_WIRE1
|
#ifndef PMU_USE_WIRE1
|
||||||
w->begin(I2C_SDA, I2C_SCL);
|
w->begin(I2C_SDA, I2C_SCL);
|
||||||
@@ -1063,8 +1083,8 @@ bool Power::axpChipInit()
|
|||||||
PMU->enablePowerOutput(XPOWERS_LDO2);
|
PMU->enablePowerOutput(XPOWERS_LDO2);
|
||||||
|
|
||||||
// oled module power channel,
|
// oled module power channel,
|
||||||
// disable it will cause abnormal communication between boot and AXP power supply,
|
// disable it will cause abnormal communication between boot and AXP power
|
||||||
// do not turn it off
|
// supply, do not turn it off
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
|
PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300);
|
||||||
// enable oled power
|
// enable oled power
|
||||||
PMU->enablePowerOutput(XPOWERS_DCDC1);
|
PMU->enablePowerOutput(XPOWERS_DCDC1);
|
||||||
@@ -1091,7 +1111,8 @@ bool Power::axpChipInit()
|
|||||||
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
PMU->setChargeTargetVoltage(XPOWERS_AXP192_CHG_VOL_4V2);
|
||||||
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
} else if (PMU->getChipModel() == XPOWERS_AXP2101) {
|
||||||
|
|
||||||
/*The alternative version of T-Beam 1.1 differs from T-Beam V1.1 in that it uses an AXP2101 power chip*/
|
/*The alternative version of T-Beam 1.1 differs from T-Beam V1.1 in that it
|
||||||
|
* uses an AXP2101 power chip*/
|
||||||
if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) {
|
if (HW_VENDOR == meshtastic_HardwareModel_TBEAM) {
|
||||||
// Unuse power channel
|
// Unuse power channel
|
||||||
PMU->disablePowerOutput(XPOWERS_DCDC2);
|
PMU->disablePowerOutput(XPOWERS_DCDC2);
|
||||||
@@ -1126,8 +1147,8 @@ bool Power::axpChipInit()
|
|||||||
// t-beam s3 core
|
// t-beam s3 core
|
||||||
/**
|
/**
|
||||||
* gnss module power channel
|
* gnss module power channel
|
||||||
* The default ALDO4 is off, you need to turn on the GNSS power first, otherwise it will be invalid during
|
* The default ALDO4 is off, you need to turn on the GNSS power first,
|
||||||
* initialization
|
* otherwise it will be invalid during initialization
|
||||||
*/
|
*/
|
||||||
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
|
PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300);
|
||||||
PMU->enablePowerOutput(XPOWERS_ALDO4);
|
PMU->enablePowerOutput(XPOWERS_ALDO4);
|
||||||
@@ -1177,7 +1198,8 @@ bool Power::axpChipInit()
|
|||||||
// disable all axp chip interrupt
|
// disable all axp chip interrupt
|
||||||
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ);
|
||||||
|
|
||||||
// Set the constant current charging current of AXP2101, temporarily use 500mA by default
|
// Set the constant current charging current of AXP2101, temporarily use
|
||||||
|
// 500mA by default
|
||||||
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
|
PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA);
|
||||||
|
|
||||||
// Set up the charging voltage
|
// Set up the charging voltage
|
||||||
@@ -1243,11 +1265,12 @@ bool Power::axpChipInit()
|
|||||||
PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
|
PMU->getPowerChannelVoltage(XPOWERS_BLDO2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can safely ignore this approach for most (or all) boards because MCU turned off
|
// We can safely ignore this approach for most (or all) boards because MCU
|
||||||
// earlier than battery discharged to 2.6V.
|
// turned off earlier than battery discharged to 2.6V.
|
||||||
//
|
//
|
||||||
// Unfortanly for now we can't use this killswitch for RAK4630-based boards because they have a bug with
|
// Unfortunately for now we can't use this killswitch for RAK4630-based boards
|
||||||
// battery voltage measurement. Probably it sometimes drops to low values.
|
// because they have a bug with battery voltage measurement. Probably it
|
||||||
|
// sometimes drops to low values.
|
||||||
#ifndef RAK4630
|
#ifndef RAK4630
|
||||||
// Set PMU shutdown voltage at 2.6V to maximize battery utilization
|
// Set PMU shutdown voltage at 2.6V to maximize battery utilization
|
||||||
PMU->setSysPowerDownVoltage(2600);
|
PMU->setSysPowerDownVoltage(2600);
|
||||||
@@ -1266,10 +1289,12 @@ bool Power::axpChipInit()
|
|||||||
attachInterrupt(
|
attachInterrupt(
|
||||||
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
|
PMU_IRQ, [] { pmu_irq = true; }, FALLING);
|
||||||
|
|
||||||
// we do not look for AXPXXX_CHARGING_FINISHED_IRQ & AXPXXX_CHARGING_IRQ because it occurs repeatedly while there is
|
// we do not look for AXPXXX_CHARGING_FINISHED_IRQ & AXPXXX_CHARGING_IRQ
|
||||||
// no battery also it could cause inadvertent waking from light sleep just because the battery filled
|
// because it occurs repeatedly while there is no battery also it could cause
|
||||||
// we don't look for AXPXXX_BATT_REMOVED_IRQ because it occurs repeatedly while no battery installed
|
// inadvertent waking from light sleep just because the battery filled we
|
||||||
// we don't look at AXPXXX_VBUS_REMOVED_IRQ because we don't have anything hooked to vbus
|
// don't look for AXPXXX_BATT_REMOVED_IRQ because it occurs repeatedly while
|
||||||
|
// no battery installed we don't look at AXPXXX_VBUS_REMOVED_IRQ because we
|
||||||
|
// don't have anything hooked to vbus
|
||||||
PMU->enableIRQ(pmuIrqMask);
|
PMU->enableIRQ(pmuIrqMask);
|
||||||
|
|
||||||
PMU->clearIrqStatus();
|
PMU->clearIrqStatus();
|
||||||
@@ -1385,8 +1410,8 @@ class LipoCharger : public HasBatteryLevel
|
|||||||
bool result = PPM->init(Wire, I2C_SDA, I2C_SCL, BQ25896_ADDR);
|
bool result = PPM->init(Wire, I2C_SDA, I2C_SCL, BQ25896_ADDR);
|
||||||
if (result) {
|
if (result) {
|
||||||
LOG_INFO("PPM BQ25896 init succeeded");
|
LOG_INFO("PPM BQ25896 init succeeded");
|
||||||
// Set the minimum operating voltage. Below this voltage, the PPM will protect
|
// Set the minimum operating voltage. Below this voltage, the PPM will
|
||||||
// PPM->setSysPowerDownVoltage(3100);
|
// protect PPM->setSysPowerDownVoltage(3100);
|
||||||
|
|
||||||
// Set input current limit, default is 500mA
|
// Set input current limit, default is 500mA
|
||||||
// PPM->setInputCurrentLimit(800);
|
// PPM->setInputCurrentLimit(800);
|
||||||
@@ -1409,7 +1434,8 @@ class LipoCharger : public HasBatteryLevel
|
|||||||
PPM->enableMeasure();
|
PPM->enableMeasure();
|
||||||
|
|
||||||
// Turn on charging function
|
// Turn on charging function
|
||||||
// If there is no battery connected, do not turn on the charging function
|
// If there is no battery connected, do not turn on the charging
|
||||||
|
// function
|
||||||
PPM->enableCharge();
|
PPM->enableCharge();
|
||||||
} else {
|
} else {
|
||||||
LOG_WARN("PPM BQ25896 init failed");
|
LOG_WARN("PPM BQ25896 init failed");
|
||||||
@@ -1444,7 +1470,8 @@ class LipoCharger : public HasBatteryLevel
|
|||||||
virtual int getBatteryPercent() override
|
virtual int getBatteryPercent() override
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
// return bq->getChargePercent(); // don't use BQ27220 for battery percent, it is not calibrated
|
// return bq->getChargePercent(); // don't use BQ27220 for battery percent,
|
||||||
|
// it is not calibrated
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1566,7 +1593,8 @@ bool Power::meshSolarInit()
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
/**
|
/**
|
||||||
* The meshSolar battery level sensor is unavailable - default to AnalogBatteryLevel
|
* The meshSolar battery level sensor is unavailable - default to
|
||||||
|
* AnalogBatteryLevel
|
||||||
*/
|
*/
|
||||||
bool Power::meshSolarInit()
|
bool Power::meshSolarInit()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -155,6 +155,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Default system gain to 0 if not defined
|
// Default system gain to 0 if not defined
|
||||||
|
#ifndef NUM_PA_POINTS
|
||||||
|
#define NUM_PA_POINTS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef TX_GAIN_LORA
|
#ifndef TX_GAIN_LORA
|
||||||
#define TX_GAIN_LORA 0
|
#define TX_GAIN_LORA 0
|
||||||
#endif
|
#endif
|
||||||
@@ -445,18 +449,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BME680 BSEC2 support detection
|
|
||||||
#if !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
|
||||||
#if defined(RAK_4631) || defined(TBEAM_V10)
|
|
||||||
|
|
||||||
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 1
|
|
||||||
#define MESHTASTIC_BME680_HEADER <bsec2.h>
|
|
||||||
#else
|
|
||||||
#define MESHTASTIC_BME680_BSEC2_SUPPORTED 0
|
|
||||||
#define MESHTASTIC_BME680_HEADER <Adafruit_BME680.h>
|
|
||||||
#endif // defined(RAK_4631)
|
|
||||||
#endif // !defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Global switches to turn off features for a minimized build
|
// Global switches to turn off features for a minimized build
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
#include "MessageStore.h"
|
#include "MessageStore.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
#include "UIRenderer.h"
|
#include "UIRenderer.h"
|
||||||
#include "configuration.h"
|
|
||||||
#include "gps/RTC.h"
|
#include "gps/RTC.h"
|
||||||
#include "graphics/Screen.h"
|
#include "graphics/Screen.h"
|
||||||
#include "graphics/ScreenFonts.h"
|
#include "graphics/ScreenFonts.h"
|
||||||
@@ -20,7 +19,6 @@
|
|||||||
|
|
||||||
// External declarations
|
// External declarations
|
||||||
extern bool hasUnreadMessage;
|
extern bool hasUnreadMessage;
|
||||||
extern meshtastic_DeviceState devicestate;
|
|
||||||
extern graphics::Screen *screen;
|
extern graphics::Screen *screen;
|
||||||
|
|
||||||
using graphics::Emote;
|
using graphics::Emote;
|
||||||
@@ -49,7 +47,7 @@ static inline size_t utf8CharLen(uint8_t c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove variation selectors (FE0F) and skin tone modifiers from emoji so they match your labels
|
// Remove variation selectors (FE0F) and skin tone modifiers from emoji so they match your labels
|
||||||
std::string normalizeEmoji(const std::string &s)
|
static std::string normalizeEmoji(const std::string &s)
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
for (size_t i = 0; i < s.size();) {
|
for (size_t i = 0; i < s.size();) {
|
||||||
@@ -82,6 +80,7 @@ uint32_t pauseStart = 0;
|
|||||||
bool waitingToReset = false;
|
bool waitingToReset = false;
|
||||||
bool scrollStarted = false;
|
bool scrollStarted = false;
|
||||||
static bool didReset = false;
|
static bool didReset = false;
|
||||||
|
static constexpr int MESSAGE_BLOCK_GAP = 6;
|
||||||
|
|
||||||
void scrollUp()
|
void scrollUp()
|
||||||
{
|
{
|
||||||
@@ -111,22 +110,6 @@ void scrollDown()
|
|||||||
|
|
||||||
void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string &line, const Emote *emotes, int emoteCount)
|
void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string &line, const Emote *emotes, int emoteCount)
|
||||||
{
|
{
|
||||||
std::string renderLine;
|
|
||||||
for (size_t i = 0; i < line.size();) {
|
|
||||||
uint8_t c = (uint8_t)line[i];
|
|
||||||
size_t len = utf8CharLen(c);
|
|
||||||
if (c == 0xEF && i + 2 < line.size() && (uint8_t)line[i + 1] == 0xB8 && (uint8_t)line[i + 2] == 0x8F) {
|
|
||||||
i += 3;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c == 0xF0 && i + 3 < line.size() && (uint8_t)line[i + 1] == 0x9F && (uint8_t)line[i + 2] == 0x8F &&
|
|
||||||
((uint8_t)line[i + 3] >= 0xBB && (uint8_t)line[i + 3] <= 0xBF)) {
|
|
||||||
i += 4;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
renderLine.append(line, i, len);
|
|
||||||
i += len;
|
|
||||||
}
|
|
||||||
int cursorX = x;
|
int cursorX = x;
|
||||||
const int fontHeight = FONT_HEIGHT_SMALL;
|
const int fontHeight = FONT_HEIGHT_SMALL;
|
||||||
|
|
||||||
@@ -203,8 +186,7 @@ void drawStringWithEmotes(OLEDDisplay *display, int x, int y, const std::string
|
|||||||
|
|
||||||
// Render the emote (if found)
|
// Render the emote (if found)
|
||||||
if (matchedEmote && i == nextEmotePos) {
|
if (matchedEmote && i == nextEmotePos) {
|
||||||
// Vertically center emote relative to font baseline (not just midline)
|
int iconY = y + (lineHeight - matchedEmote->height) / 2;
|
||||||
int iconY = fontY + (fontHeight - matchedEmote->height) / 2;
|
|
||||||
display->drawXbm(cursorX, iconY, matchedEmote->width, matchedEmote->height, matchedEmote->bitmap);
|
display->drawXbm(cursorX, iconY, matchedEmote->width, matchedEmote->height, matchedEmote->bitmap);
|
||||||
cursorX += matchedEmote->width + 1;
|
cursorX += matchedEmote->width + 1;
|
||||||
i += emojiLen;
|
i += emojiLen;
|
||||||
@@ -423,6 +405,102 @@ static inline int getRenderedLineWidth(OLEDDisplay *display, const std::string &
|
|||||||
return totalWidth;
|
return totalWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MessageBlock {
|
||||||
|
size_t start;
|
||||||
|
size_t end;
|
||||||
|
bool mine;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int getDrawnLinePixelBottom(int lineTopY, const std::string &line, bool isHeaderLine)
|
||||||
|
{
|
||||||
|
if (isHeaderLine) {
|
||||||
|
return lineTopY + (FONT_HEIGHT_SMALL - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tallest = FONT_HEIGHT_SMALL;
|
||||||
|
for (int e = 0; e < numEmotes; ++e) {
|
||||||
|
if (line.find(emotes[e].label) != std::string::npos) {
|
||||||
|
if (emotes[e].height > tallest)
|
||||||
|
tallest = emotes[e].height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int lineHeight = std::max(FONT_HEIGHT_SMALL, tallest);
|
||||||
|
const int iconTop = lineTopY + (lineHeight - tallest) / 2;
|
||||||
|
|
||||||
|
return iconTop + tallest - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drawRoundedRectOutline(OLEDDisplay *display, int x, int y, int w, int h, int r)
|
||||||
|
{
|
||||||
|
if (w <= 1 || h <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (r < 0)
|
||||||
|
r = 0;
|
||||||
|
|
||||||
|
int maxR = (std::min(w, h) / 2) - 1;
|
||||||
|
if (r > maxR)
|
||||||
|
r = maxR;
|
||||||
|
|
||||||
|
if (r == 0) {
|
||||||
|
display->drawRect(x, y, w, h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int x0 = x;
|
||||||
|
const int y0 = y;
|
||||||
|
const int x1 = x + w - 1;
|
||||||
|
const int y1 = y + h - 1;
|
||||||
|
|
||||||
|
// sides
|
||||||
|
if (x0 + r <= x1 - r) {
|
||||||
|
display->drawLine(x0 + r, y0, x1 - r, y0); // top
|
||||||
|
display->drawLine(x0 + r, y1, x1 - r, y1); // bottom
|
||||||
|
}
|
||||||
|
if (y0 + r <= y1 - r) {
|
||||||
|
display->drawLine(x0, y0 + r, x0, y1 - r); // left
|
||||||
|
display->drawLine(x1, y0 + r, x1, y1 - r); // right
|
||||||
|
}
|
||||||
|
|
||||||
|
// corner arcs
|
||||||
|
display->drawCircleQuads(x0 + r, y0 + r, r, 2); // top left
|
||||||
|
display->drawCircleQuads(x1 - r, y0 + r, r, 1); // top right
|
||||||
|
display->drawCircleQuads(x1 - r, y1 - r, r, 8); // bottom right
|
||||||
|
display->drawCircleQuads(x0 + r, y1 - r, r, 4); // bottom left
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<MessageBlock> buildMessageBlocks(const std::vector<bool> &isHeaderVec, const std::vector<bool> &isMineVec)
|
||||||
|
{
|
||||||
|
std::vector<MessageBlock> blocks;
|
||||||
|
if (isHeaderVec.empty())
|
||||||
|
return blocks;
|
||||||
|
|
||||||
|
size_t start = 0;
|
||||||
|
bool mine = isMineVec[0];
|
||||||
|
|
||||||
|
for (size_t i = 1; i < isHeaderVec.size(); ++i) {
|
||||||
|
if (isHeaderVec[i]) {
|
||||||
|
MessageBlock b;
|
||||||
|
b.start = start;
|
||||||
|
b.end = i - 1;
|
||||||
|
b.mine = mine;
|
||||||
|
blocks.push_back(b);
|
||||||
|
|
||||||
|
start = i;
|
||||||
|
mine = isMineVec[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageBlock last;
|
||||||
|
last.start = start;
|
||||||
|
last.end = isHeaderVec.size() - 1;
|
||||||
|
last.mine = mine;
|
||||||
|
blocks.push_back(last);
|
||||||
|
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
static void drawMessageScrollbar(OLEDDisplay *display, int visibleHeight, int totalHeight, int scrollOffset, int startY)
|
static void drawMessageScrollbar(OLEDDisplay *display, int visibleHeight, int totalHeight, int scrollOffset, int startY)
|
||||||
{
|
{
|
||||||
if (totalHeight <= visibleHeight)
|
if (totalHeight <= visibleHeight)
|
||||||
@@ -482,9 +560,14 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
constexpr int LEFT_MARGIN = 2;
|
constexpr int LEFT_MARGIN = 2;
|
||||||
constexpr int RIGHT_MARGIN = 2;
|
constexpr int RIGHT_MARGIN = 2;
|
||||||
constexpr int SCROLLBAR_WIDTH = 3;
|
constexpr int SCROLLBAR_WIDTH = 3;
|
||||||
|
constexpr int BUBBLE_PAD_X = 3;
|
||||||
|
constexpr int BUBBLE_PAD_Y = 4;
|
||||||
|
constexpr int BUBBLE_RADIUS = 4;
|
||||||
|
constexpr int BUBBLE_MIN_W = 24;
|
||||||
|
constexpr int BUBBLE_TEXT_INDENT = 2;
|
||||||
|
|
||||||
const int leftTextWidth = SCREEN_WIDTH - LEFT_MARGIN - RIGHT_MARGIN;
|
// Derived widths
|
||||||
|
const int leftTextWidth = SCREEN_WIDTH - LEFT_MARGIN - RIGHT_MARGIN - (BUBBLE_PAD_X * 2);
|
||||||
const int rightTextWidth = SCREEN_WIDTH - LEFT_MARGIN - RIGHT_MARGIN - SCROLLBAR_WIDTH;
|
const int rightTextWidth = SCREEN_WIDTH - LEFT_MARGIN - RIGHT_MARGIN - SCROLLBAR_WIDTH;
|
||||||
|
|
||||||
// Title string depending on mode
|
// Title string depending on mode
|
||||||
@@ -547,7 +630,28 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
char chanType[32] = "";
|
char chanType[32] = "";
|
||||||
if (currentMode == ThreadMode::ALL) {
|
if (currentMode == ThreadMode::ALL) {
|
||||||
if (m.dest == NODENUM_BROADCAST) {
|
if (m.dest == NODENUM_BROADCAST) {
|
||||||
snprintf(chanType, sizeof(chanType), "#%s", channels.getName(m.channelIndex));
|
const char *name = channels.getName(m.channelIndex);
|
||||||
|
if (currentResolution == ScreenResolution::Low || currentResolution == ScreenResolution::UltraLow) {
|
||||||
|
if (strcmp(name, "ShortTurbo") == 0)
|
||||||
|
name = "ShortT";
|
||||||
|
else if (strcmp(name, "ShortSlow") == 0)
|
||||||
|
name = "ShortS";
|
||||||
|
else if (strcmp(name, "ShortFast") == 0)
|
||||||
|
name = "ShortF";
|
||||||
|
else if (strcmp(name, "MediumSlow") == 0)
|
||||||
|
name = "MedS";
|
||||||
|
else if (strcmp(name, "MediumFast") == 0)
|
||||||
|
name = "MedF";
|
||||||
|
else if (strcmp(name, "LongSlow") == 0)
|
||||||
|
name = "LongS";
|
||||||
|
else if (strcmp(name, "LongFast") == 0)
|
||||||
|
name = "LongF";
|
||||||
|
else if (strcmp(name, "LongTurbo") == 0)
|
||||||
|
name = "LongT";
|
||||||
|
else if (strcmp(name, "LongMod") == 0)
|
||||||
|
name = "LongM";
|
||||||
|
}
|
||||||
|
snprintf(chanType, sizeof(chanType), "#%s", name);
|
||||||
} else {
|
} else {
|
||||||
snprintf(chanType, sizeof(chanType), "(DM)");
|
snprintf(chanType, sizeof(chanType), "(DM)");
|
||||||
}
|
}
|
||||||
@@ -614,8 +718,8 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Shrink Sender name if needed
|
// Shrink Sender name if needed
|
||||||
int availWidth = SCREEN_WIDTH - display->getStringWidth(timeBuf) - display->getStringWidth(chanType) -
|
int availWidth = (mine ? rightTextWidth : leftTextWidth) - display->getStringWidth(timeBuf) -
|
||||||
display->getStringWidth(" @...") - 10;
|
display->getStringWidth(chanType) - display->getStringWidth(" @...");
|
||||||
if (availWidth < 0)
|
if (availWidth < 0)
|
||||||
availWidth = 0;
|
availWidth = 0;
|
||||||
|
|
||||||
@@ -667,6 +771,8 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
cachedLines = allLines;
|
cachedLines = allLines;
|
||||||
cachedHeights = calculateLineHeights(cachedLines, emotes, isHeader);
|
cachedHeights = calculateLineHeights(cachedLines, emotes, isHeader);
|
||||||
|
|
||||||
|
std::vector<MessageBlock> blocks = buildMessageBlocks(isHeader, isMine);
|
||||||
|
|
||||||
// Scrolling logic (unchanged)
|
// Scrolling logic (unchanged)
|
||||||
int totalHeight = 0;
|
int totalHeight = 0;
|
||||||
for (size_t i = 0; i < cachedHeights.size(); ++i)
|
for (size_t i = 0; i < cachedHeights.size(); ++i)
|
||||||
@@ -714,12 +820,123 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
|
|
||||||
int finalScroll = (int)scrollY;
|
int finalScroll = (int)scrollY;
|
||||||
int yOffset = -finalScroll + getTextPositions(display)[1];
|
int yOffset = -finalScroll + getTextPositions(display)[1];
|
||||||
|
const int contentTop = getTextPositions(display)[1];
|
||||||
|
const int contentBottom = scrollBottom; // already excludes nav line
|
||||||
|
const int rightEdge = SCREEN_WIDTH - SCROLLBAR_WIDTH - RIGHT_MARGIN;
|
||||||
|
const int bubbleGapY = std::max(1, MESSAGE_BLOCK_GAP / 2);
|
||||||
|
|
||||||
|
std::vector<int> lineTop;
|
||||||
|
lineTop.resize(cachedLines.size());
|
||||||
|
{
|
||||||
|
int acc = 0;
|
||||||
|
for (size_t i = 0; i < cachedLines.size(); ++i) {
|
||||||
|
lineTop[i] = yOffset + acc;
|
||||||
|
acc += cachedHeights[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw bubbles
|
||||||
|
for (size_t bi = 0; bi < blocks.size(); ++bi) {
|
||||||
|
const auto &b = blocks[bi];
|
||||||
|
if (b.start >= cachedLines.size() || b.end >= cachedLines.size() || b.start > b.end)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int visualTop = lineTop[b.start];
|
||||||
|
|
||||||
|
int topY;
|
||||||
|
if (isHeader[b.start]) {
|
||||||
|
// Header start
|
||||||
|
constexpr int BUBBLE_PAD_TOP_HEADER = 1; // try 1 or 2
|
||||||
|
topY = visualTop - BUBBLE_PAD_TOP_HEADER;
|
||||||
|
} else {
|
||||||
|
// Body start
|
||||||
|
bool thisLineHasEmote = false;
|
||||||
|
for (int e = 0; e < numEmotes; ++e) {
|
||||||
|
if (cachedLines[b.start].find(emotes[e].label) != std::string::npos) {
|
||||||
|
thisLineHasEmote = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (thisLineHasEmote) {
|
||||||
|
constexpr int EMOTE_PADDING_ABOVE = 4;
|
||||||
|
visualTop -= EMOTE_PADDING_ABOVE;
|
||||||
|
}
|
||||||
|
topY = visualTop - BUBBLE_PAD_Y;
|
||||||
|
}
|
||||||
|
int visualBottom = getDrawnLinePixelBottom(lineTop[b.end], cachedLines[b.end], isHeader[b.end]);
|
||||||
|
int bottomY = visualBottom + BUBBLE_PAD_Y;
|
||||||
|
|
||||||
|
if (bi + 1 < blocks.size()) {
|
||||||
|
int nextHeaderIndex = (int)blocks[bi + 1].start;
|
||||||
|
int nextTop = lineTop[nextHeaderIndex];
|
||||||
|
int maxBottom = nextTop - 1 - bubbleGapY;
|
||||||
|
if (bottomY > maxBottom)
|
||||||
|
bottomY = maxBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bottomY <= topY + 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bottomY < contentTop || topY > contentBottom - 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int maxLineW = 0;
|
||||||
|
|
||||||
|
for (size_t i = b.start; i <= b.end; ++i) {
|
||||||
|
int w = 0;
|
||||||
|
if (isHeader[i]) {
|
||||||
|
w = display->getStringWidth(cachedLines[i].c_str());
|
||||||
|
if (b.mine)
|
||||||
|
w += 12; // room for ACK/NACK/relay mark
|
||||||
|
} else {
|
||||||
|
w = getRenderedLineWidth(display, cachedLines[i], emotes, numEmotes);
|
||||||
|
}
|
||||||
|
if (w > maxLineW)
|
||||||
|
maxLineW = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bubbleW = std::max(BUBBLE_MIN_W, maxLineW + (BUBBLE_PAD_X * 2));
|
||||||
|
int bubbleH = (bottomY - topY) + 1;
|
||||||
|
int bubbleX = 0;
|
||||||
|
if (b.mine) {
|
||||||
|
bubbleX = rightEdge - bubbleW;
|
||||||
|
} else {
|
||||||
|
bubbleX = x;
|
||||||
|
}
|
||||||
|
if (bubbleX < x)
|
||||||
|
bubbleX = x;
|
||||||
|
if (bubbleX + bubbleW > rightEdge)
|
||||||
|
bubbleW = std::max(1, rightEdge - bubbleX);
|
||||||
|
|
||||||
|
if (bubbleW > 1 && bubbleH > 1) {
|
||||||
|
int r = BUBBLE_RADIUS;
|
||||||
|
int maxR = (std::min(bubbleW, bubbleH) / 2) - 1;
|
||||||
|
if (maxR < 0)
|
||||||
|
maxR = 0;
|
||||||
|
if (r > maxR)
|
||||||
|
r = maxR;
|
||||||
|
|
||||||
|
drawRoundedRectOutline(display, bubbleX, topY, bubbleW, bubbleH, r);
|
||||||
|
const int extra = 3;
|
||||||
|
const int rr = r + extra;
|
||||||
|
int x1 = bubbleX + bubbleW - 1;
|
||||||
|
int y1 = topY + bubbleH - 1;
|
||||||
|
|
||||||
|
if (!b.mine) {
|
||||||
|
// top-left corner square
|
||||||
|
display->drawLine(bubbleX, topY, bubbleX + rr, topY);
|
||||||
|
display->drawLine(bubbleX, topY, bubbleX, topY + rr);
|
||||||
|
} else {
|
||||||
|
// bottom-right corner square
|
||||||
|
display->drawLine(x1 - rr, y1, x1, y1);
|
||||||
|
display->drawLine(x1, y1 - rr, x1, y1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render visible lines
|
// Render visible lines
|
||||||
|
int lineY = yOffset;
|
||||||
for (size_t i = 0; i < cachedLines.size(); ++i) {
|
for (size_t i = 0; i < cachedLines.size(); ++i) {
|
||||||
int lineY = yOffset;
|
|
||||||
for (size_t j = 0; j < i; ++j)
|
|
||||||
lineY += cachedHeights[j];
|
|
||||||
|
|
||||||
if (lineY > -cachedHeights[i] && lineY < scrollBottom) {
|
if (lineY > -cachedHeights[i] && lineY < scrollBottom) {
|
||||||
if (isHeader[i]) {
|
if (isHeader[i]) {
|
||||||
@@ -728,14 +945,28 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
int headerX;
|
int headerX;
|
||||||
if (isMine[i]) {
|
if (isMine[i]) {
|
||||||
// push header left to avoid overlap with scrollbar
|
// push header left to avoid overlap with scrollbar
|
||||||
headerX = SCREEN_WIDTH - w - SCROLLBAR_WIDTH - RIGHT_MARGIN;
|
headerX = (SCREEN_WIDTH - SCROLLBAR_WIDTH - RIGHT_MARGIN) - w - BUBBLE_TEXT_INDENT;
|
||||||
if (headerX < LEFT_MARGIN)
|
if (headerX < LEFT_MARGIN)
|
||||||
headerX = LEFT_MARGIN;
|
headerX = LEFT_MARGIN;
|
||||||
} else {
|
} else {
|
||||||
headerX = x;
|
headerX = x + BUBBLE_PAD_X + BUBBLE_TEXT_INDENT;
|
||||||
}
|
}
|
||||||
display->drawString(headerX, lineY, cachedLines[i].c_str());
|
display->drawString(headerX, lineY, cachedLines[i].c_str());
|
||||||
|
|
||||||
|
// Draw underline just under header text
|
||||||
|
int underlineY = lineY + FONT_HEIGHT_SMALL;
|
||||||
|
|
||||||
|
int underlineW = w;
|
||||||
|
int maxW = rightEdge - headerX;
|
||||||
|
if (maxW < 0)
|
||||||
|
maxW = 0;
|
||||||
|
if (underlineW > maxW)
|
||||||
|
underlineW = maxW;
|
||||||
|
|
||||||
|
for (int px = 0; px < underlineW; ++px) {
|
||||||
|
display->setPixel(headerX + px, underlineY);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw ACK/NACK mark for our own messages
|
// Draw ACK/NACK mark for our own messages
|
||||||
if (isMine[i]) {
|
if (isMine[i]) {
|
||||||
int markX = headerX - 10;
|
int markX = headerX - 10;
|
||||||
@@ -753,32 +984,28 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
|
|||||||
// AckStatus::NONE → show nothing
|
// AckStatus::NONE → show nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw underline just under header text
|
|
||||||
int underlineY = lineY + FONT_HEIGHT_SMALL;
|
|
||||||
for (int px = 0; px < w; ++px) {
|
|
||||||
display->setPixel(headerX + px, underlineY);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Render message line
|
// Render message line
|
||||||
if (isMine[i]) {
|
if (isMine[i]) {
|
||||||
// Calculate actual rendered width including emotes
|
// Calculate actual rendered width including emotes
|
||||||
int renderedWidth = getRenderedLineWidth(display, cachedLines[i], emotes, numEmotes);
|
int renderedWidth = getRenderedLineWidth(display, cachedLines[i], emotes, numEmotes);
|
||||||
int rightX = SCREEN_WIDTH - renderedWidth - SCROLLBAR_WIDTH - RIGHT_MARGIN;
|
int rightX = (SCREEN_WIDTH - SCROLLBAR_WIDTH - RIGHT_MARGIN) - renderedWidth - BUBBLE_TEXT_INDENT;
|
||||||
if (rightX < LEFT_MARGIN)
|
if (rightX < LEFT_MARGIN)
|
||||||
rightX = LEFT_MARGIN;
|
rightX = LEFT_MARGIN;
|
||||||
|
|
||||||
drawStringWithEmotes(display, rightX, lineY, cachedLines[i], emotes, numEmotes);
|
drawStringWithEmotes(display, rightX, lineY, cachedLines[i], emotes, numEmotes);
|
||||||
} else {
|
} else {
|
||||||
drawStringWithEmotes(display, x, lineY, cachedLines[i], emotes, numEmotes);
|
drawStringWithEmotes(display, x + BUBBLE_PAD_X + BUBBLE_TEXT_INDENT, lineY, cachedLines[i], emotes,
|
||||||
|
numEmotes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lineY += cachedHeights[i];
|
||||||
}
|
}
|
||||||
int totalContentHeight = totalHeight;
|
|
||||||
int visibleHeight = usableHeight;
|
|
||||||
|
|
||||||
// Draw scrollbar
|
// Draw scrollbar
|
||||||
drawMessageScrollbar(display, visibleHeight, totalContentHeight, finalScroll, getTextPositions(display)[1]);
|
drawMessageScrollbar(display, usableHeight, totalHeight, finalScroll, getTextPositions(display)[1]);
|
||||||
graphics::drawCommonHeader(display, x, y, titleStr);
|
graphics::drawCommonHeader(display, x, y, titleStr);
|
||||||
graphics::drawCommonFooter(display, x, y);
|
graphics::drawCommonFooter(display, x, y);
|
||||||
}
|
}
|
||||||
@@ -841,7 +1068,6 @@ std::vector<int> calculateLineHeights(const std::vector<std::string> &lines, con
|
|||||||
constexpr int HEADER_UNDERLINE_GAP = 0; // space between underline and first body line
|
constexpr int HEADER_UNDERLINE_GAP = 0; // space between underline and first body line
|
||||||
constexpr int HEADER_UNDERLINE_PIX = 1; // underline thickness (1px row drawn)
|
constexpr int HEADER_UNDERLINE_PIX = 1; // underline thickness (1px row drawn)
|
||||||
constexpr int BODY_LINE_LEADING = -4; // default vertical leading for normal body lines
|
constexpr int BODY_LINE_LEADING = -4; // default vertical leading for normal body lines
|
||||||
constexpr int MESSAGE_BLOCK_GAP = 4; // gap after a message block before a new header
|
|
||||||
constexpr int EMOTE_PADDING_ABOVE = 4; // space above emote line (added to line above)
|
constexpr int EMOTE_PADDING_ABOVE = 4; // space above emote line (added to line above)
|
||||||
constexpr int EMOTE_PADDING_BELOW = 3; // space below emote line (added to emote line)
|
constexpr int EMOTE_PADDING_BELOW = 3; // space below emote line (added to emote line)
|
||||||
|
|
||||||
@@ -851,6 +1077,7 @@ std::vector<int> calculateLineHeights(const std::vector<std::string> &lines, con
|
|||||||
for (size_t idx = 0; idx < lines.size(); ++idx) {
|
for (size_t idx = 0; idx < lines.size(); ++idx) {
|
||||||
const auto &line = lines[idx];
|
const auto &line = lines[idx];
|
||||||
const int baseHeight = FONT_HEIGHT_SMALL;
|
const int baseHeight = FONT_HEIGHT_SMALL;
|
||||||
|
int lineHeight = baseHeight;
|
||||||
|
|
||||||
// Detect if THIS line or NEXT line contains an emote
|
// Detect if THIS line or NEXT line contains an emote
|
||||||
bool hasEmote = false;
|
bool hasEmote = false;
|
||||||
@@ -872,8 +1099,6 @@ std::vector<int> calculateLineHeights(const std::vector<std::string> &lines, con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int lineHeight = baseHeight;
|
|
||||||
|
|
||||||
if (isHeaderVec[idx]) {
|
if (isHeaderVec[idx]) {
|
||||||
// Header line spacing
|
// Header line spacing
|
||||||
lineHeight = baseHeight + HEADER_UNDERLINE_PIX + HEADER_UNDERLINE_GAP;
|
lineHeight = baseHeight + HEADER_UNDERLINE_PIX + HEADER_UNDERLINE_GAP;
|
||||||
@@ -922,7 +1147,7 @@ void handleNewMessage(OLEDDisplay *display, const StoredMessage &sm, const mesht
|
|||||||
|
|
||||||
// Banner logic
|
// Banner logic
|
||||||
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet.from);
|
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet.from);
|
||||||
char longName[48] = "???";
|
char longName[48] = "?";
|
||||||
if (node && node->user.long_name) {
|
if (node && node->user.long_name) {
|
||||||
strncpy(longName, node->user.long_name, sizeof(longName) - 1);
|
strncpy(longName, node->user.long_name, sizeof(longName) - 1);
|
||||||
longName[sizeof(longName) - 1] = '\0';
|
longName[sizeof(longName) - 1] = '\0';
|
||||||
|
|||||||
89
src/main.cpp
89
src/main.cpp
@@ -10,6 +10,7 @@
|
|||||||
#include "ReliableRouter.h"
|
#include "ReliableRouter.h"
|
||||||
#include "airtime.h"
|
#include "airtime.h"
|
||||||
#include "buzz.h"
|
#include "buzz.h"
|
||||||
|
#include "power/PowerHAL.h"
|
||||||
|
|
||||||
#include "FSCommon.h"
|
#include "FSCommon.h"
|
||||||
#include "Led.h"
|
#include "Led.h"
|
||||||
@@ -105,6 +106,43 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr;
|
|||||||
#include <string>
|
#include <string>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
#ifdef DEBUG_PARTITION_TABLE
|
||||||
|
#include "esp_partition.h"
|
||||||
|
|
||||||
|
void printPartitionTable()
|
||||||
|
{
|
||||||
|
printf("\n--- Partition Table ---\n");
|
||||||
|
// Print Column Headers
|
||||||
|
printf("| %-16s | %-4s | %-7s | %-10s | %-10s |\n", "Label", "Type", "Subtype", "Offset", "Size");
|
||||||
|
printf("|------------------|------|---------|------------|------------|\n");
|
||||||
|
|
||||||
|
// Create an iterator to find ALL partitions (Type ANY, Subtype ANY)
|
||||||
|
esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL);
|
||||||
|
|
||||||
|
// Loop through the iterator
|
||||||
|
if (it != NULL) {
|
||||||
|
do {
|
||||||
|
const esp_partition_t *part = esp_partition_get(it);
|
||||||
|
|
||||||
|
// Print details: Label, Type (Hex), Subtype (Hex), Offset (Hex), Size (Hex)
|
||||||
|
printf("| %-16s | 0x%02x | 0x%02x | 0x%08x | 0x%08x |\n", part->label, part->type, part->subtype, part->address,
|
||||||
|
part->size);
|
||||||
|
|
||||||
|
// Move to next partition
|
||||||
|
it = esp_partition_next(it);
|
||||||
|
} while (it != NULL);
|
||||||
|
|
||||||
|
// Release the iterator memory
|
||||||
|
esp_partition_iterator_release(it);
|
||||||
|
} else {
|
||||||
|
printf("No partitions found.\n");
|
||||||
|
}
|
||||||
|
printf("-----------------------\n");
|
||||||
|
}
|
||||||
|
#endif // DEBUG_PARTITION_TABLE
|
||||||
|
#endif // ARCH_ESP32
|
||||||
|
|
||||||
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
|
||||||
#include "input/ButtonThread.h"
|
#include "input/ButtonThread.h"
|
||||||
|
|
||||||
@@ -295,6 +333,43 @@ __attribute__((weak, noinline)) bool loopCanSleep()
|
|||||||
void lateInitVariant() __attribute__((weak));
|
void lateInitVariant() __attribute__((weak));
|
||||||
void lateInitVariant() {}
|
void lateInitVariant() {}
|
||||||
|
|
||||||
|
// NRF52 (and probably other platforms) can report when system is in power failure mode
|
||||||
|
// (eg. too low battery voltage) and operating it is unsafe (data corruption, bootloops, etc).
|
||||||
|
// For example NRF52 will prevent any flash writes in that case automatically
|
||||||
|
// (but it causes issues we need to handle).
|
||||||
|
// This detection is independent from whatever ADC or dividers used in Meshtastic
|
||||||
|
// boards and is internal to chip.
|
||||||
|
|
||||||
|
// we use powerHAL layer to get this info and delay booting until power level is safe
|
||||||
|
|
||||||
|
// wait until power level is safe to continue booting (to avoid bootloops)
|
||||||
|
// blink user led in 3 flashes sequence to indicate what is happening
|
||||||
|
void waitUntilPowerLevelSafe()
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef LED_PIN
|
||||||
|
pinMode(LED_PIN, OUTPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (powerHAL_isPowerLevelSafe() == false) {
|
||||||
|
|
||||||
|
#ifdef LED_PIN
|
||||||
|
|
||||||
|
// 3x: blink for 300 ms, pause for 300 ms
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
digitalWrite(LED_PIN, LED_STATE_ON);
|
||||||
|
delay(300);
|
||||||
|
digitalWrite(LED_PIN, LED_STATE_OFF);
|
||||||
|
delay(300);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// sleep for 2s
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Print info as a structured log message (for automated log processing)
|
* Print info as a structured log message (for automated log processing)
|
||||||
*/
|
*/
|
||||||
@@ -305,6 +380,14 @@ void printInfo()
|
|||||||
#ifndef PIO_UNIT_TESTING
|
#ifndef PIO_UNIT_TESTING
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// initialize power HAL layer as early as possible
|
||||||
|
powerHAL_init();
|
||||||
|
|
||||||
|
// prevent booting if device is in power failure mode
|
||||||
|
// boot sequence will follow when battery level raises to safe mode
|
||||||
|
waitUntilPowerLevelSafe();
|
||||||
|
|
||||||
#if defined(R1_NEO)
|
#if defined(R1_NEO)
|
||||||
pinMode(DCDC_EN_HOLD, OUTPUT);
|
pinMode(DCDC_EN_HOLD, OUTPUT);
|
||||||
digitalWrite(DCDC_EN_HOLD, HIGH);
|
digitalWrite(DCDC_EN_HOLD, HIGH);
|
||||||
@@ -648,7 +731,11 @@ void setup()
|
|||||||
sensor_detected = true;
|
sensor_detected = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
#ifdef DEBUG_PARTITION_TABLE
|
||||||
|
printPartitionTable();
|
||||||
|
#endif
|
||||||
|
#endif // ARCH_ESP32
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
// Don't init display if we don't have one or we are waking headless due to a timer event
|
// Don't init display if we don't have one or we are waking headless due to a timer event
|
||||||
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
|
if (wakeCause == ESP_SLEEP_WAKEUP_TIMER) {
|
||||||
|
|||||||
@@ -61,11 +61,6 @@ bool CryptoEngine::regeneratePublicKey(uint8_t *pubKey, uint8_t *privKey)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
void CryptoEngine::clearKeys()
|
|
||||||
{
|
|
||||||
memset(public_key, 0, sizeof(public_key));
|
|
||||||
memset(private_key, 0, sizeof(private_key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encrypt a packet's payload using a key generated with Curve25519 and SHA256
|
* Encrypt a packet's payload using a key generated with Curve25519 and SHA256
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class CryptoEngine
|
|||||||
virtual bool regeneratePublicKey(uint8_t *pubKey, uint8_t *privKey);
|
virtual bool regeneratePublicKey(uint8_t *pubKey, uint8_t *privKey);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
void clearKeys();
|
|
||||||
void setDHPrivateKey(uint8_t *_private_key);
|
void setDHPrivateKey(uint8_t *_private_key);
|
||||||
virtual bool encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtastic_UserLite_public_key_t remotePublic,
|
virtual bool encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtastic_UserLite_public_key_t remotePublic,
|
||||||
uint64_t packetNum, size_t numBytes, const uint8_t *bytes, uint8_t *bytesOut);
|
uint64_t packetNum, size_t numBytes, const uint8_t *bytes, uint8_t *bytesOut);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <pb_decode.h>
|
#include <pb_decode.h>
|
||||||
#include <pb_encode.h>
|
#include <pb_encode.h>
|
||||||
|
#include <power/PowerHAL.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef ARCH_ESP32
|
#ifdef ARCH_ESP32
|
||||||
@@ -1418,6 +1419,14 @@ void NodeDB::loadFromDisk()
|
|||||||
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
|
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
|
||||||
bool fullAtomic)
|
bool fullAtomic)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// do not try to save anything if power level is not safe. In many cases flash will be lock-protected
|
||||||
|
// and all writes will fail anyway. Device should be sleeping at this point anyway.
|
||||||
|
if (!powerHAL_isPowerLevelSafe()) {
|
||||||
|
LOG_ERROR("Error: trying to saveProto() on unsafe device power level.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool okay = false;
|
bool okay = false;
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
auto f = SafeFile(filename, fullAtomic);
|
auto f = SafeFile(filename, fullAtomic);
|
||||||
@@ -1444,6 +1453,14 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
|
|||||||
|
|
||||||
bool NodeDB::saveChannelsToDisk()
|
bool NodeDB::saveChannelsToDisk()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// do not try to save anything if power level is not safe. In many cases flash will be lock-protected
|
||||||
|
// and all writes will fail anyway.
|
||||||
|
if (!powerHAL_isPowerLevelSafe()) {
|
||||||
|
LOG_ERROR("Error: trying to saveChannelsToDisk() on unsafe device power level.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
FSCom.mkdir("/prefs");
|
FSCom.mkdir("/prefs");
|
||||||
@@ -1454,6 +1471,14 @@ bool NodeDB::saveChannelsToDisk()
|
|||||||
|
|
||||||
bool NodeDB::saveDeviceStateToDisk()
|
bool NodeDB::saveDeviceStateToDisk()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// do not try to save anything if power level is not safe. In many cases flash will be lock-protected
|
||||||
|
// and all writes will fail anyway. Device should be sleeping at this point anyway.
|
||||||
|
if (!powerHAL_isPowerLevelSafe()) {
|
||||||
|
LOG_ERROR("Error: trying to saveDeviceStateToDisk() on unsafe device power level.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
FSCom.mkdir("/prefs");
|
FSCom.mkdir("/prefs");
|
||||||
@@ -1466,6 +1491,14 @@ bool NodeDB::saveDeviceStateToDisk()
|
|||||||
|
|
||||||
bool NodeDB::saveNodeDatabaseToDisk()
|
bool NodeDB::saveNodeDatabaseToDisk()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// do not try to save anything if power level is not safe. In many cases flash will be lock-protected
|
||||||
|
// and all writes will fail anyway. Device should be sleeping at this point anyway.
|
||||||
|
if (!powerHAL_isPowerLevelSafe()) {
|
||||||
|
LOG_ERROR("Error: trying to saveNodeDatabaseToDisk() on unsafe device power level.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
FSCom.mkdir("/prefs");
|
FSCom.mkdir("/prefs");
|
||||||
@@ -1478,6 +1511,14 @@ bool NodeDB::saveNodeDatabaseToDisk()
|
|||||||
|
|
||||||
bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// do not try to save anything if power level is not safe. In many cases flash will be lock-protected
|
||||||
|
// and all writes will fail anyway. Device should be sleeping at this point anyway.
|
||||||
|
if (!powerHAL_isPowerLevelSafe()) {
|
||||||
|
LOG_ERROR("Error: trying to saveToDiskNoRetry() on unsafe device power level.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
spiLock->lock();
|
spiLock->lock();
|
||||||
@@ -1533,6 +1574,14 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
|
|||||||
bool NodeDB::saveToDisk(int saveWhat)
|
bool NodeDB::saveToDisk(int saveWhat)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Save to disk %d", saveWhat);
|
LOG_DEBUG("Save to disk %d", saveWhat);
|
||||||
|
|
||||||
|
// do not try to save anything if power level is not safe. In many cases flash will be lock-protected
|
||||||
|
// and all writes will fail anyway. Device should be sleeping at this point anyway.
|
||||||
|
if (!powerHAL_isPowerLevelSafe()) {
|
||||||
|
LOG_ERROR("Error: trying to saveToDisk() on unsafe device power level.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool success = saveToDiskNoRetry(saveWhat);
|
bool success = saveToDiskNoRetry(saveWhat);
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
|
|||||||
@@ -666,18 +666,24 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
|
|||||||
power = maxPower;
|
power = maxPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NUM_PA_POINTS
|
#ifdef ARCH_PORTDUINO
|
||||||
if (TX_GAIN_LORA > 0 && !devicestate.owner.is_licensed) {
|
size_t num_pa_points = portduino_config.num_pa_points;
|
||||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, TX_GAIN_LORA);
|
const uint16_t *tx_gain = portduino_config.tx_gain_lora;
|
||||||
power -= TX_GAIN_LORA;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if (!devicestate.owner.is_licensed) {
|
size_t num_pa_points = NUM_PA_POINTS;
|
||||||
|
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (num_pa_points == 1) {
|
||||||
|
if (tx_gain[0] > 0 && !devicestate.owner.is_licensed) {
|
||||||
|
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[0]);
|
||||||
|
power -= tx_gain[0];
|
||||||
|
}
|
||||||
|
} else if (!devicestate.owner.is_licensed) {
|
||||||
// we have an array of PA gain values. Find the highest power setting that works.
|
// we have an array of PA gain values. Find the highest power setting that works.
|
||||||
const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
|
for (int radio_dbm = 0; radio_dbm < num_pa_points; radio_dbm++) {
|
||||||
for (int radio_dbm = 0; radio_dbm < NUM_PA_POINTS; radio_dbm++) {
|
|
||||||
if (((radio_dbm + tx_gain[radio_dbm]) > power) ||
|
if (((radio_dbm + tx_gain[radio_dbm]) > power) ||
|
||||||
((radio_dbm == (NUM_PA_POINTS - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
|
((radio_dbm == (num_pa_points - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= power))) {
|
||||||
// we've exceeded the power limit, or hit the max we can do
|
// we've exceeded the power limit, or hit the max we can do
|
||||||
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]);
|
LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", power, tx_gain[radio_dbm]);
|
||||||
power -= tx_gain[radio_dbm];
|
power -= tx_gain[radio_dbm];
|
||||||
@@ -685,7 +691,7 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (power > loraMaxPower) // Clamp power to maximum defined level
|
if (power > loraMaxPower) // Clamp power to maximum defined level
|
||||||
power = loraMaxPower;
|
power = loraMaxPower;
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,9 @@ typedef enum _meshtastic_AdminMessage_ModuleConfigType {
|
|||||||
/* TODO: REPLACE */
|
/* TODO: REPLACE */
|
||||||
meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11,
|
meshtastic_AdminMessage_ModuleConfigType_DETECTIONSENSOR_CONFIG = 11,
|
||||||
/* TODO: REPLACE */
|
/* TODO: REPLACE */
|
||||||
meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG = 12
|
meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG = 12,
|
||||||
|
/* TODO: REPLACE */
|
||||||
|
meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG = 13
|
||||||
} meshtastic_AdminMessage_ModuleConfigType;
|
} meshtastic_AdminMessage_ModuleConfigType;
|
||||||
|
|
||||||
typedef enum _meshtastic_AdminMessage_BackupLocation {
|
typedef enum _meshtastic_AdminMessage_BackupLocation {
|
||||||
@@ -323,8 +325,8 @@ extern "C" {
|
|||||||
#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG+1))
|
#define _meshtastic_AdminMessage_ConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ConfigType)(meshtastic_AdminMessage_ConfigType_DEVICEUI_CONFIG+1))
|
||||||
|
|
||||||
#define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG
|
#define _meshtastic_AdminMessage_ModuleConfigType_MIN meshtastic_AdminMessage_ModuleConfigType_MQTT_CONFIG
|
||||||
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG
|
#define _meshtastic_AdminMessage_ModuleConfigType_MAX meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG
|
||||||
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_PAXCOUNTER_CONFIG+1))
|
#define _meshtastic_AdminMessage_ModuleConfigType_ARRAYSIZE ((meshtastic_AdminMessage_ModuleConfigType)(meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG+1))
|
||||||
|
|
||||||
#define _meshtastic_AdminMessage_BackupLocation_MIN meshtastic_AdminMessage_BackupLocation_FLASH
|
#define _meshtastic_AdminMessage_BackupLocation_MIN meshtastic_AdminMessage_BackupLocation_FLASH
|
||||||
#define _meshtastic_AdminMessage_BackupLocation_MAX meshtastic_AdminMessage_BackupLocation_SD
|
#define _meshtastic_AdminMessage_BackupLocation_MAX meshtastic_AdminMessage_BackupLocation_SD
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ extern const pb_msgdesc_t meshtastic_BackupPreferences_msg;
|
|||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
/* meshtastic_NodeDatabase_size depends on runtime parameters */
|
/* meshtastic_NodeDatabase_size depends on runtime parameters */
|
||||||
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
|
#define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_BackupPreferences_size
|
||||||
#define meshtastic_BackupPreferences_size 2279
|
#define meshtastic_BackupPreferences_size 2362
|
||||||
#define meshtastic_ChannelFile_size 718
|
#define meshtastic_ChannelFile_size 718
|
||||||
#define meshtastic_DeviceState_size 1737
|
#define meshtastic_DeviceState_size 1737
|
||||||
#define meshtastic_NodeInfoLite_size 196
|
#define meshtastic_NodeInfoLite_size 196
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ typedef struct _meshtastic_LocalModuleConfig {
|
|||||||
/* Paxcounter Config */
|
/* Paxcounter Config */
|
||||||
bool has_paxcounter;
|
bool has_paxcounter;
|
||||||
meshtastic_ModuleConfig_PaxcounterConfig paxcounter;
|
meshtastic_ModuleConfig_PaxcounterConfig paxcounter;
|
||||||
|
/* StatusMessage Config */
|
||||||
|
bool has_statusmessage;
|
||||||
|
meshtastic_ModuleConfig_StatusMessageConfig statusmessage;
|
||||||
} meshtastic_LocalModuleConfig;
|
} meshtastic_LocalModuleConfig;
|
||||||
|
|
||||||
|
|
||||||
@@ -96,9 +99,9 @@ extern "C" {
|
|||||||
|
|
||||||
/* Initializer values for message structs */
|
/* Initializer values for message structs */
|
||||||
#define meshtastic_LocalConfig_init_default {false, meshtastic_Config_DeviceConfig_init_default, false, meshtastic_Config_PositionConfig_init_default, false, meshtastic_Config_PowerConfig_init_default, false, meshtastic_Config_NetworkConfig_init_default, false, meshtastic_Config_DisplayConfig_init_default, false, meshtastic_Config_LoRaConfig_init_default, false, meshtastic_Config_BluetoothConfig_init_default, 0, false, meshtastic_Config_SecurityConfig_init_default}
|
#define meshtastic_LocalConfig_init_default {false, meshtastic_Config_DeviceConfig_init_default, false, meshtastic_Config_PositionConfig_init_default, false, meshtastic_Config_PowerConfig_init_default, false, meshtastic_Config_NetworkConfig_init_default, false, meshtastic_Config_DisplayConfig_init_default, false, meshtastic_Config_LoRaConfig_init_default, false, meshtastic_Config_BluetoothConfig_init_default, 0, false, meshtastic_Config_SecurityConfig_init_default}
|
||||||
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_default, false, meshtastic_ModuleConfig_PaxcounterConfig_init_default}
|
#define meshtastic_LocalModuleConfig_init_default {false, meshtastic_ModuleConfig_MQTTConfig_init_default, false, meshtastic_ModuleConfig_SerialConfig_init_default, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_default, false, meshtastic_ModuleConfig_StoreForwardConfig_init_default, false, meshtastic_ModuleConfig_RangeTestConfig_init_default, false, meshtastic_ModuleConfig_TelemetryConfig_init_default, false, meshtastic_ModuleConfig_CannedMessageConfig_init_default, 0, false, meshtastic_ModuleConfig_AudioConfig_init_default, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_default, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_default, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_default, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_default, false, meshtastic_ModuleConfig_PaxcounterConfig_init_default, false, meshtastic_ModuleConfig_StatusMessageConfig_init_default}
|
||||||
#define meshtastic_LocalConfig_init_zero {false, meshtastic_Config_DeviceConfig_init_zero, false, meshtastic_Config_PositionConfig_init_zero, false, meshtastic_Config_PowerConfig_init_zero, false, meshtastic_Config_NetworkConfig_init_zero, false, meshtastic_Config_DisplayConfig_init_zero, false, meshtastic_Config_LoRaConfig_init_zero, false, meshtastic_Config_BluetoothConfig_init_zero, 0, false, meshtastic_Config_SecurityConfig_init_zero}
|
#define meshtastic_LocalConfig_init_zero {false, meshtastic_Config_DeviceConfig_init_zero, false, meshtastic_Config_PositionConfig_init_zero, false, meshtastic_Config_PowerConfig_init_zero, false, meshtastic_Config_NetworkConfig_init_zero, false, meshtastic_Config_DisplayConfig_init_zero, false, meshtastic_Config_LoRaConfig_init_zero, false, meshtastic_Config_BluetoothConfig_init_zero, 0, false, meshtastic_Config_SecurityConfig_init_zero}
|
||||||
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_zero, false, meshtastic_ModuleConfig_PaxcounterConfig_init_zero}
|
#define meshtastic_LocalModuleConfig_init_zero {false, meshtastic_ModuleConfig_MQTTConfig_init_zero, false, meshtastic_ModuleConfig_SerialConfig_init_zero, false, meshtastic_ModuleConfig_ExternalNotificationConfig_init_zero, false, meshtastic_ModuleConfig_StoreForwardConfig_init_zero, false, meshtastic_ModuleConfig_RangeTestConfig_init_zero, false, meshtastic_ModuleConfig_TelemetryConfig_init_zero, false, meshtastic_ModuleConfig_CannedMessageConfig_init_zero, 0, false, meshtastic_ModuleConfig_AudioConfig_init_zero, false, meshtastic_ModuleConfig_RemoteHardwareConfig_init_zero, false, meshtastic_ModuleConfig_NeighborInfoConfig_init_zero, false, meshtastic_ModuleConfig_AmbientLightingConfig_init_zero, false, meshtastic_ModuleConfig_DetectionSensorConfig_init_zero, false, meshtastic_ModuleConfig_PaxcounterConfig_init_zero, false, meshtastic_ModuleConfig_StatusMessageConfig_init_zero}
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
#define meshtastic_LocalConfig_device_tag 1
|
#define meshtastic_LocalConfig_device_tag 1
|
||||||
@@ -124,6 +127,7 @@ extern "C" {
|
|||||||
#define meshtastic_LocalModuleConfig_ambient_lighting_tag 12
|
#define meshtastic_LocalModuleConfig_ambient_lighting_tag 12
|
||||||
#define meshtastic_LocalModuleConfig_detection_sensor_tag 13
|
#define meshtastic_LocalModuleConfig_detection_sensor_tag 13
|
||||||
#define meshtastic_LocalModuleConfig_paxcounter_tag 14
|
#define meshtastic_LocalModuleConfig_paxcounter_tag 14
|
||||||
|
#define meshtastic_LocalModuleConfig_statusmessage_tag 15
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
#define meshtastic_LocalConfig_FIELDLIST(X, a) \
|
#define meshtastic_LocalConfig_FIELDLIST(X, a) \
|
||||||
@@ -161,7 +165,8 @@ X(a, STATIC, OPTIONAL, MESSAGE, remote_hardware, 10) \
|
|||||||
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11) \
|
X(a, STATIC, OPTIONAL, MESSAGE, neighbor_info, 11) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, ambient_lighting, 12) \
|
X(a, STATIC, OPTIONAL, MESSAGE, ambient_lighting, 12) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13) \
|
X(a, STATIC, OPTIONAL, MESSAGE, detection_sensor, 13) \
|
||||||
X(a, STATIC, OPTIONAL, MESSAGE, paxcounter, 14)
|
X(a, STATIC, OPTIONAL, MESSAGE, paxcounter, 14) \
|
||||||
|
X(a, STATIC, OPTIONAL, MESSAGE, statusmessage, 15)
|
||||||
#define meshtastic_LocalModuleConfig_CALLBACK NULL
|
#define meshtastic_LocalModuleConfig_CALLBACK NULL
|
||||||
#define meshtastic_LocalModuleConfig_DEFAULT NULL
|
#define meshtastic_LocalModuleConfig_DEFAULT NULL
|
||||||
#define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
#define meshtastic_LocalModuleConfig_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
||||||
@@ -177,6 +182,7 @@ X(a, STATIC, OPTIONAL, MESSAGE, paxcounter, 14)
|
|||||||
#define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
#define meshtastic_LocalModuleConfig_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
||||||
#define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
#define meshtastic_LocalModuleConfig_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
||||||
#define meshtastic_LocalModuleConfig_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig
|
#define meshtastic_LocalModuleConfig_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig
|
||||||
|
#define meshtastic_LocalModuleConfig_statusmessage_MSGTYPE meshtastic_ModuleConfig_StatusMessageConfig
|
||||||
|
|
||||||
extern const pb_msgdesc_t meshtastic_LocalConfig_msg;
|
extern const pb_msgdesc_t meshtastic_LocalConfig_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
||||||
@@ -186,9 +192,9 @@ extern const pb_msgdesc_t meshtastic_LocalModuleConfig_msg;
|
|||||||
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
|
#define meshtastic_LocalModuleConfig_fields &meshtastic_LocalModuleConfig_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalConfig_size
|
#define MESHTASTIC_MESHTASTIC_LOCALONLY_PB_H_MAX_SIZE meshtastic_LocalModuleConfig_size
|
||||||
#define meshtastic_LocalConfig_size 749
|
#define meshtastic_LocalConfig_size 749
|
||||||
#define meshtastic_LocalModuleConfig_size 675
|
#define meshtastic_LocalModuleConfig_size 758
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ PB_BIND(meshtastic_StoreForwardPlusPlus, meshtastic_StoreForwardPlusPlus, 2)
|
|||||||
PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO)
|
PB_BIND(meshtastic_Waypoint, meshtastic_Waypoint, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_StatusMessage, meshtastic_StatusMessage, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(meshtastic_MqttClientProxyMessage, meshtastic_MqttClientProxyMessage, 2)
|
PB_BIND(meshtastic_MqttClientProxyMessage, meshtastic_MqttClientProxyMessage, 2)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -858,6 +858,11 @@ typedef struct _meshtastic_Waypoint {
|
|||||||
uint32_t icon;
|
uint32_t icon;
|
||||||
} meshtastic_Waypoint;
|
} meshtastic_Waypoint;
|
||||||
|
|
||||||
|
/* Message for node status */
|
||||||
|
typedef struct _meshtastic_StatusMessage {
|
||||||
|
char status[80];
|
||||||
|
} meshtastic_StatusMessage;
|
||||||
|
|
||||||
typedef PB_BYTES_ARRAY_T(435) meshtastic_MqttClientProxyMessage_data_t;
|
typedef PB_BYTES_ARRAY_T(435) meshtastic_MqttClientProxyMessage_data_t;
|
||||||
/* This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server */
|
/* This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server */
|
||||||
typedef struct _meshtastic_MqttClientProxyMessage {
|
typedef struct _meshtastic_MqttClientProxyMessage {
|
||||||
@@ -1402,6 +1407,7 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define meshtastic_MeshPacket_priority_ENUMTYPE meshtastic_MeshPacket_Priority
|
#define meshtastic_MeshPacket_priority_ENUMTYPE meshtastic_MeshPacket_Priority
|
||||||
#define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed
|
#define meshtastic_MeshPacket_delayed_ENUMTYPE meshtastic_MeshPacket_Delayed
|
||||||
#define meshtastic_MeshPacket_transport_mechanism_ENUMTYPE meshtastic_MeshPacket_TransportMechanism
|
#define meshtastic_MeshPacket_transport_mechanism_ENUMTYPE meshtastic_MeshPacket_TransportMechanism
|
||||||
@@ -1444,6 +1450,7 @@ extern "C" {
|
|||||||
#define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}}
|
#define meshtastic_KeyVerification_init_default {0, {0, {0}}, {0, {0}}}
|
||||||
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
|
#define meshtastic_StoreForwardPlusPlus_init_default {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
|
||||||
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
#define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||||
|
#define meshtastic_StatusMessage_init_default {""}
|
||||||
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
#define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0}
|
||||||
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||||
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0}
|
#define meshtastic_NodeInfo_init_default {0, false, meshtastic_User_init_default, false, meshtastic_Position_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0, 0}
|
||||||
@@ -1476,6 +1483,7 @@ extern "C" {
|
|||||||
#define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}}
|
#define meshtastic_KeyVerification_init_zero {0, {0, {0}}, {0, {0}}}
|
||||||
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
|
#define meshtastic_StoreForwardPlusPlus_init_zero {_meshtastic_StoreForwardPlusPlus_SFPP_message_type_MIN, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, 0, 0, 0, 0, 0}
|
||||||
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
#define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0}
|
||||||
|
#define meshtastic_StatusMessage_init_zero {""}
|
||||||
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
#define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0}
|
||||||
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0, 0, 0, 0, _meshtastic_MeshPacket_TransportMechanism_MIN}
|
||||||
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0}
|
#define meshtastic_NodeInfo_init_zero {0, false, meshtastic_User_init_zero, false, meshtastic_Position_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0, 0}
|
||||||
@@ -1571,6 +1579,7 @@ extern "C" {
|
|||||||
#define meshtastic_Waypoint_name_tag 6
|
#define meshtastic_Waypoint_name_tag 6
|
||||||
#define meshtastic_Waypoint_description_tag 7
|
#define meshtastic_Waypoint_description_tag 7
|
||||||
#define meshtastic_Waypoint_icon_tag 8
|
#define meshtastic_Waypoint_icon_tag 8
|
||||||
|
#define meshtastic_StatusMessage_status_tag 1
|
||||||
#define meshtastic_MqttClientProxyMessage_topic_tag 1
|
#define meshtastic_MqttClientProxyMessage_topic_tag 1
|
||||||
#define meshtastic_MqttClientProxyMessage_data_tag 2
|
#define meshtastic_MqttClientProxyMessage_data_tag 2
|
||||||
#define meshtastic_MqttClientProxyMessage_text_tag 3
|
#define meshtastic_MqttClientProxyMessage_text_tag 3
|
||||||
@@ -1806,6 +1815,11 @@ X(a, STATIC, SINGULAR, FIXED32, icon, 8)
|
|||||||
#define meshtastic_Waypoint_CALLBACK NULL
|
#define meshtastic_Waypoint_CALLBACK NULL
|
||||||
#define meshtastic_Waypoint_DEFAULT NULL
|
#define meshtastic_Waypoint_DEFAULT NULL
|
||||||
|
|
||||||
|
#define meshtastic_StatusMessage_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, STRING, status, 1)
|
||||||
|
#define meshtastic_StatusMessage_CALLBACK NULL
|
||||||
|
#define meshtastic_StatusMessage_DEFAULT NULL
|
||||||
|
|
||||||
#define meshtastic_MqttClientProxyMessage_FIELDLIST(X, a) \
|
#define meshtastic_MqttClientProxyMessage_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, STRING, topic, 1) \
|
X(a, STATIC, SINGULAR, STRING, topic, 1) \
|
||||||
X(a, STATIC, ONEOF, BYTES, (payload_variant,data,payload_variant.data), 2) \
|
X(a, STATIC, ONEOF, BYTES, (payload_variant,data,payload_variant.data), 2) \
|
||||||
@@ -2072,6 +2086,7 @@ extern const pb_msgdesc_t meshtastic_Data_msg;
|
|||||||
extern const pb_msgdesc_t meshtastic_KeyVerification_msg;
|
extern const pb_msgdesc_t meshtastic_KeyVerification_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_StoreForwardPlusPlus_msg;
|
extern const pb_msgdesc_t meshtastic_StoreForwardPlusPlus_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_Waypoint_msg;
|
extern const pb_msgdesc_t meshtastic_Waypoint_msg;
|
||||||
|
extern const pb_msgdesc_t meshtastic_StatusMessage_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg;
|
extern const pb_msgdesc_t meshtastic_MqttClientProxyMessage_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_MeshPacket_msg;
|
extern const pb_msgdesc_t meshtastic_MeshPacket_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_NodeInfo_msg;
|
extern const pb_msgdesc_t meshtastic_NodeInfo_msg;
|
||||||
@@ -2106,6 +2121,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
|||||||
#define meshtastic_KeyVerification_fields &meshtastic_KeyVerification_msg
|
#define meshtastic_KeyVerification_fields &meshtastic_KeyVerification_msg
|
||||||
#define meshtastic_StoreForwardPlusPlus_fields &meshtastic_StoreForwardPlusPlus_msg
|
#define meshtastic_StoreForwardPlusPlus_fields &meshtastic_StoreForwardPlusPlus_msg
|
||||||
#define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg
|
#define meshtastic_Waypoint_fields &meshtastic_Waypoint_msg
|
||||||
|
#define meshtastic_StatusMessage_fields &meshtastic_StatusMessage_msg
|
||||||
#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg
|
#define meshtastic_MqttClientProxyMessage_fields &meshtastic_MqttClientProxyMessage_msg
|
||||||
#define meshtastic_MeshPacket_fields &meshtastic_MeshPacket_msg
|
#define meshtastic_MeshPacket_fields &meshtastic_MeshPacket_msg
|
||||||
#define meshtastic_NodeInfo_fields &meshtastic_NodeInfo_msg
|
#define meshtastic_NodeInfo_fields &meshtastic_NodeInfo_msg
|
||||||
@@ -2161,6 +2177,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg;
|
|||||||
#define meshtastic_QueueStatus_size 23
|
#define meshtastic_QueueStatus_size 23
|
||||||
#define meshtastic_RouteDiscovery_size 256
|
#define meshtastic_RouteDiscovery_size 256
|
||||||
#define meshtastic_Routing_size 259
|
#define meshtastic_Routing_size 259
|
||||||
|
#define meshtastic_StatusMessage_size 81
|
||||||
#define meshtastic_StoreForwardPlusPlus_size 377
|
#define meshtastic_StoreForwardPlusPlus_size 377
|
||||||
#define meshtastic_ToRadio_size 504
|
#define meshtastic_ToRadio_size 504
|
||||||
#define meshtastic_User_size 115
|
#define meshtastic_User_size 115
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ PB_BIND(meshtastic_ModuleConfig_CannedMessageConfig, meshtastic_ModuleConfig_Can
|
|||||||
PB_BIND(meshtastic_ModuleConfig_AmbientLightingConfig, meshtastic_ModuleConfig_AmbientLightingConfig, AUTO)
|
PB_BIND(meshtastic_ModuleConfig_AmbientLightingConfig, meshtastic_ModuleConfig_AmbientLightingConfig, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(meshtastic_ModuleConfig_StatusMessageConfig, meshtastic_ModuleConfig_StatusMessageConfig, AUTO)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(meshtastic_RemoteHardwarePin, meshtastic_RemoteHardwarePin, AUTO)
|
PB_BIND(meshtastic_RemoteHardwarePin, meshtastic_RemoteHardwarePin, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -409,6 +409,12 @@ typedef struct _meshtastic_ModuleConfig_AmbientLightingConfig {
|
|||||||
uint8_t blue;
|
uint8_t blue;
|
||||||
} meshtastic_ModuleConfig_AmbientLightingConfig;
|
} meshtastic_ModuleConfig_AmbientLightingConfig;
|
||||||
|
|
||||||
|
/* StatusMessage config - Allows setting a status message for a node to periodically rebroadcast */
|
||||||
|
typedef struct _meshtastic_ModuleConfig_StatusMessageConfig {
|
||||||
|
/* The actual status string */
|
||||||
|
char node_status[80];
|
||||||
|
} meshtastic_ModuleConfig_StatusMessageConfig;
|
||||||
|
|
||||||
/* A GPIO pin definition for remote hardware module */
|
/* A GPIO pin definition for remote hardware module */
|
||||||
typedef struct _meshtastic_RemoteHardwarePin {
|
typedef struct _meshtastic_RemoteHardwarePin {
|
||||||
/* GPIO Pin number (must match Arduino) */
|
/* GPIO Pin number (must match Arduino) */
|
||||||
@@ -460,6 +466,8 @@ typedef struct _meshtastic_ModuleConfig {
|
|||||||
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
|
meshtastic_ModuleConfig_DetectionSensorConfig detection_sensor;
|
||||||
/* TODO: REPLACE */
|
/* TODO: REPLACE */
|
||||||
meshtastic_ModuleConfig_PaxcounterConfig paxcounter;
|
meshtastic_ModuleConfig_PaxcounterConfig paxcounter;
|
||||||
|
/* TODO: REPLACE */
|
||||||
|
meshtastic_ModuleConfig_StatusMessageConfig statusmessage;
|
||||||
} payload_variant;
|
} payload_variant;
|
||||||
} meshtastic_ModuleConfig;
|
} meshtastic_ModuleConfig;
|
||||||
|
|
||||||
@@ -515,6 +523,7 @@ extern "C" {
|
|||||||
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_event_press_ENUMTYPE meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar
|
#define meshtastic_ModuleConfig_CannedMessageConfig_inputbroker_event_press_ENUMTYPE meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define meshtastic_RemoteHardwarePin_type_ENUMTYPE meshtastic_RemoteHardwarePinType
|
#define meshtastic_RemoteHardwarePin_type_ENUMTYPE meshtastic_RemoteHardwarePinType
|
||||||
|
|
||||||
|
|
||||||
@@ -534,6 +543,7 @@ extern "C" {
|
|||||||
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define meshtastic_ModuleConfig_TelemetryConfig_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
#define meshtastic_ModuleConfig_CannedMessageConfig_init_default {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_default {0, 0, 0, 0, 0}
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_init_default {""}
|
||||||
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
#define meshtastic_RemoteHardwarePin_init_default {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
||||||
#define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}}
|
#define meshtastic_ModuleConfig_init_zero {0, {meshtastic_ModuleConfig_MQTTConfig_init_zero}}
|
||||||
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0, 0, false, meshtastic_ModuleConfig_MapReportSettings_init_zero}
|
#define meshtastic_ModuleConfig_MQTTConfig_init_zero {0, "", "", "", 0, 0, 0, "", 0, 0, false, meshtastic_ModuleConfig_MapReportSettings_init_zero}
|
||||||
@@ -550,6 +560,7 @@ extern "C" {
|
|||||||
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define meshtastic_ModuleConfig_TelemetryConfig_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
#define meshtastic_ModuleConfig_CannedMessageConfig_init_zero {0, 0, 0, 0, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, _meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_MIN, 0, 0, "", 0}
|
||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_init_zero {0, 0, 0, 0, 0}
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_init_zero {""}
|
||||||
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
#define meshtastic_RemoteHardwarePin_init_zero {0, "", _meshtastic_RemoteHardwarePinType_MIN}
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
@@ -653,6 +664,7 @@ extern "C" {
|
|||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_red_tag 3
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_red_tag 3
|
||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_green_tag 4
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_green_tag 4
|
||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_blue_tag 5
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_blue_tag 5
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_node_status_tag 1
|
||||||
#define meshtastic_RemoteHardwarePin_gpio_pin_tag 1
|
#define meshtastic_RemoteHardwarePin_gpio_pin_tag 1
|
||||||
#define meshtastic_RemoteHardwarePin_name_tag 2
|
#define meshtastic_RemoteHardwarePin_name_tag 2
|
||||||
#define meshtastic_RemoteHardwarePin_type_tag 3
|
#define meshtastic_RemoteHardwarePin_type_tag 3
|
||||||
@@ -672,6 +684,7 @@ extern "C" {
|
|||||||
#define meshtastic_ModuleConfig_ambient_lighting_tag 11
|
#define meshtastic_ModuleConfig_ambient_lighting_tag 11
|
||||||
#define meshtastic_ModuleConfig_detection_sensor_tag 12
|
#define meshtastic_ModuleConfig_detection_sensor_tag 12
|
||||||
#define meshtastic_ModuleConfig_paxcounter_tag 13
|
#define meshtastic_ModuleConfig_paxcounter_tag 13
|
||||||
|
#define meshtastic_ModuleConfig_statusmessage_tag 14
|
||||||
|
|
||||||
/* Struct field encoding specification for nanopb */
|
/* Struct field encoding specification for nanopb */
|
||||||
#define meshtastic_ModuleConfig_FIELDLIST(X, a) \
|
#define meshtastic_ModuleConfig_FIELDLIST(X, a) \
|
||||||
@@ -687,7 +700,8 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,remote_hardware,payload_vari
|
|||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,neighbor_info,payload_variant.neighbor_info), 10) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,ambient_lighting,payload_variant.ambient_lighting), 11) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_variant.detection_sensor), 12) \
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,detection_sensor,payload_variant.detection_sensor), 12) \
|
||||||
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,paxcounter,payload_variant.paxcounter), 13)
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,paxcounter,payload_variant.paxcounter), 13) \
|
||||||
|
X(a, STATIC, ONEOF, MESSAGE, (payload_variant,statusmessage,payload_variant.statusmessage), 14)
|
||||||
#define meshtastic_ModuleConfig_CALLBACK NULL
|
#define meshtastic_ModuleConfig_CALLBACK NULL
|
||||||
#define meshtastic_ModuleConfig_DEFAULT NULL
|
#define meshtastic_ModuleConfig_DEFAULT NULL
|
||||||
#define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
#define meshtastic_ModuleConfig_payload_variant_mqtt_MSGTYPE meshtastic_ModuleConfig_MQTTConfig
|
||||||
@@ -703,6 +717,7 @@ X(a, STATIC, ONEOF, MESSAGE, (payload_variant,paxcounter,payload_variant.p
|
|||||||
#define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
#define meshtastic_ModuleConfig_payload_variant_ambient_lighting_MSGTYPE meshtastic_ModuleConfig_AmbientLightingConfig
|
||||||
#define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
#define meshtastic_ModuleConfig_payload_variant_detection_sensor_MSGTYPE meshtastic_ModuleConfig_DetectionSensorConfig
|
||||||
#define meshtastic_ModuleConfig_payload_variant_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig
|
#define meshtastic_ModuleConfig_payload_variant_paxcounter_MSGTYPE meshtastic_ModuleConfig_PaxcounterConfig
|
||||||
|
#define meshtastic_ModuleConfig_payload_variant_statusmessage_MSGTYPE meshtastic_ModuleConfig_StatusMessageConfig
|
||||||
|
|
||||||
#define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
|
#define meshtastic_ModuleConfig_MQTTConfig_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
X(a, STATIC, SINGULAR, BOOL, enabled, 1) \
|
||||||
@@ -865,6 +880,11 @@ X(a, STATIC, SINGULAR, UINT32, blue, 5)
|
|||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_CALLBACK NULL
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_CALLBACK NULL
|
||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_DEFAULT NULL
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_DEFAULT NULL
|
||||||
|
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, STRING, node_status, 1)
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_CALLBACK NULL
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_DEFAULT NULL
|
||||||
|
|
||||||
#define meshtastic_RemoteHardwarePin_FIELDLIST(X, a) \
|
#define meshtastic_RemoteHardwarePin_FIELDLIST(X, a) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, gpio_pin, 1) \
|
X(a, STATIC, SINGULAR, UINT32, gpio_pin, 1) \
|
||||||
X(a, STATIC, SINGULAR, STRING, name, 2) \
|
X(a, STATIC, SINGULAR, STRING, name, 2) \
|
||||||
@@ -887,6 +907,7 @@ extern const pb_msgdesc_t meshtastic_ModuleConfig_RangeTestConfig_msg;
|
|||||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_TelemetryConfig_msg;
|
extern const pb_msgdesc_t meshtastic_ModuleConfig_TelemetryConfig_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_CannedMessageConfig_msg;
|
extern const pb_msgdesc_t meshtastic_ModuleConfig_CannedMessageConfig_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_ModuleConfig_AmbientLightingConfig_msg;
|
extern const pb_msgdesc_t meshtastic_ModuleConfig_AmbientLightingConfig_msg;
|
||||||
|
extern const pb_msgdesc_t meshtastic_ModuleConfig_StatusMessageConfig_msg;
|
||||||
extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
||||||
|
|
||||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||||
@@ -905,6 +926,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
|||||||
#define meshtastic_ModuleConfig_TelemetryConfig_fields &meshtastic_ModuleConfig_TelemetryConfig_msg
|
#define meshtastic_ModuleConfig_TelemetryConfig_fields &meshtastic_ModuleConfig_TelemetryConfig_msg
|
||||||
#define meshtastic_ModuleConfig_CannedMessageConfig_fields &meshtastic_ModuleConfig_CannedMessageConfig_msg
|
#define meshtastic_ModuleConfig_CannedMessageConfig_fields &meshtastic_ModuleConfig_CannedMessageConfig_msg
|
||||||
#define meshtastic_ModuleConfig_AmbientLightingConfig_fields &meshtastic_ModuleConfig_AmbientLightingConfig_msg
|
#define meshtastic_ModuleConfig_AmbientLightingConfig_fields &meshtastic_ModuleConfig_AmbientLightingConfig_msg
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_fields &meshtastic_ModuleConfig_StatusMessageConfig_msg
|
||||||
#define meshtastic_RemoteHardwarePin_fields &meshtastic_RemoteHardwarePin_msg
|
#define meshtastic_RemoteHardwarePin_fields &meshtastic_RemoteHardwarePin_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
@@ -921,6 +943,7 @@ extern const pb_msgdesc_t meshtastic_RemoteHardwarePin_msg;
|
|||||||
#define meshtastic_ModuleConfig_RangeTestConfig_size 12
|
#define meshtastic_ModuleConfig_RangeTestConfig_size 12
|
||||||
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
|
#define meshtastic_ModuleConfig_RemoteHardwareConfig_size 96
|
||||||
#define meshtastic_ModuleConfig_SerialConfig_size 28
|
#define meshtastic_ModuleConfig_SerialConfig_size 28
|
||||||
|
#define meshtastic_ModuleConfig_StatusMessageConfig_size 81
|
||||||
#define meshtastic_ModuleConfig_StoreForwardConfig_size 24
|
#define meshtastic_ModuleConfig_StoreForwardConfig_size 24
|
||||||
#define meshtastic_ModuleConfig_TelemetryConfig_size 50
|
#define meshtastic_ModuleConfig_TelemetryConfig_size 50
|
||||||
#define meshtastic_ModuleConfig_size 227
|
#define meshtastic_ModuleConfig_size 227
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ typedef enum _meshtastic_PortNum {
|
|||||||
This module is specifically for Native Linux nodes, and provides a Git-style
|
This module is specifically for Native Linux nodes, and provides a Git-style
|
||||||
chain of messages. */
|
chain of messages. */
|
||||||
meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP = 35,
|
meshtastic_PortNum_STORE_FORWARD_PLUSPLUS_APP = 35,
|
||||||
|
/* Node Status module
|
||||||
|
ENCODING: protobuf
|
||||||
|
This module allows setting an extra string of status for a node.
|
||||||
|
Broadcasts on change and on a timer, possibly once a day. */
|
||||||
|
meshtastic_PortNum_NODE_STATUS_APP = 36,
|
||||||
/* Provides a hardware serial interface to send and receive from the Meshtastic network.
|
/* Provides a hardware serial interface to send and receive from the Meshtastic network.
|
||||||
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
|
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
|
||||||
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
|
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
|
||||||
|
|||||||
@@ -361,6 +361,8 @@ typedef struct _meshtastic_LocalStats {
|
|||||||
uint32_t heap_free_bytes;
|
uint32_t heap_free_bytes;
|
||||||
/* Number of packets that were dropped because the transmit queue was full. */
|
/* Number of packets that were dropped because the transmit queue was full. */
|
||||||
uint16_t num_tx_dropped;
|
uint16_t num_tx_dropped;
|
||||||
|
/* Noise floor value measured in dBm */
|
||||||
|
int32_t noise_floor;
|
||||||
} meshtastic_LocalStats;
|
} meshtastic_LocalStats;
|
||||||
|
|
||||||
/* Health telemetry metrics */
|
/* Health telemetry metrics */
|
||||||
@@ -458,7 +460,7 @@ extern "C" {
|
|||||||
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0}
|
#define meshtastic_HealthMetrics_init_default {false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_HostMetrics_init_default {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
|
#define meshtastic_HostMetrics_init_default {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
|
||||||
#define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
|
#define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}}
|
||||||
@@ -467,7 +469,7 @@ extern "C" {
|
|||||||
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
#define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
#define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0}
|
#define meshtastic_HealthMetrics_init_zero {false, 0, false, 0, false, 0}
|
||||||
#define meshtastic_HostMetrics_init_zero {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
|
#define meshtastic_HostMetrics_init_zero {0, 0, 0, false, 0, false, 0, 0, 0, 0, false, ""}
|
||||||
#define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}}
|
#define meshtastic_Telemetry_init_zero {0, 0, {meshtastic_DeviceMetrics_init_zero}}
|
||||||
@@ -556,6 +558,7 @@ extern "C" {
|
|||||||
#define meshtastic_LocalStats_heap_total_bytes_tag 12
|
#define meshtastic_LocalStats_heap_total_bytes_tag 12
|
||||||
#define meshtastic_LocalStats_heap_free_bytes_tag 13
|
#define meshtastic_LocalStats_heap_free_bytes_tag 13
|
||||||
#define meshtastic_LocalStats_num_tx_dropped_tag 14
|
#define meshtastic_LocalStats_num_tx_dropped_tag 14
|
||||||
|
#define meshtastic_LocalStats_noise_floor_tag 15
|
||||||
#define meshtastic_HealthMetrics_heart_bpm_tag 1
|
#define meshtastic_HealthMetrics_heart_bpm_tag 1
|
||||||
#define meshtastic_HealthMetrics_spO2_tag 2
|
#define meshtastic_HealthMetrics_spO2_tag 2
|
||||||
#define meshtastic_HealthMetrics_temperature_tag 3
|
#define meshtastic_HealthMetrics_temperature_tag 3
|
||||||
@@ -678,7 +681,8 @@ X(a, STATIC, SINGULAR, UINT32, num_tx_relay, 10) \
|
|||||||
X(a, STATIC, SINGULAR, UINT32, num_tx_relay_canceled, 11) \
|
X(a, STATIC, SINGULAR, UINT32, num_tx_relay_canceled, 11) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, heap_total_bytes, 12) \
|
X(a, STATIC, SINGULAR, UINT32, heap_total_bytes, 12) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, heap_free_bytes, 13) \
|
X(a, STATIC, SINGULAR, UINT32, heap_free_bytes, 13) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, num_tx_dropped, 14)
|
X(a, STATIC, SINGULAR, UINT32, num_tx_dropped, 14) \
|
||||||
|
X(a, STATIC, SINGULAR, INT32, noise_floor, 15)
|
||||||
#define meshtastic_LocalStats_CALLBACK NULL
|
#define meshtastic_LocalStats_CALLBACK NULL
|
||||||
#define meshtastic_LocalStats_DEFAULT NULL
|
#define meshtastic_LocalStats_DEFAULT NULL
|
||||||
|
|
||||||
@@ -755,7 +759,7 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg;
|
|||||||
#define meshtastic_EnvironmentMetrics_size 113
|
#define meshtastic_EnvironmentMetrics_size 113
|
||||||
#define meshtastic_HealthMetrics_size 11
|
#define meshtastic_HealthMetrics_size 11
|
||||||
#define meshtastic_HostMetrics_size 264
|
#define meshtastic_HostMetrics_size 264
|
||||||
#define meshtastic_LocalStats_size 76
|
#define meshtastic_LocalStats_size 87
|
||||||
#define meshtastic_Nau7802Config_size 16
|
#define meshtastic_Nau7802Config_size 16
|
||||||
#define meshtastic_PowerMetrics_size 81
|
#define meshtastic_PowerMetrics_size 81
|
||||||
#define meshtastic_Telemetry_size 272
|
#define meshtastic_Telemetry_size 272
|
||||||
|
|||||||
@@ -235,22 +235,46 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
|
|||||||
}
|
}
|
||||||
case meshtastic_AdminMessage_ota_request_tag: {
|
case meshtastic_AdminMessage_ota_request_tag: {
|
||||||
#if defined(ARCH_ESP32)
|
#if defined(ARCH_ESP32)
|
||||||
|
LOG_INFO("OTA Requested");
|
||||||
|
|
||||||
if (r->ota_request.ota_hash.size != 32) {
|
if (r->ota_request.ota_hash.size != 32) {
|
||||||
suppressRebootBanner = true;
|
suppressRebootBanner = true;
|
||||||
LOG_INFO("OTA Failed: Invalid `ota_hash` provided");
|
sendWarningAndLog("Cannot start OTA: Invalid `ota_hash` provided.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
meshtastic_OTAMode mode = r->ota_request.reboot_ota_mode;
|
meshtastic_OTAMode mode = r->ota_request.reboot_ota_mode;
|
||||||
|
const char *mode_name = (mode == METHOD_OTA_BLE ? "BLE" : "WiFi");
|
||||||
|
|
||||||
|
// Check that we have an OTA partition
|
||||||
|
const esp_partition_t *part = MeshtasticOTA::getAppPartition();
|
||||||
|
if (part == NULL) {
|
||||||
|
suppressRebootBanner = true;
|
||||||
|
sendWarningAndLog("Cannot start OTA: Cannot find OTA Loader partition.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_app_desc_t app_desc;
|
||||||
|
if (!MeshtasticOTA::getAppDesc(part, &app_desc)) {
|
||||||
|
suppressRebootBanner = true;
|
||||||
|
sendWarningAndLog("Cannot start OTA: Device does have a valid OTA Loader.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MeshtasticOTA::checkOTACapability(&app_desc, mode)) {
|
||||||
|
suppressRebootBanner = true;
|
||||||
|
sendWarningAndLog("OTA Loader does not support %s", mode_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (MeshtasticOTA::trySwitchToOTA()) {
|
if (MeshtasticOTA::trySwitchToOTA()) {
|
||||||
LOG_INFO("OTA Requested");
|
|
||||||
suppressRebootBanner = true;
|
suppressRebootBanner = true;
|
||||||
if (screen)
|
if (screen)
|
||||||
screen->startFirmwareUpdateScreen();
|
screen->startFirmwareUpdateScreen();
|
||||||
MeshtasticOTA::saveConfig(&config.network, mode, r->ota_request.ota_hash.bytes);
|
MeshtasticOTA::saveConfig(&config.network, mode, r->ota_request.ota_hash.bytes);
|
||||||
LOG_INFO("Rebooting to WiFi OTA");
|
sendWarningAndLog("Rebooting to %s OTA", mode_name);
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("WIFI OTA Failed");
|
sendWarningAndLog("Unable to switch to the OTA partition.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
int s = 1; // Reboot in 1 second, hard coded
|
int s = 1; // Reboot in 1 second, hard coded
|
||||||
@@ -1472,15 +1496,43 @@ void AdminModule::handleSendInputEvent(const meshtastic_AdminMessage_InputEvent
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdminModule::sendWarning(const char *message)
|
void AdminModule::sendWarning(const char *format, ...)
|
||||||
{
|
{
|
||||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||||
|
if (!cn)
|
||||||
|
return;
|
||||||
|
|
||||||
cn->level = meshtastic_LogRecord_Level_WARNING;
|
cn->level = meshtastic_LogRecord_Level_WARNING;
|
||||||
cn->time = getValidTime(RTCQualityFromNet);
|
cn->time = getValidTime(RTCQualityFromNet);
|
||||||
strncpy(cn->message, message, sizeof(cn->message));
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
// Format the arguments directly into the notification object
|
||||||
|
vsnprintf(cn->message, sizeof(cn->message), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
service->sendClientNotification(cn);
|
service->sendClientNotification(cn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdminModule::sendWarningAndLog(const char *format, ...)
|
||||||
|
{
|
||||||
|
// We need a temporary buffer to hold the formatted text so we can log it
|
||||||
|
// Using 250 bytes as a safe upper limit for typical text notifications
|
||||||
|
char buf[250];
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vsnprintf(buf, sizeof(buf), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
LOG_WARN(buf);
|
||||||
|
// 2. Call sendWarning
|
||||||
|
// SECURITY NOTE: We pass "%s", buf instead of just 'buf'.
|
||||||
|
// If 'buf' contained a % symbol (e.g. "Battery 50%"), passing it directly
|
||||||
|
// would crash sendWarning. "%s" treats it purely as text.
|
||||||
|
sendWarning("%s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
void disableBluetooth()
|
void disableBluetooth()
|
||||||
{
|
{
|
||||||
#if HAS_BLUETOOTH
|
#if HAS_BLUETOOTH
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include <esp_ota_ops.h>
|
||||||
|
#endif
|
||||||
#include "ProtobufModule.h"
|
#include "ProtobufModule.h"
|
||||||
|
#include <sys/types.h>
|
||||||
#if HAS_WIFI
|
#if HAS_WIFI
|
||||||
#include "mesh/wifi/WiFiAPClient.h"
|
#include "mesh/wifi/WiFiAPClient.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -71,7 +73,8 @@ class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Obser
|
|||||||
|
|
||||||
bool messageIsResponse(const meshtastic_AdminMessage *r);
|
bool messageIsResponse(const meshtastic_AdminMessage *r);
|
||||||
bool messageIsRequest(const meshtastic_AdminMessage *r);
|
bool messageIsRequest(const meshtastic_AdminMessage *r);
|
||||||
void sendWarning(const char *message);
|
void sendWarning(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
|
void sendWarningAndLog(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr const char *licensedModeMessage =
|
static constexpr const char *licensedModeMessage =
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "Default.h"
|
#include "Default.h"
|
||||||
#include "MeshService.h"
|
#include "MeshService.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "NodeStatus.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "Router.h"
|
#include "Router.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
@@ -129,14 +130,17 @@ meshtastic_MeshPacket *NodeInfoModule::allocReply()
|
|||||||
LOG_DEBUG("Skip send NodeInfo > 40%% ch. util");
|
LOG_DEBUG("Skip send NodeInfo > 40%% ch. util");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
// If we sent our NodeInfo less than 5 min. ago, don't send it again as it may be still underway.
|
|
||||||
if (!shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, 5 * 60 * 1000)) {
|
// Use graduated scaling based on active mesh size (10 minute base, scales with congestion coefficient)
|
||||||
LOG_DEBUG("Skip send NodeInfo since we sent it <5min ago");
|
uint32_t timeoutMs = Default::getConfiguredOrDefaultMsScaled(0, 10 * 60, nodeStatus->getNumOnline());
|
||||||
|
if (!shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, timeoutMs)) {
|
||||||
|
LOG_DEBUG("Skip send NodeInfo since we sent it <%us ago", timeoutMs / 1000);
|
||||||
ignoreRequest = true; // Mark it as ignored for MeshModule
|
ignoreRequest = true; // Mark it as ignored for MeshModule
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, 60 * 1000)) {
|
} else if (shorterTimeout && lastSentToMesh && Throttle::isWithinTimespanMs(lastSentToMesh, 60 * 1000)) {
|
||||||
|
// For interactive/urgent requests (e.g., user-triggered or implicit requests), use a shorter 60s timeout
|
||||||
LOG_DEBUG("Skip send NodeInfo since we sent it <60s ago");
|
LOG_DEBUG("Skip send NodeInfo since we sent it <60s ago");
|
||||||
ignoreRequest = true; // Mark it as ignored for MeshModule
|
ignoreRequest = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
ignoreRequest = false; // Don't ignore requests anymore
|
ignoreRequest = false; // Don't ignore requests anymore
|
||||||
|
|||||||
@@ -50,9 +50,10 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case meshtastic::BluetoothStatus::ConnectionState::CONNECTED: {
|
case meshtastic::BluetoothStatus::ConnectionState::CONNECTED: {
|
||||||
ble_state = connected;
|
if (ble_state != connected) {
|
||||||
PAIRING_LED_starttime = millis();
|
ble_state = connected;
|
||||||
break;
|
PAIRING_LED_starttime = millis();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ extern void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const c
|
|||||||
#include "Sensor/LTR390UVSensor.h"
|
#include "Sensor/LTR390UVSensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __has_include(MESHTASTIC_BME680_HEADER)
|
#if __has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>)
|
||||||
#include "Sensor/BME680Sensor.h"
|
#include "Sensor/BME680Sensor.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ void EnvironmentTelemetryModule::i2cScanFinished(ScanI2C *i2cScanner)
|
|||||||
#if __has_include(<Adafruit_LTR390.h>)
|
#if __has_include(<Adafruit_LTR390.h>)
|
||||||
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
|
addSensor<LTR390UVSensor>(i2cScanner, ScanI2C::DeviceType::LTR390UV);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(MESHTASTIC_BME680_HEADER)
|
#if __has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>)
|
||||||
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
|
addSensor<BME680Sensor>(i2cScanner, ScanI2C::DeviceType::BME_680);
|
||||||
#endif
|
#endif
|
||||||
#if __has_include(<Adafruit_BMP280.h>)
|
#if __has_include(<Adafruit_BMP280.h>)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && (__has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>))
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "BME680Sensor.h"
|
#include "BME680Sensor.h"
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
int32_t BME680Sensor::runOnce()
|
int32_t BME680Sensor::runOnce()
|
||||||
{
|
{
|
||||||
if (!bme680.run()) {
|
if (!bme680.run()) {
|
||||||
@@ -18,13 +18,13 @@ int32_t BME680Sensor::runOnce()
|
|||||||
}
|
}
|
||||||
return 35;
|
return 35;
|
||||||
}
|
}
|
||||||
#endif // defined(MESHTASTIC_BME680_BSEC2_SUPPORTED)
|
#endif
|
||||||
|
|
||||||
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
{
|
{
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
if (!bme680.begin(dev->address.address, *bus))
|
if (!bme680.begin(dev->address.address, *bus))
|
||||||
checkStatus("begin");
|
checkStatus("begin");
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
status = 1;
|
status = 1;
|
||||||
|
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
|
|
||||||
initI2CSensor();
|
initI2CSensor();
|
||||||
return status;
|
return status;
|
||||||
@@ -64,7 +64,7 @@ bool BME680Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
{
|
{
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
|
if (bme680.getData(BSEC_OUTPUT_RAW_PRESSURE).signal == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -98,11 +98,11 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
measurement->variant.environment_metrics.barometric_pressure = bme680->readPressure() / 100.0F;
|
measurement->variant.environment_metrics.barometric_pressure = bme680->readPressure() / 100.0F;
|
||||||
measurement->variant.environment_metrics.gas_resistance = bme680->readGas() / 1000.0;
|
measurement->variant.environment_metrics.gas_resistance = bme680->readGas() / 1000.0;
|
||||||
|
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
void BME680Sensor::loadState()
|
void BME680Sensor::loadState()
|
||||||
{
|
{
|
||||||
#ifdef FSCom
|
#ifdef FSCom
|
||||||
@@ -179,6 +179,6 @@ void BME680Sensor::checkStatus(const char *functionName)
|
|||||||
else if (bme680.sensor.status > BME68X_OK)
|
else if (bme680.sensor.status > BME68X_OK)
|
||||||
LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status);
|
LOG_WARN("%s BME68X code: %d", functionName, bme680.sensor.status);
|
||||||
}
|
}
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && __has_include(MESHTASTIC_BME680_HEADER)
|
#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR && (__has_include(<bsec2.h>) || __has_include(<Adafruit_BME680.h>))
|
||||||
|
|
||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "TelemetrySensor.h"
|
#include "TelemetrySensor.h"
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
#include <bme68xLibrary.h>
|
#include <bme68xLibrary.h>
|
||||||
#include <bsec2.h>
|
#include <bsec2.h>
|
||||||
#else
|
#else
|
||||||
#include <Adafruit_BME680.h>
|
#include <Adafruit_BME680.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
|
|
||||||
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
|
#define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // That's 6 hours worth of millis()
|
||||||
|
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
const uint8_t bsec_config[] = {
|
const uint8_t bsec_config[] = {
|
||||||
#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
|
#include "config/bme680/bme680_iaq_33v_3s_4d/bsec_iaq.txt"
|
||||||
};
|
};
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
class BME680Sensor : public TelemetrySensor
|
class BME680Sensor : public TelemetrySensor
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
Bsec2 bme680;
|
Bsec2 bme680;
|
||||||
#else
|
#else
|
||||||
using BME680Ptr = std::unique_ptr<Adafruit_BME680>;
|
using BME680Ptr = std::unique_ptr<Adafruit_BME680>;
|
||||||
@@ -31,10 +31,10 @@ class BME680Sensor : public TelemetrySensor
|
|||||||
static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique<Adafruit_BME680>(bus); }
|
static BME680Ptr makeBME680(TwoWire *bus) { return std::make_unique<Adafruit_BME680>(bus); }
|
||||||
|
|
||||||
BME680Ptr bme680;
|
BME680Ptr bme680;
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
const char *bsecConfigFileName = "/prefs/bsec.dat";
|
const char *bsecConfigFileName = "/prefs/bsec.dat";
|
||||||
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
|
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
|
||||||
uint8_t accuracy = 0;
|
uint8_t accuracy = 0;
|
||||||
@@ -51,13 +51,13 @@ class BME680Sensor : public TelemetrySensor
|
|||||||
void loadState();
|
void loadState();
|
||||||
void updateState();
|
void updateState();
|
||||||
void checkStatus(const char *functionName);
|
void checkStatus(const char *functionName);
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BME680Sensor();
|
BME680Sensor();
|
||||||
#if MESHTASTIC_BME680_BSEC2_SUPPORTED == 1
|
#if __has_include(<bsec2.h>)
|
||||||
virtual int32_t runOnce() override;
|
virtual int32_t runOnce() override;
|
||||||
#endif // MESHTASTIC_BME680_BSEC2_SUPPORTED
|
#endif
|
||||||
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
virtual bool getMetrics(meshtastic_Telemetry *measurement) override;
|
||||||
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
virtual bool initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,15 @@
|
|||||||
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
#include "../mesh/generated/meshtastic/telemetry.pb.h"
|
||||||
#include "RAK12035Sensor.h"
|
#include "RAK12035Sensor.h"
|
||||||
|
|
||||||
|
// The RAK12035 library's sensor_sleep() sets WB_IO2 (GPIO 34) LOW, which controls
|
||||||
|
// the 3.3V switched power rail (PIN_3V3_EN). This turns off power to ALL peripherals
|
||||||
|
// including GPS. We need to restore power after the library turns it off.
|
||||||
|
#ifdef PIN_3V3_EN
|
||||||
|
#define RESTORE_3V3_POWER() digitalWrite(PIN_3V3_EN, HIGH)
|
||||||
|
#else
|
||||||
|
#define RESTORE_3V3_POWER()
|
||||||
|
#endif
|
||||||
|
|
||||||
RAK12035Sensor::RAK12035Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RAK12035, "RAK12035") {}
|
RAK12035Sensor::RAK12035Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RAK12035, "RAK12035") {}
|
||||||
|
|
||||||
bool RAK12035Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
bool RAK12035Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
||||||
@@ -13,7 +22,6 @@ bool RAK12035Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
delay(100);
|
delay(100);
|
||||||
sensor.begin(dev->address.address);
|
sensor.begin(dev->address.address);
|
||||||
|
|
||||||
// Get sensor firmware version
|
|
||||||
uint8_t data = 0;
|
uint8_t data = 0;
|
||||||
sensor.get_sensor_version(&data);
|
sensor.get_sensor_version(&data);
|
||||||
if (data != 0) {
|
if (data != 0) {
|
||||||
@@ -21,8 +29,8 @@ bool RAK12035Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
LOG_INFO("RAK12035Sensor Init Succeed \nSensor1 Firmware version: %i, Sensor Name: %s", data, sensorName);
|
LOG_INFO("RAK12035Sensor Init Succeed \nSensor1 Firmware version: %i, Sensor Name: %s", data, sensorName);
|
||||||
status = true;
|
status = true;
|
||||||
sensor.sensor_sleep();
|
sensor.sensor_sleep();
|
||||||
|
RESTORE_3V3_POWER();
|
||||||
} else {
|
} else {
|
||||||
// If we reach here, it means the sensor did not initialize correctly.
|
|
||||||
LOG_INFO("Init sensor: %s", sensorName);
|
LOG_INFO("Init sensor: %s", sensorName);
|
||||||
LOG_ERROR("RAK12035Sensor Init Failed");
|
LOG_ERROR("RAK12035Sensor Init Failed");
|
||||||
status = false;
|
status = false;
|
||||||
@@ -38,8 +46,6 @@ bool RAK12035Sensor::initDevice(TwoWire *bus, ScanI2C::FoundDevice *dev)
|
|||||||
|
|
||||||
void RAK12035Sensor::setup()
|
void RAK12035Sensor::setup()
|
||||||
{
|
{
|
||||||
// Set the calibration values
|
|
||||||
// Reading the saved calibration values from the sensor.
|
|
||||||
// TODO:: Check for and run calibration check for up to 2 additional sensors if present.
|
// TODO:: Check for and run calibration check for up to 2 additional sensors if present.
|
||||||
uint16_t zero_val = 0;
|
uint16_t zero_val = 0;
|
||||||
uint16_t hundred_val = 0;
|
uint16_t hundred_val = 0;
|
||||||
@@ -71,6 +77,7 @@ void RAK12035Sensor::setup()
|
|||||||
LOG_INFO("Wet calibration reset complete. New value is %d", hundred_val);
|
LOG_INFO("Wet calibration reset complete. New value is %d", hundred_val);
|
||||||
}
|
}
|
||||||
sensor.sensor_sleep();
|
sensor.sensor_sleep();
|
||||||
|
RESTORE_3V3_POWER();
|
||||||
delay(200);
|
delay(200);
|
||||||
LOG_INFO("Dry calibration value is %d", zero_val);
|
LOG_INFO("Dry calibration value is %d", zero_val);
|
||||||
LOG_INFO("Wet calibration value is %d", hundred_val);
|
LOG_INFO("Wet calibration value is %d", hundred_val);
|
||||||
@@ -79,10 +86,6 @@ void RAK12035Sensor::setup()
|
|||||||
bool RAK12035Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
bool RAK12035Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
||||||
{
|
{
|
||||||
// TODO:: read and send metrics for up to 2 additional soil monitors if present.
|
// TODO:: read and send metrics for up to 2 additional soil monitors if present.
|
||||||
// -- how to do this.. this could get a little complex..
|
|
||||||
// ie - 1> we combine them into an average and send that, 2> we send them as separate metrics
|
|
||||||
// ^-- these scenarios would require different handling of the metrics in the receiving end and maybe a setting in the
|
|
||||||
// device ui and an additional proto for that?
|
|
||||||
measurement->variant.environment_metrics.has_soil_temperature = true;
|
measurement->variant.environment_metrics.has_soil_temperature = true;
|
||||||
measurement->variant.environment_metrics.has_soil_moisture = true;
|
measurement->variant.environment_metrics.has_soil_moisture = true;
|
||||||
|
|
||||||
@@ -97,6 +100,7 @@ bool RAK12035Sensor::getMetrics(meshtastic_Telemetry *measurement)
|
|||||||
success &= sensor.get_sensor_temperature(&temp);
|
success &= sensor.get_sensor_temperature(&temp);
|
||||||
delay(200);
|
delay(200);
|
||||||
sensor.sensor_sleep();
|
sensor.sensor_sleep();
|
||||||
|
RESTORE_3V3_POWER();
|
||||||
|
|
||||||
if (success == false) {
|
if (success == false) {
|
||||||
LOG_ERROR("Failed to read sensor data");
|
LOG_ERROR("Failed to read sensor data");
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
#include "MeshtasticOTA.h"
|
#include "MeshtasticOTA.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace MeshtasticOTA
|
namespace MeshtasticOTA
|
||||||
{
|
{
|
||||||
|
|
||||||
static const char *nvsNamespace = "MeshtasticOTA";
|
static const char *nvsNamespace = "MeshtasticOTA";
|
||||||
static const char *appProjectName = "MeshtasticOTA";
|
static const char *combinedAppProjectName = "MeshtasticOTA";
|
||||||
|
static const char *bleOnlyAppProjectName = "MeshtasticOTA-BLE";
|
||||||
|
static const char *wifiOnlyAppProjectName = "MeshtasticOTA-WiFi";
|
||||||
|
|
||||||
static bool updated = false;
|
static bool updated = false;
|
||||||
|
|
||||||
@@ -68,21 +72,44 @@ bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc)
|
|||||||
LOG_INFO("esp_ota_get_partition_description failed");
|
LOG_INFO("esp_ota_get_partition_description failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (strcmp(app_desc->project_name, appProjectName) != 0) {
|
|
||||||
LOG_INFO("app_desc->project_name == 0");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool checkOTACapability(esp_app_desc_t *app_desc, uint8_t method)
|
||||||
|
{
|
||||||
|
// Combined loader supports all (both) transports, BLE and WiFi
|
||||||
|
if (strcmp(app_desc->project_name, combinedAppProjectName) == 0) {
|
||||||
|
LOG_INFO("OTA partition contains combined BLE/WiFi OTA Loader");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (method == METHOD_OTA_BLE && strcmp(app_desc->project_name, bleOnlyAppProjectName) == 0) {
|
||||||
|
LOG_INFO("OTA partition contains BLE-only OTA Loader");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (method == METHOD_OTA_WIFI && strcmp(app_desc->project_name, wifiOnlyAppProjectName) == 0) {
|
||||||
|
LOG_INFO("OTA partition contains WiFi-only OTA Loader");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LOG_INFO("OTA partition does not contain a known OTA loader");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool trySwitchToOTA()
|
bool trySwitchToOTA()
|
||||||
{
|
{
|
||||||
const esp_partition_t *part = getAppPartition();
|
const esp_partition_t *part = getAppPartition();
|
||||||
esp_app_desc_t app_desc;
|
|
||||||
if (!getAppDesc(part, &app_desc))
|
if (part == NULL) {
|
||||||
|
LOG_WARN("Unable to get app partition in preparation of OTA reboot");
|
||||||
return false;
|
return false;
|
||||||
if (esp_ota_set_boot_partition(part) != ESP_OK)
|
}
|
||||||
|
|
||||||
|
uint8_t result = esp_ota_set_boot_partition(part);
|
||||||
|
// Partition and app checks should now be done in the AdminModule before this is called
|
||||||
|
if (result != ESP_OK) {
|
||||||
|
LOG_WARN("Unable to switch to OTA partiton. (Reason %d)", result);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,20 @@
|
|||||||
|
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#ifdef ESP_PLATFORM
|
||||||
|
#include <esp_ota_ops.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define METHOD_OTA_BLE 1
|
||||||
|
#define METHOD_OTA_WIFI 2
|
||||||
|
|
||||||
namespace MeshtasticOTA
|
namespace MeshtasticOTA
|
||||||
{
|
{
|
||||||
void initialize();
|
void initialize();
|
||||||
bool isUpdated();
|
bool isUpdated();
|
||||||
|
const esp_partition_t *getAppPartition();
|
||||||
|
bool getAppDesc(const esp_partition_t *part, esp_app_desc_t *app_desc);
|
||||||
|
bool checkOTACapability(esp_app_desc_t *app_desc, uint8_t method);
|
||||||
void recoverConfig(meshtastic_Config_NetworkConfig *network);
|
void recoverConfig(meshtastic_Config_NetworkConfig *network);
|
||||||
void saveConfig(meshtastic_Config_NetworkConfig *network, meshtastic_OTAMode method, uint8_t *ota_hash);
|
void saveConfig(meshtastic_Config_NetworkConfig *network, meshtastic_OTAMode method, uint8_t *ota_hash);
|
||||||
bool trySwitchToOTA();
|
bool trySwitchToOTA();
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ void startAdv(void)
|
|||||||
Bluefruit.Advertising.addService(meshBleService);
|
Bluefruit.Advertising.addService(meshBleService);
|
||||||
/* Start Advertising
|
/* Start Advertising
|
||||||
* - Enable auto advertising if disconnected
|
* - Enable auto advertising if disconnected
|
||||||
* - Interval: fast mode = 20 ms, slow mode = 152.5 ms
|
* - Interval: fast mode = 20 ms, slow mode = 417,5 ms
|
||||||
* - Timeout for fast mode is 30 seconds
|
* - Timeout for fast mode is 30 seconds
|
||||||
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
|
* - Start(timeout) with timeout = 0 will advertise forever (until connected)
|
||||||
*
|
*
|
||||||
@@ -127,7 +127,7 @@ void startAdv(void)
|
|||||||
* https://developer.apple.com/library/content/qa/qa1931/_index.html
|
* https://developer.apple.com/library/content/qa/qa1931/_index.html
|
||||||
*/
|
*/
|
||||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
Bluefruit.Advertising.setInterval(32, 668); // in unit of 0.625 ms
|
||||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||||
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X
|
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds. FIXME, we should stop advertising after X
|
||||||
}
|
}
|
||||||
@@ -240,6 +240,12 @@ int NRF52Bluetooth::getRssi()
|
|||||||
{
|
{
|
||||||
return 0; // FIXME figure out where to source this
|
return 0; // FIXME figure out where to source this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Valid BLE TX power levels as per nRF52840 Product Specification are: "-20 to +8 dBm TX power, configurable in 4 dB steps".
|
||||||
|
// See https://docs.nordicsemi.com/bundle/ps_nrf52840/page/keyfeatures_html5.html
|
||||||
|
#define VALID_BLE_TX_POWER(x) \
|
||||||
|
((x) == -20 || (x) == -16 || (x) == -12 || (x) == -8 || (x) == -4 || (x) == 0 || (x) == 4 || (x) == 8)
|
||||||
|
|
||||||
void NRF52Bluetooth::setup()
|
void NRF52Bluetooth::setup()
|
||||||
{
|
{
|
||||||
// Initialise the Bluefruit module
|
// Initialise the Bluefruit module
|
||||||
@@ -251,6 +257,9 @@ void NRF52Bluetooth::setup()
|
|||||||
Bluefruit.Advertising.stop();
|
Bluefruit.Advertising.stop();
|
||||||
Bluefruit.Advertising.clearData();
|
Bluefruit.Advertising.clearData();
|
||||||
Bluefruit.ScanResponse.clearData();
|
Bluefruit.ScanResponse.clearData();
|
||||||
|
#if defined(NRF52_BLE_TX_POWER) && VALID_BLE_TX_POWER(NRF52_BLE_TX_POWER)
|
||||||
|
Bluefruit.setTxPower(NRF52_BLE_TX_POWER);
|
||||||
|
#endif
|
||||||
if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) {
|
if (config.bluetooth.mode != meshtastic_Config_BluetoothConfig_PairingMode_NO_PIN) {
|
||||||
configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN
|
configuredPasskey = config.bluetooth.mode == meshtastic_Config_BluetoothConfig_PairingMode_FIXED_PIN
|
||||||
? config.bluetooth.fixed_pin
|
? config.bluetooth.fixed_pin
|
||||||
@@ -272,6 +281,29 @@ void NRF52Bluetooth::setup()
|
|||||||
// Set the connect/disconnect callback handlers
|
// Set the connect/disconnect callback handlers
|
||||||
Bluefruit.Periph.setConnectCallback(onConnect);
|
Bluefruit.Periph.setConnectCallback(onConnect);
|
||||||
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
|
Bluefruit.Periph.setDisconnectCallback(onDisconnect);
|
||||||
|
|
||||||
|
// Do not change Slave Latency to value other than 0 !!!
|
||||||
|
// There is probably a bug in SoftDevice + certain Apple iOS versions being
|
||||||
|
// brain damaged causing connectivity problems.
|
||||||
|
|
||||||
|
// On one side it seems SoftDevice is using SlaveLatency value even
|
||||||
|
// if connection parameter negotation failed and phone sees it as connectivity errors.
|
||||||
|
|
||||||
|
// On the other hand Apple can randomly refuse any parameter negotiation and shutdown connection
|
||||||
|
// even if you meet Apple Developer Guidelines for BLE devices. Because f* you, that's why.
|
||||||
|
|
||||||
|
// While this API call sets preferred connection parameters (PPCP) - many phones ignore it (yeah) and it seems SoftDevice
|
||||||
|
// will try to renegotiate connection parameters based on those values after phone connection.
|
||||||
|
// So those are relatively safe values so Apple braindead firmware won't get angry and at least we may try
|
||||||
|
// to negotiate some longer connection interval to save battery.
|
||||||
|
|
||||||
|
// See https://github.com/meshtastic/firmware/pull/8858 for measurements. We are dealing with microamp savings anyway so not
|
||||||
|
// worth dying on a hill here.
|
||||||
|
|
||||||
|
Bluefruit.Periph.setConnSlaveLatency(0);
|
||||||
|
// 1.25 ms units - so min, max is 15, 100 ms range.
|
||||||
|
Bluefruit.Periph.setConnInterval(12, 80);
|
||||||
|
|
||||||
#ifndef BLE_DFU_SECURE
|
#ifndef BLE_DFU_SECURE
|
||||||
bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
bledfu.setPermission(SECMODE_ENC_WITH_MITM, SECMODE_ENC_WITH_MITM);
|
||||||
bledfu.begin(); // Install the DFU helper
|
bledfu.begin(); // Install the DFU helper
|
||||||
@@ -300,7 +332,7 @@ void NRF52Bluetooth::setup()
|
|||||||
void NRF52Bluetooth::resumeAdvertising()
|
void NRF52Bluetooth::resumeAdvertising()
|
||||||
{
|
{
|
||||||
Bluefruit.Advertising.restartOnDisconnect(true);
|
Bluefruit.Advertising.restartOnDisconnect(true);
|
||||||
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
|
Bluefruit.Advertising.setInterval(32, 668); // in unit of 0.625 ms
|
||||||
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
|
||||||
Bluefruit.Advertising.start(0);
|
Bluefruit.Advertising.start(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,25 @@
|
|||||||
//
|
//
|
||||||
// defaults for NRF52 architecture
|
// defaults for NRF52 architecture
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal Reference is +/-0.6V, with an adjustable gain of 1/6, 1/5, 1/4,
|
||||||
|
* 1/3, 1/2 or 1, meaning 3.6, 3.0, 2.4, 1.8, 1.2 or 0.6V for the ADC levels.
|
||||||
|
*
|
||||||
|
* External Reference is VDD/4, with an adjustable gain of 1, 2 or 4, meaning
|
||||||
|
* VDD/4, VDD/2 or VDD for the ADC levels.
|
||||||
|
*
|
||||||
|
* Default settings are internal reference with 1/6 gain (GND..3.6V ADC range)
|
||||||
|
* Some variants overwrite it.
|
||||||
|
*/
|
||||||
|
#ifndef AREF_VOLTAGE
|
||||||
|
#define AREF_VOLTAGE 3.6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BATTERY_SENSE_RESOLUTION_BITS
|
||||||
|
#define BATTERY_SENSE_RESOLUTION_BITS 10
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef HAS_BLUETOOTH
|
#ifndef HAS_BLUETOOTH
|
||||||
#define HAS_BLUETOOTH 1
|
#define HAS_BLUETOOTH 1
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
#define NRFX_WDT_ENABLED 1
|
#define NRFX_WDT_ENABLED 1
|
||||||
#define NRFX_WDT0_ENABLED 1
|
#define NRFX_WDT0_ENABLED 1
|
||||||
#define NRFX_WDT_CONFIG_NO_IRQ 1
|
#define NRFX_WDT_CONFIG_NO_IRQ 1
|
||||||
#include <nrfx_wdt.c>
|
#include "nrfx_power.h"
|
||||||
#include <nrfx_wdt.h>
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ble_gap.h>
|
#include <ble_gap.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
#include <nrfx_wdt.c>
|
||||||
|
#include <nrfx_wdt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
// #include <Adafruit_USBD_Device.h>
|
// #include <Adafruit_USBD_Device.h>
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "meshUtils.h"
|
#include "meshUtils.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
|
#include <power/PowerHAL.h>
|
||||||
|
|
||||||
#include <hal/nrf_lpcomp.h>
|
#include <hal/nrf_lpcomp.h>
|
||||||
|
|
||||||
@@ -30,6 +31,21 @@
|
|||||||
#include "BQ25713.h"
|
#include "BQ25713.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// WARNING! THRESHOLD + HYSTERESIS should be less than regulated VDD voltage - which depends on board
|
||||||
|
// and is 3.0 or 3.3V. Also VDD likes to read values like 2.9999 so make sure you account for that
|
||||||
|
// otherwise board will not boot at all. Before you modify this part - please triple read NRF52840 power design
|
||||||
|
// section in datasheet and you understand how REG0 and REG1 regulators work together.
|
||||||
|
#ifndef SAFE_VDD_VOLTAGE_THRESHOLD
|
||||||
|
#define SAFE_VDD_VOLTAGE_THRESHOLD 2.7
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// hysteresis value
|
||||||
|
#ifndef SAFE_VDD_VOLTAGE_THRESHOLD_HYST
|
||||||
|
#define SAFE_VDD_VOLTAGE_THRESHOLD_HYST 0.2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t getVDDVoltage();
|
||||||
|
|
||||||
// Weak empty variant initialization function.
|
// Weak empty variant initialization function.
|
||||||
// May be redefined by variant files.
|
// May be redefined by variant files.
|
||||||
void variant_shutdown() __attribute__((weak));
|
void variant_shutdown() __attribute__((weak));
|
||||||
@@ -38,12 +54,95 @@ void variant_shutdown() {}
|
|||||||
static nrfx_wdt_t nrfx_wdt = NRFX_WDT_INSTANCE(0);
|
static nrfx_wdt_t nrfx_wdt = NRFX_WDT_INSTANCE(0);
|
||||||
static nrfx_wdt_channel_id nrfx_wdt_channel_id_nrf52_main;
|
static nrfx_wdt_channel_id nrfx_wdt_channel_id_nrf52_main;
|
||||||
|
|
||||||
|
// This is a public global so that the debugger can set it to false automatically from our gdbinit
|
||||||
|
// @phaseloop comment: most part of codebase, including filesystem flash driver depend on softdevice
|
||||||
|
// methods so disabling it may actually crash thing. Proceed with caution.
|
||||||
|
|
||||||
|
bool useSoftDevice = true; // Set to false for easier debugging
|
||||||
|
|
||||||
static inline void debugger_break(void)
|
static inline void debugger_break(void)
|
||||||
{
|
{
|
||||||
__asm volatile("bkpt #0x01\n\t"
|
__asm volatile("bkpt #0x01\n\t"
|
||||||
"mov pc, lr\n\t");
|
"mov pc, lr\n\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PowerHAL NRF52 specific function implementations
|
||||||
|
bool powerHAL_isVBUSConnected()
|
||||||
|
{
|
||||||
|
return NRF_POWER->USBREGSTATUS & POWER_USBREGSTATUS_VBUSDETECT_Msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool powerHAL_isPowerLevelSafe()
|
||||||
|
{
|
||||||
|
|
||||||
|
static bool powerLevelSafe = true;
|
||||||
|
|
||||||
|
uint16_t threshold = SAFE_VDD_VOLTAGE_THRESHOLD * 1000; // convert V to mV
|
||||||
|
uint16_t hysteresis = SAFE_VDD_VOLTAGE_THRESHOLD_HYST * 1000;
|
||||||
|
|
||||||
|
if (powerLevelSafe) {
|
||||||
|
if (getVDDVoltage() < threshold) {
|
||||||
|
powerLevelSafe = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// power level is only safe again when it raises above threshold + hysteresis
|
||||||
|
if (getVDDVoltage() >= (threshold + hysteresis)) {
|
||||||
|
powerLevelSafe = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return powerLevelSafe;
|
||||||
|
}
|
||||||
|
|
||||||
|
void powerHAL_platformInit()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Enable POF power failure comparator. It will prevent writing to NVMC flash when supply voltage is too low.
|
||||||
|
// Set to some low value as last resort - powerHAL_isPowerLevelSafe uses different method and should manage proper node
|
||||||
|
// behaviour on its own.
|
||||||
|
|
||||||
|
// POFWARN is pretty useless for node power management because it triggers only once and clearing this event will not
|
||||||
|
// re-trigger it again until voltage rises to safe level and drops again. So we will use SAADC routed to VDD to read safely
|
||||||
|
// voltage.
|
||||||
|
|
||||||
|
// @phaseloop: I disable POFCON for now because it seems to be unreliable or buggy. Even when set at 2.0V it
|
||||||
|
// triggers below 2.8V and corrupts data when pairing bluetooth - because it prevents filesystem writes and
|
||||||
|
// adafruit BLE library triggers lfs_assert which reboots node and formats filesystem.
|
||||||
|
// I did experiments with bench power supply and no matter what is set to POFCON, it always triggers right below
|
||||||
|
// 2.8V. I compared raw registry values with datasheet.
|
||||||
|
|
||||||
|
NRF_POWER->POFCON =
|
||||||
|
((POWER_POFCON_THRESHOLD_V22 << POWER_POFCON_THRESHOLD_Pos) | (POWER_POFCON_POF_Enabled << POWER_POFCON_POF_Pos));
|
||||||
|
|
||||||
|
// remember to always match VBAT_AR_INTERNAL with AREF_VALUE in variant definition file
|
||||||
|
#ifdef VBAT_AR_INTERNAL
|
||||||
|
analogReference(VBAT_AR_INTERNAL);
|
||||||
|
#else
|
||||||
|
analogReference(AR_INTERNAL); // 3.6V
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// get VDD voltage (in millivolts)
|
||||||
|
uint16_t getVDDVoltage()
|
||||||
|
{
|
||||||
|
// we use the same values as regular battery read so there is no conflict on SAADC
|
||||||
|
analogReadResolution(BATTERY_SENSE_RESOLUTION_BITS);
|
||||||
|
|
||||||
|
// VDD range on NRF52840 is 1.8-3.3V so we need to remap analog reference to 3.6V
|
||||||
|
// let's hope battery reading runs in same task and we don't have race condition
|
||||||
|
analogReference(AR_INTERNAL);
|
||||||
|
|
||||||
|
uint16_t vddADCRead = analogReadVDD();
|
||||||
|
float voltage = ((1000 * 3.6) / pow(2, BATTERY_SENSE_RESOLUTION_BITS)) * vddADCRead;
|
||||||
|
|
||||||
|
// restore default battery reading reference
|
||||||
|
#ifdef VBAT_AR_INTERNAL
|
||||||
|
analogReference(VBAT_AR_INTERNAL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return voltage;
|
||||||
|
}
|
||||||
|
|
||||||
bool loopCanSleep()
|
bool loopCanSleep()
|
||||||
{
|
{
|
||||||
// turn off sleep only while connected via USB
|
// turn off sleep only while connected via USB
|
||||||
@@ -72,22 +171,6 @@ void getMacAddr(uint8_t *dmac)
|
|||||||
dmac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
|
dmac[0] = src[5] | 0xc0; // MSB high two bits get set elsewhere in the bluetooth stack
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initBrownout()
|
|
||||||
{
|
|
||||||
auto vccthresh = POWER_POFCON_THRESHOLD_V24;
|
|
||||||
|
|
||||||
auto err_code = sd_power_pof_enable(POWER_POFCON_POF_Enabled);
|
|
||||||
assert(err_code == NRF_SUCCESS);
|
|
||||||
|
|
||||||
err_code = sd_power_pof_threshold_set(vccthresh);
|
|
||||||
assert(err_code == NRF_SUCCESS);
|
|
||||||
|
|
||||||
// We don't bother with setting up brownout if soft device is disabled - because during production we always use softdevice
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a public global so that the debugger can set it to false automatically from our gdbinit
|
|
||||||
bool useSoftDevice = true; // Set to false for easier debugging
|
|
||||||
|
|
||||||
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
#if !MESHTASTIC_EXCLUDE_BLUETOOTH
|
||||||
void setBluetoothEnable(bool enable)
|
void setBluetoothEnable(bool enable)
|
||||||
{
|
{
|
||||||
@@ -106,7 +189,6 @@ void setBluetoothEnable(bool enable)
|
|||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
nrf52Bluetooth = new NRF52Bluetooth();
|
nrf52Bluetooth = new NRF52Bluetooth();
|
||||||
nrf52Bluetooth->startDisabled();
|
nrf52Bluetooth->startDisabled();
|
||||||
initBrownout();
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@@ -120,9 +202,6 @@ void setBluetoothEnable(bool enable)
|
|||||||
LOG_DEBUG("Init NRF52 Bluetooth");
|
LOG_DEBUG("Init NRF52 Bluetooth");
|
||||||
nrf52Bluetooth = new NRF52Bluetooth();
|
nrf52Bluetooth = new NRF52Bluetooth();
|
||||||
nrf52Bluetooth->setup();
|
nrf52Bluetooth->setup();
|
||||||
|
|
||||||
// We delay brownout init until after BLE because BLE starts soft device
|
|
||||||
initBrownout();
|
|
||||||
}
|
}
|
||||||
// Already setup, apparently
|
// Already setup, apparently
|
||||||
else
|
else
|
||||||
@@ -192,9 +271,24 @@ extern "C" void lfs_assert(const char *reason)
|
|||||||
delay(500); // Give the serial port a bit of time to output that last message.
|
delay(500); // Give the serial port a bit of time to output that last message.
|
||||||
// Try setting GPREGRET with the SoftDevice first. If that fails (perhaps because the SD hasn't been initialize yet) then set
|
// Try setting GPREGRET with the SoftDevice first. If that fails (perhaps because the SD hasn't been initialize yet) then set
|
||||||
// NRF_POWER->GPREGRET directly.
|
// NRF_POWER->GPREGRET directly.
|
||||||
if (!(sd_power_gpregret_clr(0, 0xFF) == NRF_SUCCESS && sd_power_gpregret_set(0, NRF52_MAGIC_LFS_IS_CORRUPT) == NRF_SUCCESS)) {
|
|
||||||
NRF_POWER->GPREGRET = NRF52_MAGIC_LFS_IS_CORRUPT;
|
// TODO: this will/can crash CPU if bluetooth stack is not compiled in or bluetooth is not initialized
|
||||||
|
// (regardless if enabled or disabled) - as there is no live SoftDevice stack
|
||||||
|
// implement "safe" functions detecting softdevice stack state and using proper method to set registers
|
||||||
|
|
||||||
|
// do not set GPREGRET if POFWARN is triggered because it means lfs_assert reports flash undervoltage protection
|
||||||
|
// and not data corruption. Reboot is fine as boot procedure will wait until power level is safe again
|
||||||
|
|
||||||
|
if (!NRF_POWER->EVENTS_POFWARN) {
|
||||||
|
if (!(sd_power_gpregret_clr(0, 0xFF) == NRF_SUCCESS &&
|
||||||
|
sd_power_gpregret_set(0, NRF52_MAGIC_LFS_IS_CORRUPT) == NRF_SUCCESS)) {
|
||||||
|
NRF_POWER->GPREGRET = NRF52_MAGIC_LFS_IS_CORRUPT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: this should not be done when SoftDevice is enabled as device will not boot back on soft reset
|
||||||
|
// as some data is retained in RAM which will prevent re-enabling bluetooth stack
|
||||||
|
// Google what Nordic has to say about NVIC_* + SoftDevice
|
||||||
NVIC_SystemReset();
|
NVIC_SystemReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,11 +61,12 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state)
|
|||||||
{
|
{
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'p':
|
case 'p':
|
||||||
if (sscanf(arg, "%d", &TCPPort) < 1)
|
if (sscanf(arg, "%d", &TCPPort) < 1) {
|
||||||
return ARGP_ERR_UNKNOWN;
|
return ARGP_ERR_UNKNOWN;
|
||||||
else
|
} else {
|
||||||
checkConfigPort = false;
|
checkConfigPort = false;
|
||||||
printf("Using config file %d\n", TCPPort);
|
printf("Using config file %d\n", TCPPort);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
configPath = arg;
|
configPath = arg;
|
||||||
@@ -649,6 +650,19 @@ bool loadConfig(const char *configPath)
|
|||||||
if (yamlConfig["Lora"]["RF95_MAX_POWER"])
|
if (yamlConfig["Lora"]["RF95_MAX_POWER"])
|
||||||
portduino_config.rf95_max_power = yamlConfig["Lora"]["RF95_MAX_POWER"].as<int>(20);
|
portduino_config.rf95_max_power = yamlConfig["Lora"]["RF95_MAX_POWER"].as<int>(20);
|
||||||
|
|
||||||
|
if (yamlConfig["Lora"]["TX_GAIN_LORA"]) {
|
||||||
|
YAML::Node tx_gain_node = yamlConfig["Lora"]["TX_GAIN_LORA"];
|
||||||
|
if (tx_gain_node.IsSequence() && tx_gain_node.size() != 0) {
|
||||||
|
portduino_config.num_pa_points = min(tx_gain_node.size(), std::size(portduino_config.tx_gain_lora));
|
||||||
|
for (int i = 0; i < portduino_config.num_pa_points; i++) {
|
||||||
|
portduino_config.tx_gain_lora[i] = tx_gain_node[i].as<int>();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
portduino_config.num_pa_points = 1;
|
||||||
|
portduino_config.tx_gain_lora[0] = tx_gain_node.as<int>(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (portduino_config.lora_module != use_autoconf && portduino_config.lora_module != use_simradio &&
|
if (portduino_config.lora_module != use_autoconf && portduino_config.lora_module != use_simradio &&
|
||||||
!portduino_config.force_simradio) {
|
!portduino_config.force_simradio) {
|
||||||
portduino_config.dio2_as_rf_switch = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
|
portduino_config.dio2_as_rf_switch = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as<bool>(false);
|
||||||
@@ -874,10 +888,8 @@ bool loadConfig(const char *configPath)
|
|||||||
}
|
}
|
||||||
if (checkConfigPort) {
|
if (checkConfigPort) {
|
||||||
portduino_config.api_port = (yamlConfig["General"]["APIPort"]).as<int>(-1);
|
portduino_config.api_port = (yamlConfig["General"]["APIPort"]).as<int>(-1);
|
||||||
if (portduino_config.api_port != -1 &&
|
if (portduino_config.api_port != -1 && portduino_config.api_port > 1023 && portduino_config.api_port < 65536) {
|
||||||
portduino_config.api_port > 1023 &&
|
TCPPort = (portduino_config.api_port);
|
||||||
portduino_config.api_port < 65536) {
|
|
||||||
TCPPort = (portduino_config.api_port);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
portduino_config.mac_address = (yamlConfig["General"]["MACAddress"]).as<std::string>("");
|
portduino_config.mac_address = (yamlConfig["General"]["MACAddress"]).as<std::string>("");
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ extern struct portduino_config_struct {
|
|||||||
int lora_usb_pid = 0x5512;
|
int lora_usb_pid = 0x5512;
|
||||||
int lora_usb_vid = 0x1A86;
|
int lora_usb_vid = 0x1A86;
|
||||||
int spiSpeed = 2000000;
|
int spiSpeed = 2000000;
|
||||||
|
int num_pa_points = 1; // default to 1 point, with 0 gain
|
||||||
|
uint16_t tx_gain_lora[22] = {0};
|
||||||
pinMapping lora_cs_pin = {"Lora", "CS"};
|
pinMapping lora_cs_pin = {"Lora", "CS"};
|
||||||
pinMapping lora_irq_pin = {"Lora", "IRQ"};
|
pinMapping lora_irq_pin = {"Lora", "IRQ"};
|
||||||
pinMapping lora_busy_pin = {"Lora", "Busy"};
|
pinMapping lora_busy_pin = {"Lora", "Busy"};
|
||||||
@@ -231,6 +233,17 @@ extern struct portduino_config_struct {
|
|||||||
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
|
out << YAML::Key << "LR1120_MAX_POWER" << YAML::Value << lr1120_max_power;
|
||||||
if (rf95_max_power != 20)
|
if (rf95_max_power != 20)
|
||||||
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
|
out << YAML::Key << "RF95_MAX_POWER" << YAML::Value << rf95_max_power;
|
||||||
|
|
||||||
|
if (num_pa_points > 1) {
|
||||||
|
out << YAML::Key << "TX_GAIN_LORA" << YAML::Value << YAML::Flow << YAML::BeginSeq;
|
||||||
|
for (int i = 0; i < num_pa_points; i++) {
|
||||||
|
out << YAML::Value << tx_gain_lora[i];
|
||||||
|
}
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
} else if (tx_gain_lora[0] != 0) {
|
||||||
|
out << YAML::Key << "TX_GAIN_LORA" << YAML::Value << tx_gain_lora[0];
|
||||||
|
}
|
||||||
|
|
||||||
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
|
out << YAML::Key << "DIO2_AS_RF_SWITCH" << YAML::Value << dio2_as_rf_switch;
|
||||||
if (dio3_tcxo_voltage != 0)
|
if (dio3_tcxo_voltage != 0)
|
||||||
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;
|
out << YAML::Key << "DIO3_TCXO_VOLTAGE" << YAML::Value << YAML::Precision(3) << (float)dio3_tcxo_voltage / 1000;
|
||||||
|
|||||||
19
src/power/PowerHAL.cpp
Normal file
19
src/power/PowerHAL.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
#include "PowerHAL.h"
|
||||||
|
|
||||||
|
void powerHAL_init()
|
||||||
|
{
|
||||||
|
return powerHAL_platformInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak, noinline)) void powerHAL_platformInit() {}
|
||||||
|
|
||||||
|
__attribute__((weak, noinline)) bool powerHAL_isPowerLevelSafe()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak, noinline)) bool powerHAL_isVBUSConnected()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
26
src/power/PowerHAL.h
Normal file
26
src/power/PowerHAL.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Power Hardware Abstraction Layer. Set of API calls to offload power management, measurements, reboots, etc
|
||||||
|
to the platform and variant code to avoid #ifdef spaghetti hell and limitless device-based edge cases
|
||||||
|
in the main firmware code
|
||||||
|
|
||||||
|
Functions declared here (with exception of powerHAL_init) should be defined in platform specific codebase.
|
||||||
|
Default function body does usually nothing.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Initialize HAL layer. Call it as early as possible during device boot
|
||||||
|
// do not overwrite it as it's not declared with "weak" attribute.
|
||||||
|
void powerHAL_init();
|
||||||
|
|
||||||
|
// platform specific init code if needed to be run early on boot
|
||||||
|
void powerHAL_platformInit();
|
||||||
|
|
||||||
|
// Return true if current battery level is safe for device operation (for example flash writes).
|
||||||
|
// This should be reported by power failure comparator (NRF52) or similar circuits on other platforms.
|
||||||
|
// Do not use battery ADC as improper ADC configuration may prevent device from booting.
|
||||||
|
bool powerHAL_isPowerLevelSafe();
|
||||||
|
|
||||||
|
// return if USB voltage is connected
|
||||||
|
bool powerHAL_isVBUSConnected();
|
||||||
@@ -6,6 +6,8 @@ build_flags =
|
|||||||
${esp32_base.build_flags}
|
${esp32_base.build_flags}
|
||||||
-D CHATTER_2
|
-D CHATTER_2
|
||||||
-I variants/esp32/chatter2
|
-I variants/esp32/chatter2
|
||||||
|
-DMESHTASTIC_EXCLUDE_WEBSERVER=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
|
||||||
|
|
||||||
lib_deps =
|
lib_deps =
|
||||||
${esp32_base.lib_deps}
|
${esp32_base.lib_deps}
|
||||||
|
|||||||
@@ -7,3 +7,22 @@ custom_esp32_kind = esp32
|
|||||||
build_flags =
|
build_flags =
|
||||||
${esp32_common.build_flags}
|
${esp32_common.build_flags}
|
||||||
-DMESHTASTIC_EXCLUDE_AUDIO=1
|
-DMESHTASTIC_EXCLUDE_AUDIO=1
|
||||||
|
; Override lib_deps to use environmental_extra_no_bsec instead of environmental_extra
|
||||||
|
; BSEC library uses ~3.5KB DRAM which causes overflow on original ESP32 targets
|
||||||
|
lib_deps =
|
||||||
|
${arduino_base.lib_deps}
|
||||||
|
${networking_base.lib_deps}
|
||||||
|
${networking_extra.lib_deps}
|
||||||
|
${environmental_base.lib_deps}
|
||||||
|
${environmental_extra_no_bsec.lib_deps}
|
||||||
|
${radiolib_base.lib_deps}
|
||||||
|
# renovate: datasource=git-refs depName=meshtastic-esp32_https_server packageName=https://github.com/meshtastic/esp32_https_server gitBranch=master
|
||||||
|
https://github.com/meshtastic/esp32_https_server/archive/3223704846752e6d545139204837bdb2a55459ca.zip
|
||||||
|
# renovate: datasource=custom.pio depName=NimBLE-Arduino packageName=h2zero/library/NimBLE-Arduino
|
||||||
|
h2zero/NimBLE-Arduino@^1.4.3
|
||||||
|
# renovate: datasource=git-refs depName=libpax packageName=https://github.com/dbinfrago/libpax gitBranch=master
|
||||||
|
https://github.com/dbinfrago/libpax/archive/3cdc0371c375676a97967547f4065607d4c53fd1.zip
|
||||||
|
# renovate: datasource=github-tags depName=XPowersLib packageName=lewisxhe/XPowersLib
|
||||||
|
https://github.com/lewisxhe/XPowersLib/archive/v0.3.2.zip
|
||||||
|
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
|
||||||
|
rweather/Crypto@0.4.0
|
||||||
@@ -16,6 +16,8 @@ build_flags =
|
|||||||
${esp32_base.build_flags}
|
${esp32_base.build_flags}
|
||||||
-I variants/esp32/m5stack_core
|
-I variants/esp32/m5stack_core
|
||||||
-DM5STACK
|
-DM5STACK
|
||||||
|
-DMESHTASTIC_EXCLUDE_WEBSERVER=1
|
||||||
|
-DMESHTASTIC_EXCLUDE_PAXCOUNTER=1
|
||||||
-DUSER_SETUP_LOADED
|
-DUSER_SETUP_LOADED
|
||||||
-DTFT_SDA_READ
|
-DTFT_SDA_READ
|
||||||
-DTFT_DRIVER=0x9341
|
-DTFT_DRIVER=0x9341
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ custom_meshtastic_tags = M5Stack
|
|||||||
|
|
||||||
extends = esp32c6_base
|
extends = esp32c6_base
|
||||||
board = esp32-c6-devkitc-1
|
board = esp32-c6-devkitc-1
|
||||||
|
board_upload.flash_size = 16MB
|
||||||
|
board_build.partitions = default_16MB.csv
|
||||||
;OpenOCD flash method
|
;OpenOCD flash method
|
||||||
;upload_protocol = esp-builtin
|
;upload_protocol = esp-builtin
|
||||||
;Normal method
|
;Normal method
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
// DIO6 -> RFSW1_V2
|
// DIO6 -> RFSW1_V2
|
||||||
// DIO7 -> not connected on E80 module - note that GNSS and Wifi scanning are not possible.
|
// DIO7 -> not connected on E80 module - note that GNSS and Wifi scanning are not possible.
|
||||||
|
|
||||||
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7, RADIOLIB_NC, RADIOLIB_NC};
|
static const uint32_t rfswitch_dio_pins[] = {RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_LR11X0_DIO7, RADIOLIB_NC,
|
||||||
|
RADIOLIB_NC};
|
||||||
|
|
||||||
static const Module::RfSwitchMode_t rfswitch_table[] = {
|
static const Module::RfSwitchMode_t rfswitch_table[] = {
|
||||||
// mode DIO5 DIO6 DIO7
|
// mode DIO5 DIO6 DIO7
|
||||||
|
|||||||
@@ -67,4 +67,8 @@ void variant_shutdown()
|
|||||||
nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
|
nrf_gpio_cfg_input(PIN_BUTTON1, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
|
||||||
nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
|
nrf_gpio_pin_sense_t sense1 = NRF_GPIO_PIN_SENSE_LOW;
|
||||||
nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense1);
|
nrf_gpio_cfg_sense_set(PIN_BUTTON1, sense1);
|
||||||
|
|
||||||
|
nrf_gpio_cfg_input(EXT_CHRG_DETECT, NRF_GPIO_PIN_PULLUP); // Configure the pin to be woken up as an input
|
||||||
|
nrf_gpio_pin_sense_t sense2 = NRF_GPIO_PIN_SENSE_LOW;
|
||||||
|
nrf_gpio_cfg_sense_set(EXT_CHRG_DETECT, sense2);
|
||||||
}
|
}
|
||||||
|
|||||||
9
variants/nrf52840/dls_Minimesh_Lite/platformio.ini
Normal file
9
variants/nrf52840/dls_Minimesh_Lite/platformio.ini
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[env:minimesh_lite]
|
||||||
|
extends = nrf52840_base
|
||||||
|
board = minimesh_lite
|
||||||
|
board_level = extra
|
||||||
|
build_flags = ${nrf52840_base.build_flags}
|
||||||
|
-Ivariants/nrf52840/dls_Minimesh_Lite
|
||||||
|
-DPRIVATE_HW
|
||||||
|
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/dls_Minimesh_Lite>
|
||||||
|
debug_tool = jlink
|
||||||
38
variants/nrf52840/dls_Minimesh_Lite/variant.cpp
Normal file
38
variants/nrf52840/dls_Minimesh_Lite/variant.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
|
||||||
|
Copyright (c) 2016 Sandeep Mistry All right reserved.
|
||||||
|
Copyright (c) 2018, Adafruit Industries (adafruit.com)
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "variant.h"
|
||||||
|
#include "nrf.h"
|
||||||
|
#include "wiring_constants.h"
|
||||||
|
#include "wiring_digital.h"
|
||||||
|
|
||||||
|
const uint32_t g_ADigitalPinMap[] = {
|
||||||
|
// P0
|
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
|
||||||
|
// P1
|
||||||
|
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
|
||||||
|
|
||||||
|
void initVariant()
|
||||||
|
{
|
||||||
|
// 3V3 Power Rail
|
||||||
|
pinMode(PIN_3V3_EN, OUTPUT);
|
||||||
|
digitalWrite(PIN_3V3_EN, HIGH);
|
||||||
|
}
|
||||||
104
variants/nrf52840/dls_Minimesh_Lite/variant.h
Normal file
104
variants/nrf52840/dls_Minimesh_Lite/variant.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#ifndef _VARIANT_MINIMESH_LITE_
|
||||||
|
#define _VARIANT_MINIMESH_LITE_
|
||||||
|
|
||||||
|
#define VARIANT_MCK (64000000ul)
|
||||||
|
#define USE_LFRC
|
||||||
|
|
||||||
|
#include "WVariant.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MINIMESH_LITE
|
||||||
|
|
||||||
|
// Number of pins defined in PinDescription array
|
||||||
|
#define PINS_COUNT (48)
|
||||||
|
#define NUM_DIGITAL_PINS (48)
|
||||||
|
#define NUM_ANALOG_INPUTS (1)
|
||||||
|
#define NUM_ANALOG_OUTPUTS (0)
|
||||||
|
|
||||||
|
#define PIN_3V3_EN (0 + 13) // P0.13
|
||||||
|
|
||||||
|
// Analog pins
|
||||||
|
#define BATTERY_PIN (0 + 31) // P0.31 Battery ADC
|
||||||
|
#define ADC_CHANNEL ADC1_GPIO4_CHANNEL
|
||||||
|
#define ADC_RESOLUTION 14
|
||||||
|
#define BATTERY_SENSE_RESOLUTION_BITS 12
|
||||||
|
#define BATTERY_SENSE_RESOLUTION 4096.0
|
||||||
|
#define VBAT_MV_PER_LSB (0.73242188F)
|
||||||
|
#define VBAT_DIVIDER (0.6F)
|
||||||
|
#define VBAT_DIVIDER_COMP (1.73)
|
||||||
|
#define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB)
|
||||||
|
#undef AREF_VOLTAGE
|
||||||
|
#define AREF_VOLTAGE 3.0
|
||||||
|
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
|
||||||
|
#define ADC_MULTIPLIER VBAT_DIVIDER_COMP
|
||||||
|
#define VBAT_RAW_TO_SCALED(x) (REAL_VBAT_MV_PER_LSB * x)
|
||||||
|
|
||||||
|
// WIRE IC AND IIC PINS
|
||||||
|
#define WIRE_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_WIRE_SDA (32 + 4)
|
||||||
|
#define PIN_WIRE_SCL (0 + 11)
|
||||||
|
|
||||||
|
// LED
|
||||||
|
#define PIN_LED1 (0 + 15)
|
||||||
|
#define LED_BUILTIN PIN_LED1
|
||||||
|
// Actually red
|
||||||
|
#define LED_BLUE PIN_LED1
|
||||||
|
#define LED_STATE_ON 1
|
||||||
|
|
||||||
|
// Button
|
||||||
|
#define BUTTON_PIN (32 + 0)
|
||||||
|
|
||||||
|
// GPS
|
||||||
|
#define GPS_TX_PIN (0 + 20)
|
||||||
|
#define GPS_RX_PIN (0 + 22)
|
||||||
|
|
||||||
|
#define PIN_GPS_EN (0 + 24)
|
||||||
|
#define GPS_UBLOX
|
||||||
|
// define GPS_DEBUG
|
||||||
|
|
||||||
|
// UART interfaces
|
||||||
|
#define PIN_SERIAL1_TX GPS_TX_PIN
|
||||||
|
#define PIN_SERIAL1_RX GPS_RX_PIN
|
||||||
|
|
||||||
|
#define PIN_SERIAL2_RX (0 + 6)
|
||||||
|
#define PIN_SERIAL2_TX (0 + 8)
|
||||||
|
|
||||||
|
// Serial interfaces
|
||||||
|
#define SPI_INTERFACES_COUNT 1
|
||||||
|
|
||||||
|
#define PIN_SPI_MISO (0 + 2)
|
||||||
|
#define PIN_SPI_MOSI (32 + 15)
|
||||||
|
#define PIN_SPI_SCK (32 + 11)
|
||||||
|
|
||||||
|
#define LORA_MISO PIN_SPI_MISO
|
||||||
|
#define LORA_MOSI PIN_SPI_MOSI
|
||||||
|
#define LORA_SCK PIN_SPI_SCK
|
||||||
|
#define LORA_CS (32 + 13)
|
||||||
|
|
||||||
|
// LORA MODULES
|
||||||
|
#define USE_LLCC68
|
||||||
|
#define USE_SX1262
|
||||||
|
#define USE_SX1268
|
||||||
|
|
||||||
|
// SX126X CONFIG
|
||||||
|
#define SX126X_CS (32 + 13)
|
||||||
|
#define SX126X_DIO1 (0 + 10)
|
||||||
|
#define SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
|
||||||
|
#define SX126X_BUSY (0 + 29)
|
||||||
|
#define SX126X_RESET (0 + 9)
|
||||||
|
#define SX126X_RXEN (0 + 17)
|
||||||
|
#define SX126X_TXEN RADIOLIB_NC
|
||||||
|
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
|
||||||
|
#define TCXO_OPTIONAL // make it so that the firmware can try both TCXO and XTAL
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _VARIANT_MINIMESH_LITE_
|
||||||
@@ -150,6 +150,14 @@ No longer populated on PCB
|
|||||||
#define PIN_SPI1_MOSI ST7789_SDA
|
#define PIN_SPI1_MOSI ST7789_SDA
|
||||||
#define PIN_SPI1_SCK ST7789_SCK
|
#define PIN_SPI1_SCK ST7789_SCK
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bluetooth
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The bluetooth transmit power on the nRF52840 is adjustable from -20dB to +8dB in steps of 4dB
|
||||||
|
// so NRF52_BLE_TX_POWER can be set to -20, -16, -12, -8, -4, 0 (default), 4, and 8.
|
||||||
|
//#define NRF52_BLE_TX_POWER 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPS pins
|
* GPS pins
|
||||||
*/
|
*/
|
||||||
|
|||||||
21
variants/stm32/russell/platformio.ini
Normal file
21
variants/stm32/russell/platformio.ini
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
; Russell is a board designed to mount on an ER34615/IFR32700 cell and go Up! on a balloon
|
||||||
|
; Hardware repository: https://github.com/Meshtastic-Malaysia/russell
|
||||||
|
; - RAK3172 STM32WLE5CCU6 MCU + integrated SX1262 LoRa
|
||||||
|
; - CDtop CD-PA1010D GPS
|
||||||
|
; - Bosch Sensortec BME280 sensor
|
||||||
|
; - Consonance CN3158 LiFePO4 solar charger
|
||||||
|
[env:russell]
|
||||||
|
extends = stm32_base
|
||||||
|
board = wiscore_rak3172
|
||||||
|
board_level = extra
|
||||||
|
board_upload.maximum_size = 233472 ; reserve the last 28KB for filesystem
|
||||||
|
build_flags =
|
||||||
|
${stm32_base.build_flags}
|
||||||
|
-Ivariants/stm32/russell
|
||||||
|
-DPRIVATE_HW
|
||||||
|
lib_deps =
|
||||||
|
${stm32_base.lib_deps}
|
||||||
|
# renovate: datasource=custom.pio depName=Adafruit BME280 packageName=adafruit/library/Adafruit BME280 Library
|
||||||
|
adafruit/Adafruit BME280 Library@2.3.0
|
||||||
|
|
||||||
|
upload_port = stlink
|
||||||
7
variants/stm32/russell/rfswitch.h
Normal file
7
variants/stm32/russell/rfswitch.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
// Pins from https://forum.rakwireless.com/t/rak3172-internal-schematic/4557/2
|
||||||
|
// PB8, PC13
|
||||||
|
|
||||||
|
static const RADIOLIB_PIN_TYPE rfswitch_pins[5] = {PB8, PC13, RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC};
|
||||||
|
|
||||||
|
static const Module::RfSwitchMode_t rfswitch_table[4] = {
|
||||||
|
{STM32WLx::MODE_IDLE, {LOW, LOW}}, {STM32WLx::MODE_RX, {HIGH, LOW}}, {STM32WLx::MODE_TX_HP, {LOW, HIGH}}, END_OF_MODE_TABLE};
|
||||||
41
variants/stm32/russell/variant.h
Normal file
41
variants/stm32/russell/variant.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#ifndef _VARIANT_RUSSELL_
|
||||||
|
#define _VARIANT_RUSSELL_
|
||||||
|
|
||||||
|
#define USE_STM32WLx
|
||||||
|
|
||||||
|
// I/O
|
||||||
|
#define LED_PIN PA0 // Red LED
|
||||||
|
#define LED_STATE_ON 1
|
||||||
|
#define BUTTON_PIN PH3 // Shared with BOOT0
|
||||||
|
#define BUTTON_NEED_PULLUP
|
||||||
|
// Charger IC charge/standby pins are open-drain with no hardware pull-up:
|
||||||
|
// Internal pull-up is needed on STM32 (TODO)
|
||||||
|
// #define EXT_CHRG_DETECT PA5
|
||||||
|
// #define EXT_PWR_DETECT PA4
|
||||||
|
|
||||||
|
// Bosch Sensortec BME280
|
||||||
|
#define HAS_SENSOR 1
|
||||||
|
|
||||||
|
// CDtop CD-PA1010D
|
||||||
|
#define ENABLE_HWSERIAL1
|
||||||
|
#define PIN_SERIAL1_RX PB7
|
||||||
|
#define PIN_SERIAL1_TX PB6
|
||||||
|
#define HAS_GPS 1
|
||||||
|
#define PIN_GPS_STANDBY PA15
|
||||||
|
#define GPS_RX_PIN PB7
|
||||||
|
#define GPS_TX_PIN PB6
|
||||||
|
|
||||||
|
// LoRa
|
||||||
|
/*
|
||||||
|
* RAK3172 (-20–85°C) -> No TCXO
|
||||||
|
* RAK3172-T (-40–85°C) -> 3.0V TCXO
|
||||||
|
* https://github.com/RAKWireless/RAK-STM32-RUI/blob/e5a28be8fab1a492bd9223dd425ca33a8a297d90/variants/WisDuo_RAK3172-T_Board/radio_conf.h#L91
|
||||||
|
*/
|
||||||
|
#define TCXO_OPTIONAL
|
||||||
|
#define SX126X_DIO3_TCXO_VOLTAGE 3.0
|
||||||
|
|
||||||
|
// Required to avoid Serial1 conflicts due to board definition here:
|
||||||
|
// https://github.com/stm32duino/Arduino_Core_STM32/blob/main/variants/STM32WLxx/WL54CCU_WL55CCU_WLE4C(8-B-C)U_WLE5C(8-B-C)U/variant_RAK3172_MODULE.h
|
||||||
|
#define RAK3172
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
[VERSION]
|
[VERSION]
|
||||||
major = 2
|
major = 2
|
||||||
minor = 7
|
minor = 7
|
||||||
build = 18
|
build = 19
|
||||||
|
|||||||
Reference in New Issue
Block a user