mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-13 22:32:27 +00:00
Compare commits
23 Commits
refactor-n
...
e6e3c04db1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6e3c04db1 | ||
|
|
c8628b3422 | ||
|
|
2ac74d6677 | ||
|
|
9d487ddc0d | ||
|
|
9dc1bcdc3d | ||
|
|
bcfe069997 | ||
|
|
a0cfea87a1 | ||
|
|
4fc96bdf83 | ||
|
|
4ef943f204 | ||
|
|
a8fa5f25cb | ||
|
|
3b2a1547de | ||
|
|
6f725a1996 | ||
|
|
467c042bf7 | ||
|
|
cc4c41167c | ||
|
|
fff2bbf4a0 | ||
|
|
fba92229a6 | ||
|
|
ff0a4ea320 | ||
|
|
83b603827c | ||
|
|
ee80ec7b68 | ||
|
|
ec0dfb7337 | ||
|
|
817f3b9ec8 | ||
|
|
0726bb4b56 | ||
|
|
6b11991be0 |
2
.github/actions/build-variant/action.yml
vendored
2
.github/actions/build-variant/action.yml
vendored
@@ -76,7 +76,7 @@ runs:
|
||||
done
|
||||
|
||||
- name: PlatformIO ${{ inputs.arch }} download cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.platformio/.cache
|
||||
key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }}
|
||||
|
||||
17
.github/workflows/main_matrix.yml
vendored
17
.github/workflows/main_matrix.yml
vendored
@@ -77,16 +77,21 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
check: ${{ fromJson(needs.setup.outputs.check) }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
# Use 'arctastic' self-hosted runner pool when checking in the main repo
|
||||
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
|
||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Build base
|
||||
id: base
|
||||
uses: ./.github/actions/setup-base
|
||||
with:
|
||||
submodules: recursive
|
||||
ref: ${{github.event.pull_request.head.ref}}
|
||||
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||
- name: Check ${{ matrix.check.board }}
|
||||
run: bin/check-all.sh ${{ matrix.check.board }}
|
||||
uses: meshtastic/gh-action-firmware@main
|
||||
with:
|
||||
pio_platform: ${{ matrix.check.platform }}
|
||||
pio_env: ${{ matrix.check.board }}
|
||||
pio_target: check
|
||||
|
||||
build:
|
||||
needs: [setup, version]
|
||||
|
||||
2
.github/workflows/release_channels.yml
vendored
2
.github/workflows/release_channels.yml
vendored
@@ -102,7 +102,7 @@ jobs:
|
||||
PIP_DISABLE_PIP_VERSION_CHECK: 1
|
||||
|
||||
- name: Create Bumps pull request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
base: ${{ github.event.repository.default_branch }}
|
||||
branch: create-pull-request/bump-version
|
||||
|
||||
2
.github/workflows/update_protobufs.yml
vendored
2
.github/workflows/update_protobufs.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
./bin/regen-protos.sh
|
||||
|
||||
- name: Create pull request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@v8
|
||||
with:
|
||||
branch: create-pull-request/update-protobufs
|
||||
labels: submodules
|
||||
|
||||
@@ -9,24 +9,24 @@ plugins:
|
||||
lint:
|
||||
enabled:
|
||||
- checkov@3.2.495
|
||||
- renovate@42.30.4
|
||||
- renovate@42.44.0
|
||||
- prettier@3.7.4
|
||||
- trufflehog@3.91.2
|
||||
- trufflehog@3.92.2
|
||||
- yamllint@1.37.1
|
||||
- bandit@1.9.2
|
||||
- trivy@0.67.2
|
||||
- trivy@0.68.1
|
||||
- taplo@0.10.0
|
||||
- ruff@0.14.7
|
||||
- ruff@0.14.8
|
||||
- isort@7.0.0
|
||||
- markdownlint@0.46.0
|
||||
- oxipng@9.1.5
|
||||
- markdownlint@0.47.0
|
||||
- oxipng@10.0.0
|
||||
- svgo@4.0.0
|
||||
- actionlint@1.7.9
|
||||
- flake8@7.3.0
|
||||
- hadolint@2.14.0
|
||||
- shfmt@3.6.0
|
||||
- shellcheck@0.11.0
|
||||
- black@25.11.0
|
||||
- black@25.12.0
|
||||
- git-diff-check
|
||||
- gitleaks@8.30.0
|
||||
- clang-format@16.0.3
|
||||
|
||||
@@ -22,7 +22,7 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
@@ -32,20 +32,10 @@ cp $BUILDDIR/$basename.factory.bin $OUTDIR/$basename.factory.bin
|
||||
echo "Copying ESP32 update bin file"
|
||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||
|
||||
echo "Building Filesystem for ESP32 targets"
|
||||
# If you want to build the webui, uncomment the following lines
|
||||
# pio run --environment $1 -t buildfs
|
||||
# cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$1-$VERSION.bin
|
||||
# # Remove webserver files from the filesystem and rebuild
|
||||
# ls -l data/static # Diagnostic list of files
|
||||
# rm -rf data/static
|
||||
pio run --environment $1 -t buildfs --disable-auto-clean
|
||||
echo "Copying Filesystem for ESP32 targets"
|
||||
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
|
||||
cp bin/device-install.* $OUTDIR/
|
||||
cp bin/device-update.* $OUTDIR/
|
||||
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -22,7 +22,7 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
@@ -47,8 +47,5 @@ if (echo $1 | grep -q "rak4631"); then
|
||||
cp $SRCHEX $OUTDIR/
|
||||
fi
|
||||
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -22,15 +22,12 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying uf2 file"
|
||||
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
||||
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -22,15 +22,12 @@ export APP_VERSION=$VERSION
|
||||
|
||||
basename=firmware-$1-$VERSION
|
||||
|
||||
pio run --environment $1 # -v
|
||||
pio run --environment $1 -t mtjson # -v
|
||||
|
||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||
|
||||
echo "Copying STM32 bin file"
|
||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||
|
||||
# Generate the manifest file
|
||||
echo "Generating Meshtastic manifest"
|
||||
TIMEFORMAT="Generated manifest in %E seconds"
|
||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
||||
echo "Copying manifest"
|
||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||
|
||||
@@ -159,20 +159,22 @@ def load_boot_logo(source, target, env):
|
||||
|
||||
# Load the boot logo on TFT builds
|
||||
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
|
||||
env.AddPreAction('$BUILD_DIR/littlefs.bin', load_boot_logo)
|
||||
env.AddPreAction(f"$BUILD_DIR/{lfsbin}", load_boot_logo)
|
||||
|
||||
# Rename (mv) littlefs.bin to include the PROGNAME
|
||||
# This ensures the littlefs.bin is named consistently with the firmware
|
||||
env.AddPostAction('$BUILD_DIR/littlefs.bin', env.VerboseAction(
|
||||
f'mv $BUILD_DIR/littlefs.bin $BUILD_DIR/{lfsbin}',
|
||||
f'Renaming littlefs.bin to {lfsbin}'
|
||||
))
|
||||
mtjson_deps = ["buildprog"]
|
||||
if platform.name == "espressif32":
|
||||
# Build littlefs image as part of mtjson target
|
||||
# Equivalent to `pio run -t buildfs`
|
||||
target_lfs = env.DataToBin(
|
||||
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR"
|
||||
)
|
||||
mtjson_deps.append(target_lfs)
|
||||
|
||||
env.AddCustomTarget(
|
||||
name="mtjson",
|
||||
dependencies=None,
|
||||
dependencies=mtjson_deps,
|
||||
actions=[manifest_gather],
|
||||
title="Meshtastic Manifest",
|
||||
description="Generating Meshtastic manifest JSON + Checksums",
|
||||
always_build=True,
|
||||
always_build=False,
|
||||
)
|
||||
|
||||
@@ -11,6 +11,9 @@ else:
|
||||
prefsLoc = env["PROJECT_DIR"] + "/version.properties"
|
||||
verObj = readProps(prefsLoc)
|
||||
env.Replace(PROGNAME=f"firmware-{env.get('PIOENV')}-{verObj['long']}")
|
||||
env.Replace(ESP32_FS_IMAGE_NAME=f"littlefs-{env.get('PIOENV')}-{verObj['long']}")
|
||||
|
||||
# Print the new program name for verification
|
||||
print(f"PROGNAME: {env.get('PROGNAME')}")
|
||||
if platform.name == "espressif32":
|
||||
print(f"ESP32_FS_IMAGE_NAME: {env.get('ESP32_FS_IMAGE_NAME')}")
|
||||
|
||||
@@ -10,6 +10,12 @@ Import("env")
|
||||
platform = env.PioPlatform()
|
||||
|
||||
sys.path.append(join(platform.get_package_dir("tool-esptoolpy")))
|
||||
# IntelHex workaround, remove after fixed upstream
|
||||
# https://github.com/platformio/platform-espressif32/issues/1632
|
||||
try:
|
||||
import intelhex
|
||||
except ImportError:
|
||||
env.Execute("$PYTHONEXE -m pip install intelhex")
|
||||
import esptool
|
||||
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ lib_deps =
|
||||
[device-ui_base]
|
||||
lib_deps =
|
||||
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
|
||||
https://github.com/meshtastic/device-ui/archive/4fb5f24787caa841b58dbf623a52c4c5861d6722.zip
|
||||
https://github.com/meshtastic/device-ui/archive/2746a1ce3804998460a2cb319b8ea8a238dfd8c9.zip
|
||||
|
||||
; Common libs for environmental measurements in telemetry module
|
||||
[environmental_base]
|
||||
|
||||
@@ -532,8 +532,10 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
const int labelX = x;
|
||||
int barsOffset = (isHighResolution) ? 24 : 0;
|
||||
#ifdef USE_EINK
|
||||
#ifndef T_DECK_PRO
|
||||
barsOffset -= 12;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
const int barX = x + 45 + barsOffset;
|
||||
#else
|
||||
@@ -574,7 +576,7 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x
|
||||
#endif
|
||||
// Value string
|
||||
display->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display->drawString(SCREEN_WIDTH - 2, getTextPositions(display)[line], combinedStr);
|
||||
display->drawString(SCREEN_WIDTH, getTextPositions(display)[line], combinedStr);
|
||||
};
|
||||
|
||||
// === Memory values ===
|
||||
|
||||
@@ -53,6 +53,7 @@ typedef struct _InputEvent {
|
||||
class InputPollable
|
||||
{
|
||||
public:
|
||||
virtual ~InputPollable() = default;
|
||||
virtual void pollOnce() = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "RotaryEncoderImpl.h"
|
||||
#include "InputBroker.h"
|
||||
#include "RotaryEncoder.h"
|
||||
#ifdef ARCH_ESP32
|
||||
#include "sleep.h"
|
||||
#endif
|
||||
|
||||
#define ORIGIN_NAME "RotaryEncoder"
|
||||
|
||||
@@ -11,6 +14,20 @@ RotaryEncoderImpl *rotaryEncoderImpl;
|
||||
RotaryEncoderImpl::RotaryEncoderImpl()
|
||||
{
|
||||
rotary = nullptr;
|
||||
#ifdef ARCH_ESP32
|
||||
isFirstInit = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
RotaryEncoderImpl::~RotaryEncoderImpl()
|
||||
{
|
||||
LOG_DEBUG("RotaryEncoderImpl destructor");
|
||||
detachRotaryEncoderInterrupts();
|
||||
|
||||
if (rotary != nullptr) {
|
||||
delete rotary;
|
||||
rotary = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool RotaryEncoderImpl::init()
|
||||
@@ -25,15 +42,22 @@ bool RotaryEncoderImpl::init()
|
||||
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
|
||||
eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
|
||||
|
||||
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
||||
moduleConfig.canned_message.inputbroker_pin_press);
|
||||
rotary->resetButton();
|
||||
if (rotary == nullptr) {
|
||||
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
||||
moduleConfig.canned_message.inputbroker_pin_press);
|
||||
}
|
||||
|
||||
interruptInstance = this;
|
||||
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
|
||||
attachRotaryEncoderInterrupts();
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Register callbacks for before and after lightsleep
|
||||
// Used to detach and reattach interrupts
|
||||
if (isFirstInit) {
|
||||
lsObserver.observe(¬ifyLightSleep);
|
||||
lsEndObserver.observe(¬ifyLightSleepEnd);
|
||||
isFirstInit = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
LOG_INFO("RotaryEncoder initialized pins(%d, %d, %d), events(%d, %d, %d)", moduleConfig.canned_message.inputbroker_pin_a,
|
||||
moduleConfig.canned_message.inputbroker_pin_b, moduleConfig.canned_message.inputbroker_pin_press, eventCw, eventCcw,
|
||||
@@ -71,6 +95,50 @@ void RotaryEncoderImpl::pollOnce()
|
||||
}
|
||||
}
|
||||
|
||||
void RotaryEncoderImpl::detachRotaryEncoderInterrupts()
|
||||
{
|
||||
LOG_DEBUG("RotaryEncoderImpl detach button interrupts");
|
||||
if (interruptInstance == this) {
|
||||
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_a);
|
||||
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_b);
|
||||
detachInterrupt(moduleConfig.canned_message.inputbroker_pin_press);
|
||||
interruptInstance = nullptr;
|
||||
} else {
|
||||
LOG_WARN("RotaryEncoderImpl: interrupts already detached");
|
||||
}
|
||||
}
|
||||
|
||||
void RotaryEncoderImpl::attachRotaryEncoderInterrupts()
|
||||
{
|
||||
LOG_DEBUG("RotaryEncoderImpl attach button interrupts");
|
||||
if (rotary != nullptr && interruptInstance == nullptr) {
|
||||
rotary->resetButton();
|
||||
|
||||
interruptInstance = this;
|
||||
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
|
||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
|
||||
} else {
|
||||
LOG_WARN("RotaryEncoderImpl: interrupts already attached");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
|
||||
int RotaryEncoderImpl::beforeLightSleep(void *unused)
|
||||
{
|
||||
detachRotaryEncoderInterrupts();
|
||||
return 0; // Indicates success;
|
||||
}
|
||||
|
||||
int RotaryEncoderImpl::afterLightSleep(esp_sleep_wakeup_cause_t cause)
|
||||
{
|
||||
attachRotaryEncoderInterrupts();
|
||||
return 0; // Indicates success;
|
||||
}
|
||||
#endif
|
||||
|
||||
RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance;
|
||||
|
||||
#endif
|
||||
@@ -8,12 +8,18 @@
|
||||
|
||||
class RotaryEncoder;
|
||||
|
||||
class RotaryEncoderImpl : public InputPollable
|
||||
class RotaryEncoderImpl final : public InputPollable
|
||||
{
|
||||
public:
|
||||
RotaryEncoderImpl();
|
||||
bool init(void);
|
||||
~RotaryEncoderImpl() override;
|
||||
bool init();
|
||||
virtual void pollOnce() override;
|
||||
// Disconnect and reconnect interrupts for light sleep
|
||||
#ifdef ARCH_ESP32
|
||||
int beforeLightSleep(void *unused);
|
||||
int afterLightSleep(esp_sleep_wakeup_cause_t cause);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
static RotaryEncoderImpl *interruptInstance;
|
||||
@@ -23,6 +29,21 @@ class RotaryEncoderImpl : public InputPollable
|
||||
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
||||
|
||||
RotaryEncoder *rotary;
|
||||
|
||||
private:
|
||||
#ifdef ARCH_ESP32
|
||||
bool isFirstInit;
|
||||
#endif
|
||||
void detachRotaryEncoderInterrupts();
|
||||
void attachRotaryEncoderInterrupts();
|
||||
|
||||
#ifdef ARCH_ESP32
|
||||
// Get notified when lightsleep begins and ends
|
||||
CallbackObserver<RotaryEncoderImpl, void *> lsObserver =
|
||||
CallbackObserver<RotaryEncoderImpl, void *>(this, &RotaryEncoderImpl::beforeLightSleep);
|
||||
CallbackObserver<RotaryEncoderImpl, esp_sleep_wakeup_cause_t> lsEndObserver =
|
||||
CallbackObserver<RotaryEncoderImpl, esp_sleep_wakeup_cause_t>(this, &RotaryEncoderImpl::afterLightSleep);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
||||
|
||||
@@ -805,11 +805,15 @@ void NodeDB::installDefaultModuleConfig()
|
||||
moduleConfig.external_notification.output_ms = 500;
|
||||
moduleConfig.external_notification.nag_timeout = 2;
|
||||
#endif
|
||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312)
|
||||
// Default to RAK led pin 2 (blue)
|
||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3)
|
||||
// Default to PIN_LED2 for external notification output (LED color depends on device variant)
|
||||
moduleConfig.external_notification.enabled = true;
|
||||
moduleConfig.external_notification.output = PIN_LED2;
|
||||
#if defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3)
|
||||
moduleConfig.external_notification.active = false;
|
||||
#else
|
||||
moduleConfig.external_notification.active = true;
|
||||
#endif
|
||||
moduleConfig.external_notification.alert_message = true;
|
||||
moduleConfig.external_notification.output_ms = 1000;
|
||||
moduleConfig.external_notification.nag_timeout = default_ringtone_nag_secs;
|
||||
|
||||
@@ -217,7 +217,7 @@ void setupModules()
|
||||
}
|
||||
#endif // HAS_BUTTON
|
||||
#if ARCH_PORTDUINO
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
|
||||
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
|
||||
seesawRotary = new SeesawRotary("SeesawRotary");
|
||||
if (!seesawRotary->init()) {
|
||||
delete seesawRotary;
|
||||
|
||||
@@ -45,8 +45,12 @@ bool PositionModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, mes
|
||||
{
|
||||
auto p = *pptr;
|
||||
|
||||
// If inbound message is a replay (or spoof!) of our own messages, we shouldn't process
|
||||
// (why use second-hand sources for our own data?)
|
||||
const auto transport = mp.transport_mechanism;
|
||||
if (isFromUs(&mp) && !IS_ONE_OF(transport, meshtastic_MeshPacket_TransportMechanism_TRANSPORT_INTERNAL,
|
||||
meshtastic_MeshPacket_TransportMechanism_TRANSPORT_API)) {
|
||||
LOG_WARN("Ignoring packet supposedly from us over external transport");
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME this can in fact happen with packets sent from EUD (src=RX_SRC_USER)
|
||||
// to set fixed location, EUD-GPS location or just the time (see also issue #900)
|
||||
@@ -472,19 +476,53 @@ void PositionModule::sendLostAndFoundText()
|
||||
delete[] message;
|
||||
}
|
||||
|
||||
// Helper: return imprecise (truncated + centered) lat/lon as int32 using current precision
|
||||
static inline void computeImpreciseLatLon(int32_t inLat, int32_t inLon, uint8_t precisionBits, int32_t &outLat, int32_t &outLon)
|
||||
{
|
||||
if (precisionBits > 0 && precisionBits < 32) {
|
||||
// Build mask for top 'precisionBits' bits of a 32-bit unsigned field
|
||||
const uint32_t mask = (precisionBits == 32) ? UINT32_MAX : (UINT32_MAX << (32 - precisionBits));
|
||||
// Note: latitude_i/longitude_i are stored as signed 32-bit in meshtastic code but
|
||||
// the bitmask logic used previously operated as unsigned—preserve that behavior by
|
||||
// casting to uint32_t for masking, then back to int32_t.
|
||||
uint32_t lat_u = static_cast<uint32_t>(inLat) & mask;
|
||||
uint32_t lon_u = static_cast<uint32_t>(inLon) & mask;
|
||||
|
||||
// Add the "center of cell" offset used elsewhere:
|
||||
// The code previously added (1 << (31 - precision)) to produce the middle of the possible location.
|
||||
uint32_t center_offset = (1u << (31 - precisionBits));
|
||||
lat_u += center_offset;
|
||||
lon_u += center_offset;
|
||||
|
||||
outLat = static_cast<int32_t>(lat_u);
|
||||
outLon = static_cast<int32_t>(lon_u);
|
||||
} else {
|
||||
// full precision: return input unchanged
|
||||
outLat = inLat;
|
||||
outLon = inLon;
|
||||
}
|
||||
}
|
||||
|
||||
struct SmartPosition PositionModule::getDistanceTraveledSinceLastSend(meshtastic_PositionLite currentPosition)
|
||||
{
|
||||
// The minimum distance to travel before we are able to send a new position packet.
|
||||
const uint32_t distanceTravelThreshold =
|
||||
Default::getConfiguredOrDefault(config.position.broadcast_smart_minimum_distance, 100);
|
||||
|
||||
// Determine the distance in meters between two points on the globe
|
||||
float distanceTraveledSinceLastSend = GeoCoord::latLongToMeter(
|
||||
lastGpsLatitude * 1e-7, lastGpsLongitude * 1e-7, currentPosition.latitude_i * 1e-7, currentPosition.longitude_i * 1e-7);
|
||||
int32_t lastLatImprecise, lastLonImprecise;
|
||||
int32_t currentLatImprecise, currentLonImprecise;
|
||||
|
||||
return SmartPosition{.distanceTraveled = abs(distanceTraveledSinceLastSend),
|
||||
computeImpreciseLatLon(lastGpsLatitude, lastGpsLongitude, precision, lastLatImprecise, lastLonImprecise);
|
||||
computeImpreciseLatLon(currentPosition.latitude_i, currentPosition.longitude_i, precision, currentLatImprecise,
|
||||
currentLonImprecise);
|
||||
|
||||
float distMeters = GeoCoord::latLongToMeter(lastLatImprecise * 1e-7, lastLonImprecise * 1e-7, currentLatImprecise * 1e-7,
|
||||
currentLonImprecise * 1e-7);
|
||||
|
||||
float distanceTraveled = fabsf(distMeters);
|
||||
|
||||
return SmartPosition{.distanceTraveled = distanceTraveled,
|
||||
.distanceThreshold = distanceTravelThreshold,
|
||||
.hasTraveledOverThreshold = abs(distanceTraveledSinceLastSend) >= distanceTravelThreshold};
|
||||
.hasTraveledOverThreshold = distanceTraveled >= distanceTravelThreshold};
|
||||
}
|
||||
|
||||
void PositionModule::handleNewPosition()
|
||||
|
||||
@@ -26,7 +26,11 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
power_state = charged;
|
||||
}
|
||||
} else {
|
||||
power_state = discharging;
|
||||
if (powerStatus->getBatteryChargePercent() > 5) {
|
||||
power_state = discharging;
|
||||
} else {
|
||||
power_state = critical;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -58,16 +62,33 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
||||
|
||||
int32_t StatusLEDModule::runOnce()
|
||||
{
|
||||
my_interval = 1000;
|
||||
|
||||
if (power_state == charging) {
|
||||
CHARGE_LED_state = !CHARGE_LED_state;
|
||||
} else if (power_state == charged) {
|
||||
CHARGE_LED_state = LED_STATE_ON;
|
||||
} else if (power_state == critical) {
|
||||
if (POWER_LED_starttime + 30000 < millis() && !doing_fast_blink) {
|
||||
doing_fast_blink = true;
|
||||
POWER_LED_starttime = millis();
|
||||
}
|
||||
if (doing_fast_blink) {
|
||||
PAIRING_LED_state = LED_STATE_OFF;
|
||||
CHARGE_LED_state = !CHARGE_LED_state;
|
||||
my_interval = 250;
|
||||
if (POWER_LED_starttime + 2000 < millis()) {
|
||||
doing_fast_blink = false;
|
||||
}
|
||||
} else {
|
||||
CHARGE_LED_state = LED_STATE_OFF;
|
||||
}
|
||||
|
||||
} else {
|
||||
CHARGE_LED_state = LED_STATE_OFF;
|
||||
}
|
||||
|
||||
if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis()) {
|
||||
if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis() || doing_fast_blink) {
|
||||
PAIRING_LED_state = LED_STATE_OFF;
|
||||
} else if (ble_state == unpaired) {
|
||||
if (slowTrack) {
|
||||
|
||||
@@ -31,8 +31,10 @@ class StatusLEDModule : private concurrency::OSThread
|
||||
bool PAIRING_LED_state = LED_STATE_OFF;
|
||||
|
||||
uint32_t PAIRING_LED_starttime = 0;
|
||||
uint32_t POWER_LED_starttime = 0;
|
||||
bool doing_fast_blink = false;
|
||||
|
||||
enum PowerState { discharging, charging, charged };
|
||||
enum PowerState { discharging, charging, charged, critical };
|
||||
|
||||
PowerState power_state = discharging;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
[env:meshtastic-dr-dev]
|
||||
extends = esp32_base
|
||||
board = esp32doit-devkit-v1
|
||||
board_level = extra
|
||||
board_upload.maximum_size = 4194304
|
||||
board_upload.maximum_ram_size = 532480
|
||||
build_flags =
|
||||
|
||||
@@ -5,7 +5,7 @@ custom_esp32_kind = esp32
|
||||
custom_mtjson_part =
|
||||
platform =
|
||||
# renovate: datasource=custom.pio depName=platformio/espressif32 packageName=platformio/platform/espressif32
|
||||
platformio/espressif32@6.11.0
|
||||
platformio/espressif32@6.12.0
|
||||
|
||||
extra_scripts =
|
||||
${env.extra_scripts}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
[env:tbeam]
|
||||
extends = esp32_base
|
||||
board = ttgo-t-beam
|
||||
board_level = pr
|
||||
board_level = extra
|
||||
board_check = true
|
||||
lib_deps = ${esp32_base.lib_deps}
|
||||
build_flags = ${esp32_base.build_flags}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[env:link32-s3-v1]
|
||||
extends = esp32s3_base
|
||||
board = esp32-s3-devkitc-1
|
||||
board_level = extra
|
||||
build_flags =
|
||||
${esp32_base.build_flags}
|
||||
-D LINK_32
|
||||
|
||||
@@ -63,9 +63,20 @@ void initVariant()
|
||||
// called from main-nrf52.cpp during the cpuDeepSleep() function
|
||||
void variant_shutdown()
|
||||
{
|
||||
digitalWrite(red_LED_PIN, HIGH);
|
||||
digitalWrite(green_LED_PIN, HIGH);
|
||||
digitalWrite(LED_BLUE, HIGH);
|
||||
|
||||
digitalWrite(PIN_EN1, LOW);
|
||||
digitalWrite(PIN_EN2, LOW);
|
||||
digitalWrite(EEPROM_POWER, LOW);
|
||||
digitalWrite(KEY_POWER, LOW);
|
||||
digitalWrite(DHT_POWER, LOW);
|
||||
digitalWrite(ACC_POWER, LOW);
|
||||
digitalWrite(Battery_POWER, LOW);
|
||||
digitalWrite(GPS_POWER, LOW);
|
||||
|
||||
// This sets the pin to OUTPUT and LOW for the pins *not* in the if block.
|
||||
for (int pin = 0; pin < 48; pin++) {
|
||||
if (pin == PIN_POWER_USB || pin == BUTTON_PIN || pin == PIN_EN1 || pin == PIN_EN2 || pin == DHT_POWER ||
|
||||
pin == ACC_POWER || pin == Battery_POWER || pin == GPS_POWER || pin == LR1110_SPI_MISO_PIN ||
|
||||
|
||||
@@ -54,6 +54,7 @@ extern "C" {
|
||||
#define LED_POWER red_LED_PIN
|
||||
#define LED_CHARGE LED_POWER // Signals the Status LED Module to handle this LED
|
||||
#define green_LED_PIN 35
|
||||
#define PIN_LED2 green_LED_PIN
|
||||
#define LED_BLUE 37
|
||||
#define LED_PAIRING LED_BLUE // Signals the Status LED Module to handle this LED
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
[env:feather_rp2040_rfm95]
|
||||
extends = rp2040_base
|
||||
board = adafruit_feather
|
||||
board_level = extra
|
||||
upload_protocol = picotool
|
||||
# add our variants files to the include and src paths
|
||||
build_flags =
|
||||
|
||||
Reference in New Issue
Block a user