mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-21 02:02:23 +00:00
Compare commits
15 Commits
Thinknode-
...
b3eb6e65a2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3eb6e65a2 | ||
|
|
cce8cbfe34 | ||
|
|
a4a6c3509a | ||
|
|
68250dc937 | ||
|
|
e6e3c04db1 | ||
|
|
c8628b3422 | ||
|
|
2ac74d6677 | ||
|
|
9d487ddc0d | ||
|
|
9dc1bcdc3d | ||
|
|
bcfe069997 | ||
|
|
a0cfea87a1 | ||
|
|
4fc96bdf83 | ||
|
|
4ef943f204 | ||
|
|
a8fa5f25cb | ||
|
|
467c042bf7 |
2
.github/actions/build-variant/action.yml
vendored
2
.github/actions/build-variant/action.yml
vendored
@@ -76,7 +76,7 @@ runs:
|
|||||||
done
|
done
|
||||||
|
|
||||||
- name: PlatformIO ${{ inputs.arch }} download cache
|
- name: PlatformIO ${{ inputs.arch }} download cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v5
|
||||||
with:
|
with:
|
||||||
path: ~/.platformio/.cache
|
path: ~/.platformio/.cache
|
||||||
key: pio-cache-${{ inputs.arch }}-${{ hashFiles('.github/actions/**', '**.ini') }}
|
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
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
check: ${{ fromJson(needs.setup.outputs.check) }}
|
check: ${{ fromJson(needs.setup.outputs.check) }}
|
||||||
|
# Use 'arctastic' self-hosted runner pool when checking in the main repo
|
||||||
runs-on: ubuntu-latest
|
runs-on: ${{ github.repository_owner == 'meshtastic' && 'arctastic' || 'ubuntu-latest' }}
|
||||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
- name: Build base
|
with:
|
||||||
id: base
|
submodules: recursive
|
||||||
uses: ./.github/actions/setup-base
|
ref: ${{github.event.pull_request.head.ref}}
|
||||||
|
repository: ${{github.event.pull_request.head.repo.full_name}}
|
||||||
- name: Check ${{ matrix.check.board }}
|
- 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:
|
build:
|
||||||
needs: [setup, version]
|
needs: [setup, version]
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ plugins:
|
|||||||
lint:
|
lint:
|
||||||
enabled:
|
enabled:
|
||||||
- checkov@3.2.495
|
- checkov@3.2.495
|
||||||
- renovate@42.44.0
|
- renovate@42.48.0
|
||||||
- prettier@3.7.4
|
- prettier@3.7.4
|
||||||
- trufflehog@3.92.2
|
- trufflehog@3.92.3
|
||||||
- yamllint@1.37.1
|
- yamllint@1.37.1
|
||||||
- bandit@1.9.2
|
- bandit@1.9.2
|
||||||
- trivy@0.68.1
|
- trivy@0.68.1
|
||||||
- taplo@0.10.0
|
- taplo@0.10.0
|
||||||
- ruff@0.14.8
|
- ruff@0.14.9
|
||||||
- isort@7.0.0
|
- isort@7.0.0
|
||||||
- markdownlint@0.47.0
|
- markdownlint@0.47.0
|
||||||
- oxipng@10.0.0
|
- oxipng@10.0.0
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export APP_VERSION=$VERSION
|
|||||||
|
|
||||||
basename=firmware-$1-$VERSION
|
basename=firmware-$1-$VERSION
|
||||||
|
|
||||||
pio run --environment $1 # -v
|
pio run --environment $1 -t mtjson # -v
|
||||||
|
|
||||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
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"
|
echo "Copying ESP32 update bin file"
|
||||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||||
|
|
||||||
echo "Building Filesystem for ESP32 targets"
|
echo "Copying 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
|
|
||||||
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
|
cp $BUILDDIR/littlefs-$1-$VERSION.bin $OUTDIR/littlefs-$1-$VERSION.bin
|
||||||
cp bin/device-install.* $OUTDIR/
|
cp bin/device-install.* $OUTDIR/
|
||||||
cp bin/device-update.* $OUTDIR/
|
cp bin/device-update.* $OUTDIR/
|
||||||
|
|
||||||
# Generate the manifest file
|
echo "Copying manifest"
|
||||||
echo "Generating Meshtastic manifest"
|
|
||||||
TIMEFORMAT="Generated manifest in %E seconds"
|
|
||||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
|
||||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export APP_VERSION=$VERSION
|
|||||||
|
|
||||||
basename=firmware-$1-$VERSION
|
basename=firmware-$1-$VERSION
|
||||||
|
|
||||||
pio run --environment $1 # -v
|
pio run --environment $1 -t mtjson # -v
|
||||||
|
|
||||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||||
|
|
||||||
@@ -47,8 +47,5 @@ if (echo $1 | grep -q "rak4631"); then
|
|||||||
cp $SRCHEX $OUTDIR/
|
cp $SRCHEX $OUTDIR/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generate the manifest file
|
echo "Copying manifest"
|
||||||
echo "Generating Meshtastic manifest"
|
|
||||||
TIMEFORMAT="Generated manifest in %E seconds"
|
|
||||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
|
||||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||||
|
|||||||
@@ -22,15 +22,12 @@ export APP_VERSION=$VERSION
|
|||||||
|
|
||||||
basename=firmware-$1-$VERSION
|
basename=firmware-$1-$VERSION
|
||||||
|
|
||||||
pio run --environment $1 # -v
|
pio run --environment $1 -t mtjson # -v
|
||||||
|
|
||||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||||
|
|
||||||
echo "Copying uf2 file"
|
echo "Copying uf2 file"
|
||||||
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
cp $BUILDDIR/$basename.uf2 $OUTDIR/$basename.uf2
|
||||||
|
|
||||||
# Generate the manifest file
|
echo "Copying manifest"
|
||||||
echo "Generating Meshtastic manifest"
|
|
||||||
TIMEFORMAT="Generated manifest in %E seconds"
|
|
||||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
|
||||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
||||||
|
|||||||
@@ -22,15 +22,12 @@ export APP_VERSION=$VERSION
|
|||||||
|
|
||||||
basename=firmware-$1-$VERSION
|
basename=firmware-$1-$VERSION
|
||||||
|
|
||||||
pio run --environment $1 # -v
|
pio run --environment $1 -t mtjson # -v
|
||||||
|
|
||||||
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
cp $BUILDDIR/$basename.elf $OUTDIR/$basename.elf
|
||||||
|
|
||||||
echo "Copying STM32 bin file"
|
echo "Copying STM32 bin file"
|
||||||
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
cp $BUILDDIR/$basename.bin $OUTDIR/$basename.bin
|
||||||
|
|
||||||
# Generate the manifest file
|
echo "Copying manifest"
|
||||||
echo "Generating Meshtastic manifest"
|
|
||||||
TIMEFORMAT="Generated manifest in %E seconds"
|
|
||||||
time pio run --environment $1 -t mtjson --silent --disable-auto-clean
|
|
||||||
cp $BUILDDIR/$basename.mt.json $OUTDIR/$basename.mt.json
|
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
|
# Load the boot logo on TFT builds
|
||||||
if ("HAS_TFT", 1) in env.get("CPPDEFINES", []):
|
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
|
mtjson_deps = ["buildprog"]
|
||||||
# This ensures the littlefs.bin is named consistently with the firmware
|
if platform.name == "espressif32":
|
||||||
env.AddPostAction('$BUILD_DIR/littlefs.bin', env.VerboseAction(
|
# Build littlefs image as part of mtjson target
|
||||||
f'mv $BUILD_DIR/littlefs.bin $BUILD_DIR/{lfsbin}',
|
# Equivalent to `pio run -t buildfs`
|
||||||
f'Renaming littlefs.bin to {lfsbin}'
|
target_lfs = env.DataToBin(
|
||||||
))
|
join("$BUILD_DIR", "${ESP32_FS_IMAGE_NAME}"), "$PROJECT_DATA_DIR"
|
||||||
|
)
|
||||||
|
mtjson_deps.append(target_lfs)
|
||||||
|
|
||||||
env.AddCustomTarget(
|
env.AddCustomTarget(
|
||||||
name="mtjson",
|
name="mtjson",
|
||||||
dependencies=None,
|
dependencies=mtjson_deps,
|
||||||
actions=[manifest_gather],
|
actions=[manifest_gather],
|
||||||
title="Meshtastic Manifest",
|
title="Meshtastic Manifest",
|
||||||
description="Generating Meshtastic manifest JSON + Checksums",
|
description="Generating Meshtastic manifest JSON + Checksums",
|
||||||
always_build=True,
|
always_build=False,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ else:
|
|||||||
prefsLoc = env["PROJECT_DIR"] + "/version.properties"
|
prefsLoc = env["PROJECT_DIR"] + "/version.properties"
|
||||||
verObj = readProps(prefsLoc)
|
verObj = readProps(prefsLoc)
|
||||||
env.Replace(PROGNAME=f"firmware-{env.get('PIOENV')}-{verObj['long']}")
|
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 the new program name for verification
|
||||||
print(f"PROGNAME: {env.get('PROGNAME')}")
|
print(f"PROGNAME: {env.get('PROGNAME')}")
|
||||||
|
if platform.name == "espressif32":
|
||||||
|
print(f"ESP32_FS_IMAGE_NAME: {env.get('ESP32_FS_IMAGE_NAME')}")
|
||||||
|
|||||||
@@ -123,7 +123,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/4fb5f24787caa841b58dbf623a52c4c5861d6722.zip
|
https://github.com/meshtastic/device-ui/archive/2746a1ce3804998460a2cb319b8ea8a238dfd8c9.zip
|
||||||
|
|
||||||
; Common libs for environmental measurements in telemetry module
|
; Common libs for environmental measurements in telemetry module
|
||||||
[environmental_base]
|
[environmental_base]
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ typedef struct _InputEvent {
|
|||||||
class InputPollable
|
class InputPollable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~InputPollable() = default;
|
||||||
virtual void pollOnce() = 0;
|
virtual void pollOnce() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
#include "RotaryEncoderImpl.h"
|
#include "RotaryEncoderImpl.h"
|
||||||
#include "InputBroker.h"
|
#include "InputBroker.h"
|
||||||
#include "RotaryEncoder.h"
|
#include "RotaryEncoder.h"
|
||||||
|
#ifdef ARCH_ESP32
|
||||||
|
#include "sleep.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ORIGIN_NAME "RotaryEncoder"
|
#define ORIGIN_NAME "RotaryEncoder"
|
||||||
|
|
||||||
@@ -11,6 +14,20 @@ RotaryEncoderImpl *rotaryEncoderImpl;
|
|||||||
RotaryEncoderImpl::RotaryEncoderImpl()
|
RotaryEncoderImpl::RotaryEncoderImpl()
|
||||||
{
|
{
|
||||||
rotary = nullptr;
|
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()
|
bool RotaryEncoderImpl::init()
|
||||||
@@ -25,15 +42,22 @@ bool RotaryEncoderImpl::init()
|
|||||||
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
|
eventCcw = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_ccw);
|
||||||
eventPressed = static_cast<input_broker_event>(moduleConfig.canned_message.inputbroker_event_press);
|
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,
|
if (rotary == nullptr) {
|
||||||
moduleConfig.canned_message.inputbroker_pin_press);
|
rotary = new RotaryEncoder(moduleConfig.canned_message.inputbroker_pin_a, moduleConfig.canned_message.inputbroker_pin_b,
|
||||||
rotary->resetButton();
|
moduleConfig.canned_message.inputbroker_pin_press);
|
||||||
|
}
|
||||||
|
|
||||||
interruptInstance = this;
|
attachRotaryEncoderInterrupts();
|
||||||
auto interruptHandler = []() { inputBroker->requestPollSoon(interruptInstance); };
|
|
||||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_a, interruptHandler, CHANGE);
|
#ifdef ARCH_ESP32
|
||||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_b, interruptHandler, CHANGE);
|
// Register callbacks for before and after lightsleep
|
||||||
attachInterrupt(moduleConfig.canned_message.inputbroker_pin_press, interruptHandler, CHANGE);
|
// 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,
|
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,
|
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;
|
RotaryEncoderImpl *RotaryEncoderImpl::interruptInstance;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -8,12 +8,18 @@
|
|||||||
|
|
||||||
class RotaryEncoder;
|
class RotaryEncoder;
|
||||||
|
|
||||||
class RotaryEncoderImpl : public InputPollable
|
class RotaryEncoderImpl final : public InputPollable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RotaryEncoderImpl();
|
RotaryEncoderImpl();
|
||||||
bool init(void);
|
~RotaryEncoderImpl() override;
|
||||||
|
bool init();
|
||||||
virtual void pollOnce() override;
|
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:
|
protected:
|
||||||
static RotaryEncoderImpl *interruptInstance;
|
static RotaryEncoderImpl *interruptInstance;
|
||||||
@@ -23,6 +29,21 @@ class RotaryEncoderImpl : public InputPollable
|
|||||||
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
input_broker_event eventPressed = INPUT_BROKER_NONE;
|
||||||
|
|
||||||
RotaryEncoder *rotary;
|
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;
|
extern RotaryEncoderImpl *rotaryEncoderImpl;
|
||||||
|
|||||||
@@ -225,4 +225,4 @@ class MeshModule
|
|||||||
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
||||||
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
||||||
*/
|
*/
|
||||||
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
void setReplyTo(meshtastic_MeshPacket *p, const meshtastic_MeshPacket &to);
|
||||||
|
|||||||
@@ -805,11 +805,11 @@ void NodeDB::installDefaultModuleConfig()
|
|||||||
moduleConfig.external_notification.output_ms = 500;
|
moduleConfig.external_notification.output_ms = 500;
|
||||||
moduleConfig.external_notification.nag_timeout = 2;
|
moduleConfig.external_notification.nag_timeout = 2;
|
||||||
#endif
|
#endif
|
||||||
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE)
|
#if defined(RAK4630) || defined(RAK11310) || defined(RAK3312) || defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3)
|
||||||
// Default to RAK led pin 2 (blue)
|
// Default to PIN_LED2 for external notification output (LED color depends on device variant)
|
||||||
moduleConfig.external_notification.enabled = true;
|
moduleConfig.external_notification.enabled = true;
|
||||||
moduleConfig.external_notification.output = PIN_LED2;
|
moduleConfig.external_notification.output = PIN_LED2;
|
||||||
#if defined(MUZI_BASE)
|
#if defined(MUZI_BASE) || defined(ELECROW_ThinkNode_M3)
|
||||||
moduleConfig.external_notification.active = false;
|
moduleConfig.external_notification.active = false;
|
||||||
#else
|
#else
|
||||||
moduleConfig.external_notification.active = true;
|
moduleConfig.external_notification.active = true;
|
||||||
|
|||||||
@@ -150,7 +150,9 @@ void ReliableRouter::sniffReceived(const meshtastic_MeshPacket *p, const meshtas
|
|||||||
PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0;
|
PacketId nakId = (c && c->error_reason != meshtastic_Routing_Error_NONE) ? p->decoded.request_id : 0;
|
||||||
|
|
||||||
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
|
||||||
if (ackId || nakId) {
|
if ((ackId || nakId) &&
|
||||||
|
// Implicit ACKs from MQTT should not stop retransmissions
|
||||||
|
!(isFromUs(p) && p->transport_mechanism == meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT)) {
|
||||||
LOG_DEBUG("Received a %s for 0x%x, stopping retransmissions", ackId ? "ACK" : "NAK", ackId);
|
LOG_DEBUG("Received a %s for 0x%x, stopping retransmissions", ackId ? "ACK" : "NAK", ackId);
|
||||||
if (ackId) {
|
if (ackId) {
|
||||||
stopRetransmission(p->to, ackId);
|
stopRetransmission(p->to, ackId);
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ uint8_t RoutingModule::getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit
|
|||||||
return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit
|
return Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit); // Use the default hop limit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *RoutingModule::allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||||
|
uint8_t hopLimit)
|
||||||
|
{
|
||||||
|
return MeshModule::allocAckNak(err, to, idFrom, chIndex, hopLimit);
|
||||||
|
}
|
||||||
|
|
||||||
RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg)
|
RoutingModule::RoutingModule() : ProtobufModule("routing", meshtastic_PortNum_ROUTING_APP, &meshtastic_Routing_msg)
|
||||||
{
|
{
|
||||||
isPromiscuous = true;
|
isPromiscuous = true;
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ class RoutingModule : public ProtobufModule<meshtastic_Routing>
|
|||||||
virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0,
|
virtual void sendAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex, uint8_t hopLimit = 0,
|
||||||
bool ackWantsAck = false);
|
bool ackWantsAck = false);
|
||||||
|
|
||||||
|
meshtastic_MeshPacket *allocAckNak(meshtastic_Routing_Error err, NodeNum to, PacketId idFrom, ChannelIndex chIndex,
|
||||||
|
uint8_t hopLimit = 0);
|
||||||
|
|
||||||
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
// Given the hopStart and hopLimit upon reception of a request, return the hop limit to use for the response
|
||||||
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
uint8_t getHopLimitForResponse(uint8_t hopStart, uint8_t hopLimit);
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,11 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
|||||||
power_state = charged;
|
power_state = charged;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
power_state = discharging;
|
if (powerStatus->getBatteryChargePercent() > 5) {
|
||||||
|
power_state = discharging;
|
||||||
|
} else {
|
||||||
|
power_state = critical;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -58,16 +62,33 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
|
|||||||
|
|
||||||
int32_t StatusLEDModule::runOnce()
|
int32_t StatusLEDModule::runOnce()
|
||||||
{
|
{
|
||||||
|
my_interval = 1000;
|
||||||
|
|
||||||
if (power_state == charging) {
|
if (power_state == charging) {
|
||||||
CHARGE_LED_state = !CHARGE_LED_state;
|
CHARGE_LED_state = !CHARGE_LED_state;
|
||||||
} else if (power_state == charged) {
|
} else if (power_state == charged) {
|
||||||
CHARGE_LED_state = LED_STATE_ON;
|
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 {
|
} else {
|
||||||
CHARGE_LED_state = LED_STATE_OFF;
|
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;
|
PAIRING_LED_state = LED_STATE_OFF;
|
||||||
} else if (ble_state == unpaired) {
|
} else if (ble_state == unpaired) {
|
||||||
if (slowTrack) {
|
if (slowTrack) {
|
||||||
|
|||||||
@@ -31,8 +31,10 @@ class StatusLEDModule : private concurrency::OSThread
|
|||||||
bool PAIRING_LED_state = LED_STATE_OFF;
|
bool PAIRING_LED_state = LED_STATE_OFF;
|
||||||
|
|
||||||
uint32_t PAIRING_LED_starttime = 0;
|
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;
|
PowerState power_state = discharging;
|
||||||
|
|
||||||
|
|||||||
@@ -87,10 +87,13 @@ inline void onReceiveProto(char *topic, byte *payload, size_t length)
|
|||||||
// Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
|
// Generate an implicit ACK towards ourselves (handled and processed only locally!) for this message.
|
||||||
// We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
|
// We do this because packets are not rebroadcasted back into MQTT anymore and we assume that at least one node
|
||||||
// receives it when we get our own packet back. Then we'll stop our retransmissions.
|
// receives it when we get our own packet back. Then we'll stop our retransmissions.
|
||||||
if (isFromUs(e.packet))
|
if (isFromUs(e.packet)) {
|
||||||
routingModule->sendAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
|
auto pAck = routingModule->allocAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
|
||||||
else
|
pAck->transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT;
|
||||||
|
router->sendLocal(pAck);
|
||||||
|
} else {
|
||||||
LOG_INFO("Ignore downlink message we originally sent");
|
LOG_INFO("Ignore downlink message we originally sent");
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isFromUs(e.packet)) {
|
if (isFromUs(e.packet)) {
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ void cpuDeepSleep(uint32_t msecToWake)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TTGO_T_ECHO
|
#ifdef TTGO_T_ECHO
|
||||||
// To power off the T-Echo, the display must be set
|
// To power off the T-Echo, the display must be set
|
||||||
// as an input pin; otherwise, there will be leakage current.
|
// as an input pin; otherwise, there will be leakage current.
|
||||||
pinMode(PIN_EINK_CS, INPUT);
|
pinMode(PIN_EINK_CS, INPUT);
|
||||||
pinMode(PIN_EINK_DC, INPUT);
|
pinMode(PIN_EINK_DC, INPUT);
|
||||||
|
|||||||
@@ -63,9 +63,20 @@ void initVariant()
|
|||||||
// called from main-nrf52.cpp during the cpuDeepSleep() function
|
// called from main-nrf52.cpp during the cpuDeepSleep() function
|
||||||
void variant_shutdown()
|
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(EEPROM_POWER, LOW);
|
||||||
digitalWrite(KEY_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++) {
|
for (int pin = 0; pin < 48; pin++) {
|
||||||
if (pin == PIN_POWER_USB || pin == BUTTON_PIN || pin == PIN_EN1 || pin == PIN_EN2 || pin == DHT_POWER ||
|
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 ||
|
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_POWER red_LED_PIN
|
||||||
#define LED_CHARGE LED_POWER // Signals the Status LED Module to handle this LED
|
#define LED_CHARGE LED_POWER // Signals the Status LED Module to handle this LED
|
||||||
#define green_LED_PIN 35
|
#define green_LED_PIN 35
|
||||||
|
#define PIN_LED2 green_LED_PIN
|
||||||
#define LED_BLUE 37
|
#define LED_BLUE 37
|
||||||
#define LED_PAIRING LED_BLUE // Signals the Status LED Module to handle this LED
|
#define LED_PAIRING LED_BLUE // Signals the Status LED Module to handle this LED
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user