Compare commits

..

18 Commits

Author SHA1 Message Date
Jonathan Bennett
c6003be4c9 Merge branch 'develop' into status-message 2026-01-28 17:20:17 -06:00
oscgonfer
d7d6fe7f0f Avoid short-circuit evaluation issues in Telemetry (#9467)
* Make sensors in telemetry non-definitory

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-28 17:18:42 -06:00
Jonathan Bennett
0c14c461c7 Merge branch 'develop' into status-message 2026-01-28 17:11:47 -06:00
Jonathan Bennett
4fd0a8276b Just set LED_BUILTIN universally to -1, as we don't use it. (#8830)
* Just set LED_BUILTIN universally to -1, as we don't use it.

* LUD_BUILTIN workarounds

* Squash the LED_BUILTINs that sneaked in

* Don't kill valid pin derfine
2026-01-28 17:09:13 -06:00
Jonathan Bennett
b7081a5c62 Merge branch 'develop' into status-message 2026-01-28 16:17:48 -06:00
Jonathan Bennett
1d219a93ab Move input init to an init function in InputBroker (#9463)
* Move input init to an init function in iInputBroker

* Unbreak targets with EXCLUDE_INPUTBROKER

* Update src/input/InputBroker.cpp

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix conditional compilation for input broker

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Trunk

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 14:58:05 -06:00
Eric Severance
f710cd6ecb Support fully direct request/responses (#9455)
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-01-28 14:14:01 -06:00
Jonathan Bennett
571c1ac34c Initial serialModule cleanup (#9465)
* Initial serialModule cleanup

* Move SERIAL_PRINT_PORT definition to variant.h

* Add missed c6 check

* Update src/modules/SerialModule.cpp

Compile error for invalid SERIAL_PRINT_OBJECT value

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 14:08:32 -06:00
Ben Meadors
fb635987d1 Merge remote-tracking branch 'origin/master' into develop 2026-01-28 13:31:39 -06:00
Jason P
a922751afc External Notification - handleReceived Rewrite (#9454)
* First steps in consolidating code and minimizing rewrite

* Continuing code cleanup

* Merge containsBell and !isMuted to a single code path

* Forgot about alert_message_buzzer in the cleanup

* More code refinements and cleanup

* Fix nagCycleCutoff

* CoPilot Updates
2026-01-28 11:12:02 -06:00
renovate[bot]
c1e3f56324 Update LovyanGFX to v1.2.19 (#9405)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-01-28 11:08:07 -06:00
Ben Meadors
d0562e1ee6 Add model workflows (#9462)
* Add GitHub workflows for issue completeness, duplicate detection, onboarding, and contribution quality checks

* Fix indentation

* Refactor GitHub workflows for issue handling

* Consolidate to two triage workflows

* Update .github/workflows/models_pr_triage.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-28 10:50:56 -06:00
Jonathan Bennett
c87b511010 Merge branch 'develop' into status-message 2026-01-25 15:58:55 -06:00
Jonathan Bennett
1f0ef2498a Don't reboot node simply for a StatusMessage config update 2026-01-20 18:10:40 -06:00
Jonathan Bennett
84cd870323 Trunk 2026-01-20 10:42:23 -06:00
Jonathan Bennett
2eda145a56 Merge branch 'develop' into status-message 2026-01-20 10:34:24 -06:00
Jonathan Bennett
2f821ca267 Merge branch 'develop' into status-message 2026-01-18 15:20:57 -06:00
Jonathan Bennett
be8506857c Add StatusMessage module and config overrides 2026-01-18 15:15:31 -06:00
121 changed files with 963 additions and 676 deletions

View File

@@ -0,0 +1,204 @@
name: Issue Triage (Models)
on:
issues:
types: [opened]
permissions:
issues: write
models: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: true
jobs:
triage:
if: ${{ github.repository == 'meshtastic/firmware' && github.event.issue.user.type != 'Bot' }}
runs-on: ubuntu-latest
steps:
# ─────────────────────────────────────────────────────────────────────────
# Step 1: Quality check (spam/AI-slop detection) - runs first, exits early if spam
# ─────────────────────────────────────────────────────────────────────────
- name: Detect spam or low-quality content
uses: actions/ai-inference@v2
id: quality
continue-on-error: true
with:
max-tokens: 20
prompt: |
Is this GitHub issue spam, AI-generated slop, or low quality?
Title: ${{ github.event.issue.title }}
Body: ${{ github.event.issue.body }}
Respond with exactly one of: spam, ai-generated, needs-review, ok
system-prompt: You detect spam and low-quality contributions. Be conservative - only flag obvious spam or AI slop.
model: openai/gpt-4o-mini
- name: Apply quality label if needed
if: steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
uses: actions/github-script@v8
env:
QUALITY_LABEL: ${{ steps.quality.outputs.response }}
with:
script: |
const label = (process.env.QUALITY_LABEL || '').trim().toLowerCase();
const labelMeta = {
'spam': { color: 'd73a4a', description: 'Possible spam' },
'ai-generated': { color: 'fbca04', description: 'Possible AI-generated low-quality content' },
'needs-review': { color: 'f9d0c4', description: 'Needs human review' },
};
const meta = labelMeta[label];
if (!meta) return;
// Ensure label exists
try {
await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
} catch (e) {
if (e.status !== 404) throw e;
await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
}
// Apply label
await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.issue.number, labels: [label] });
// Set output to skip remaining steps
core.setOutput('is_spam', 'true');
# ─────────────────────────────────────────────────────────────────────────
# Step 2: Duplicate detection - only if not spam
# ─────────────────────────────────────────────────────────────────────────
- name: Detect duplicate issues
if: steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == ''
uses: pelikhan/action-genai-issue-dedup@bdb3b5d9451c1090ffcdf123d7447a5e7c7a2528 # v0.0.19
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# ─────────────────────────────────────────────────────────────────────────
# Step 3: Completeness check + auto-labeling (combined into one AI call)
# ─────────────────────────────────────────────────────────────────────────
- name: Determine if completeness check should be skipped
if: steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == ''
uses: actions/github-script@v8
id: check-skip
with:
script: |
const title = (context.payload.issue.title || '').toLowerCase();
const labels = (context.payload.issue.labels || []).map(label => label.name);
const hasFeatureRequest = title.includes('feature request');
const hasEnhancement = labels.includes('enhancement');
const shouldSkip = hasFeatureRequest && hasEnhancement;
core.setOutput('should_skip', shouldSkip ? 'true' : 'false');
- name: Analyze issue completeness and determine labels
if: (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '') && steps.check-skip.outputs.should_skip != 'true'
uses: actions/ai-inference@v2
id: analysis
continue-on-error: true
with:
prompt: |
Analyze this GitHub issue for completeness and determine if it needs labels.
If this looks like a bug on the device/firmware (crash, reboot, lockup, radio issues, GPS issues, display issues, power/sleep issues), request device logs and explain how to get them:
Web Flasher logs:
- Go to https://flasher.meshtastic.org
- Connect the device via USB and click Connect
- Open the device console/log output, reproduce the problem, then copy/download and attach/paste the logs
Meshtastic CLI logs:
- Run: meshtastic --port <serial-port> --noproto
- Reproduce the problem, then copy/paste the terminal output
Also request key context if missing: device model/variant, firmware version, region, steps to reproduce, expected vs actual.
Respond ONLY with JSON:
{
"complete": true|false,
"comment": "Your helpful comment requesting missing info, or empty string if complete",
"label": "needs-logs" | "needs-info" | "none"
}
Use "needs-logs" if this is a device bug AND no logs are attached.
Use "needs-info" if basic info like firmware version or steps to reproduce are missing.
Use "none" if the issue is complete or is a feature request.
Title: ${{ github.event.issue.title }}
Body: ${{ github.event.issue.body }}
system-prompt: You are a helpful assistant that triages GitHub issues. Be conservative with labels.
model: openai/gpt-4o-mini
- name: Process analysis result
if: (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '') && steps.check-skip.outputs.should_skip != 'true' && steps.analysis.outputs.response != ''
uses: actions/github-script@v8
id: process
env:
AI_RESPONSE: ${{ steps.analysis.outputs.response }}
with:
script: |
const raw = (process.env.AI_RESPONSE || '').trim();
let complete = false;
let comment = '';
let label = 'none';
try {
const parsed = JSON.parse(raw);
complete = !!parsed.complete;
comment = (parsed.comment ?? '').toString().trim();
label = (parsed.label ?? 'none').toString().trim().toLowerCase();
} catch {
// If JSON parse fails, treat as incomplete with raw response as comment
complete = false;
comment = raw;
label = 'none';
}
// Validate label
const allowedLabels = new Set(['needs-logs', 'needs-info', 'none']);
if (!allowedLabels.has(label)) label = 'none';
core.setOutput('should_comment', (!complete && comment.length > 0) ? 'true' : 'false');
core.setOutput('comment_body', comment);
core.setOutput('label', label);
- name: Apply triage label
if: steps.process.outputs.label != '' && steps.process.outputs.label != 'none'
uses: actions/github-script@v8
env:
LABEL_NAME: ${{ steps.process.outputs.label }}
with:
script: |
const label = process.env.LABEL_NAME;
const labelMeta = {
'needs-logs': { color: 'cfd3d7', description: 'Device logs requested for triage' },
'needs-info': { color: 'f9d0c4', description: 'More information requested for triage' },
};
const meta = labelMeta[label];
if (!meta) return;
// Ensure label exists
try {
await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
} catch (e) {
if (e.status !== 404) throw e;
await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
}
// Apply label
await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.issue.number, labels: [label] });
- name: Comment on issue
if: steps.process.outputs.should_comment == 'true'
uses: actions/github-script@v8
env:
COMMENT_BODY: ${{ steps.process.outputs.comment_body }}
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.issue.number,
body: process.env.COMMENT_BODY
});

138
.github/workflows/models_pr_triage.yml vendored Normal file
View File

@@ -0,0 +1,138 @@
name: PR Triage (Models)
on:
pull_request_target:
types: [opened]
permissions:
pull-requests: write
issues: write
models: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
triage:
if: ${{ github.repository == 'meshtastic/firmware' && github.event.pull_request.user.type != 'Bot' }}
runs-on: ubuntu-latest
steps:
# ─────────────────────────────────────────────────────────────────────────
# Step 1: Check if PR already has automation/type labels (skip if so)
# ─────────────────────────────────────────────────────────────────────────
- name: Check existing labels
uses: actions/github-script@v8
id: check-labels
with:
script: |
const skipLabels = new Set(['automation']);
const typeLabels = new Set(['bugfix', 'hardware-support', 'enhancement', 'dependencies', 'submodules', 'github_actions', 'trunk', 'cleanup']);
const prLabels = context.payload.pull_request.labels.map(l => l.name);
const shouldSkipAll = prLabels.some(l => skipLabels.has(l));
const hasTypeLabel = prLabels.some(l => typeLabels.has(l));
core.setOutput('skip_all', shouldSkipAll ? 'true' : 'false');
core.setOutput('has_type_label', hasTypeLabel ? 'true' : 'false');
# ─────────────────────────────────────────────────────────────────────────
# Step 2: Quality check (spam/AI-slop detection)
# ─────────────────────────────────────────────────────────────────────────
- name: Detect spam or low-quality content
if: steps.check-labels.outputs.skip_all != 'true'
uses: actions/ai-inference@v2
id: quality
continue-on-error: true
with:
max-tokens: 20
prompt: |
Is this GitHub pull request spam, AI-generated slop, or low quality?
Title: ${{ github.event.pull_request.title }}
Body: ${{ github.event.pull_request.body }}
Respond with exactly one of: spam, ai-generated, needs-review, ok
system-prompt: You detect spam and low-quality contributions. Be conservative - only flag obvious spam or AI slop.
model: openai/gpt-4o-mini
- name: Apply quality label if needed
if: steps.check-labels.outputs.skip_all != 'true' && steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
uses: actions/github-script@v8
id: quality-label
env:
QUALITY_LABEL: ${{ steps.quality.outputs.response }}
with:
script: |
const label = (process.env.QUALITY_LABEL || '').trim().toLowerCase();
const labelMeta = {
'spam': { color: 'd73a4a', description: 'Possible spam' },
'ai-generated': { color: 'fbca04', description: 'Possible AI-generated low-quality content' },
'needs-review': { color: 'f9d0c4', description: 'Needs human review' },
};
const meta = labelMeta[label];
if (!meta) return;
// Ensure label exists
try {
await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
} catch (e) {
if (e.status !== 404) throw e;
await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
}
// Apply label
await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: [label] });
core.setOutput('is_spam', 'true');
# ─────────────────────────────────────────────────────────────────────────
# Step 3: Auto-label PR type (bugfix/hardware-support/enhancement)
# ─────────────────────────────────────────────────────────────────────────
- name: Classify PR for labeling
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '')
uses: actions/ai-inference@v2
id: classify
continue-on-error: true
with:
max-tokens: 30
prompt: |
Classify this pull request into exactly one category.
Return exactly one of: bugfix, hardware-support, enhancement
Use bugfix if it fixes a bug, crash, or incorrect behavior.
Use hardware-support if it adds or improves support for a specific hardware device/variant.
Use enhancement if it adds a new feature, improves performance, or refactors code.
Title: ${{ github.event.pull_request.title }}
Body: ${{ github.event.pull_request.body }}
system-prompt: You classify pull requests into categories. Be conservative and pick the most appropriate single label.
model: openai/gpt-4o-mini
- name: Apply type label
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && steps.classify.outputs.response != ''
uses: actions/github-script@v8
env:
TYPE_LABEL: ${{ steps.classify.outputs.response }}
with:
script: |
const label = (process.env.TYPE_LABEL || '').trim().toLowerCase();
const labelMeta = {
'bugfix': { color: 'd73a4a', description: 'Bug fix' },
'hardware-support': { color: '0e8a16', description: 'Hardware support addition or improvement' },
'enhancement': { color: 'a2eeef', description: 'New feature or enhancement' },
};
const meta = labelMeta[label];
if (!meta) return;
// Ensure label exists
try {
await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
} catch (e) {
if (e.status !== 404) throw e;
await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
}
// Apply label
await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: [label] });

View File

@@ -56,6 +56,7 @@ build_flags = -Wno-missing-field-initializers
-DMESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE=1
-DMESHTASTIC_EXCLUDE_POWERMON=1
-D MAX_THREADS=40 ; As we've split modules, we have more threads to manage
-DLED_BUILTIN=-1
#-DBUILD_EPOCH=$UNIX_TIME ; set in platformio-custom.py now
#-D OLED_PL=1
#-D DEBUG_HEAP=1 ; uncomment to add free heap space / memory leak debugging logs

View File

@@ -1,8 +1,59 @@
#include "InputBroker.h"
#include "PowerFSM.h" // needed for event trigger
#include "configuration.h"
#include "graphics/Screen.h"
#include "modules/ExternalNotificationModule.h"
#if ARCH_PORTDUINO
#include "input/LinuxInputImpl.h"
#include "input/SeesawRotary.h"
#include "platform/portduino/PortduinoGlue.h"
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
#include "input/ExpressLRSFiveWay.h"
#include "input/RotaryEncoderImpl.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "input/SerialKeyboardImpl.h"
#include "input/UpDownInterruptImpl1.h"
#include "input/i2cButton.h"
#if HAS_TRACKBALL
#include "input/TrackballInterruptImpl1.h"
#endif
#include "modules/StatusLEDModule.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "input/cardKbI2cImpl.h"
#endif
#include "input/kbMatrixImpl.h"
#endif
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
#include "input/ButtonThread.h"
#if defined(BUTTON_PIN_TOUCH)
ButtonThread *TouchButtonThread = nullptr;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
static bool touchBacklightWasOn = false;
static bool touchBacklightActive = false;
#endif
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
ButtonThread *UserButtonThread = nullptr;
#endif
#if defined(ALT_BUTTON_PIN)
ButtonThread *BackButtonThread = nullptr;
#endif
#if defined(CANCEL_BUTTON_PIN)
ButtonThread *CancelButtonThread = nullptr;
#endif
#endif
InputBroker *inputBroker = nullptr;
InputBroker::InputBroker()
@@ -74,3 +125,262 @@ void InputBroker::pollSoonWorker(void *p)
vTaskDelete(NULL);
}
#endif
void InputBroker::Init()
{
#ifdef BUTTON_PIN
#ifdef ARCH_ESP32
#if ESP_ARDUINO_VERSION_MAJOR >= 3
#ifdef BUTTON_NEED_PULLUP
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP);
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#endif
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
delay(10);
#endif
#ifdef BUTTON_NEED_PULLUP2
gpio_pullup_en((gpio_num_t)BUTTON_NEED_PULLUP2);
delay(10);
#endif
#endif
#endif
#endif
// buttons are now inputBroker, so have to come after setupModules
#if HAS_BUTTON
int pullup_sense = 0;
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
#ifdef BUTTON_SENSE_TYPE
pullup_sense = BUTTON_SENSE_TYPE;
#else
pullup_sense = INPUT_PULLUP_SENSE;
#endif
#endif
#if defined(ARCH_PORTDUINO)
if (portduino_config.userButtonPin.enabled) {
LOG_DEBUG("Use GPIO%02d for button", portduino_config.userButtonPin.pin);
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig config;
config.pinNumber = (uint8_t)portduino_config.userButtonPin.pin;
config.activeLow = true;
config.activePullup = true;
config.pullupSense = INPUT_PULLUP;
config.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
config.singlePress = INPUT_BROKER_USER_PRESS;
config.longPress = INPUT_BROKER_SELECT;
UserButtonThread->initButton(config);
}
}
#endif
#ifdef BUTTON_PIN_TOUCH
TouchButtonThread = new ButtonThread("BackButton");
ButtonConfig touchConfig;
touchConfig.pinNumber = BUTTON_PIN_TOUCH;
touchConfig.activeLow = true;
touchConfig.activePullup = true;
touchConfig.pullupSense = pullup_sense;
touchConfig.intRoutine = []() {
TouchButtonThread->userButton.tick();
TouchButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
touchConfig.singlePress = INPUT_BROKER_NONE;
touchConfig.longPress = INPUT_BROKER_BACK;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
// On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds
touchConfig.longPress = INPUT_BROKER_NONE;
touchConfig.suppressLeadUpSound = true;
touchConfig.onPress = []() {
touchBacklightWasOn = uiconfig.screen_brightness == 1;
if (!touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, HIGH);
}
touchBacklightActive = true;
};
touchConfig.onRelease = []() {
if (touchBacklightActive && !touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, LOW);
}
touchBacklightActive = false;
};
#endif
TouchButtonThread->initButton(touchConfig);
#endif
#if defined(CANCEL_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
CancelButtonThread = new ButtonThread("CancelButton");
ButtonConfig cancelConfig;
cancelConfig.pinNumber = CANCEL_BUTTON_PIN;
cancelConfig.activeLow = CANCEL_BUTTON_ACTIVE_LOW;
cancelConfig.activePullup = CANCEL_BUTTON_ACTIVE_PULLUP;
cancelConfig.pullupSense = pullup_sense;
cancelConfig.intRoutine = []() {
CancelButtonThread->userButton.tick();
CancelButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
cancelConfig.singlePress = INPUT_BROKER_CANCEL;
cancelConfig.longPress = INPUT_BROKER_SHUTDOWN;
cancelConfig.longPressTime = 4000;
CancelButtonThread->initButton(cancelConfig);
#endif
#if defined(ALT_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
BackButtonThread = new ButtonThread("BackButton");
ButtonConfig backConfig;
backConfig.pinNumber = ALT_BUTTON_PIN;
backConfig.activeLow = ALT_BUTTON_ACTIVE_LOW;
backConfig.activePullup = ALT_BUTTON_ACTIVE_PULLUP;
backConfig.pullupSense = pullup_sense;
backConfig.intRoutine = []() {
BackButtonThread->userButton.tick();
BackButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
backConfig.singlePress = INPUT_BROKER_ALT_PRESS;
backConfig.longPress = INPUT_BROKER_ALT_LONG;
backConfig.longPressTime = 500;
BackButtonThread->initButton(backConfig);
#endif
#if defined(BUTTON_PIN)
#if defined(USERPREFS_BUTTON_PIN)
int _pinNum = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN;
#else
int _pinNum = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN;
#endif
#ifndef BUTTON_ACTIVE_LOW
#define BUTTON_ACTIVE_LOW true
#endif
#ifndef BUTTON_ACTIVE_PULLUP
#define BUTTON_ACTIVE_PULLUP true
#endif
// Buttons. Moved here cause we need NodeDB to be initialized
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig userConfig;
userConfig.pinNumber = (uint8_t)_pinNum;
userConfig.activeLow = BUTTON_ACTIVE_LOW;
userConfig.activePullup = BUTTON_ACTIVE_PULLUP;
userConfig.pullupSense = pullup_sense;
userConfig.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
userConfig.singlePress = INPUT_BROKER_USER_PRESS;
userConfig.longPress = INPUT_BROKER_SELECT;
userConfig.longPressTime = 500;
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
UserButtonThread->initButton(userConfig);
} else {
ButtonConfig userConfigNoScreen;
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
userConfigNoScreen.activePullup = BUTTON_ACTIVE_PULLUP;
userConfigNoScreen.pullupSense = pullup_sense;
userConfigNoScreen.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
concurrency::mainDelay.interruptFromISR(&higherWake);
};
userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS;
userConfigNoScreen.longPress = INPUT_BROKER_NONE;
userConfigNoScreen.longPressTime = 500;
userConfigNoScreen.longLongPress = INPUT_BROKER_SHUTDOWN;
userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING;
userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE;
UserButtonThread->initButton(userConfigNoScreen);
}
#endif
#endif
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
#if defined(T_LORA_PAGER)
// use a special FSM based rotary encoder version for T-LoRa Pager
rotaryEncoderImpl = new RotaryEncoderImpl();
if (!rotaryEncoderImpl->init()) {
delete rotaryEncoderImpl;
rotaryEncoderImpl = nullptr;
}
#elif defined(INPUTDRIVER_ENCODER_TYPE) && (INPUTDRIVER_ENCODER_TYPE == 2)
upDownInterruptImpl1 = new UpDownInterruptImpl1();
if (!upDownInterruptImpl1->init()) {
delete upDownInterruptImpl1;
upDownInterruptImpl1 = nullptr;
}
#else
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
rotaryEncoderInterruptImpl1 = nullptr;
}
#endif
cardKbI2cImpl = new CardKbI2cImpl();
cardKbI2cImpl->init();
#if defined(M5STACK_UNITC6L)
i2cButton = new i2cButtonThread("i2cButtonThread");
#endif
#ifdef INPUTBROKER_MATRIX_TYPE
kbMatrixImpl = new KbMatrixImpl();
kbMatrixImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
#ifdef INPUTBROKER_SERIAL_TYPE
aSerialKeyboardImpl = new SerialKeyboardImpl();
aSerialKeyboardImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
}
#endif // HAS_BUTTON
#if ARCH_PORTDUINO
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) {
delete seesawRotary;
seesawRotary = nullptr;
}
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
}
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
trackballInterruptImpl1 = new TrackballInterruptImpl1();
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
}
#endif
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
expressLRSFiveWayInput = new ExpressLRSFiveWay();
#endif
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Observer.h"
#include "concurrency/OSThread.h"
#include "freertosinc.h"
#ifdef InputBrokerDebug
@@ -76,6 +77,7 @@ class InputBroker : public Observable<const InputEvent *>
void queueInputEvent(const InputEvent *event);
void processInputEventQueue();
#endif
void Init();
protected:
int handleInputEvent(const InputEvent *event);
@@ -89,4 +91,5 @@ class InputBroker : public Observable<const InputEvent *>
#endif
};
extern InputBroker *inputBroker;
extern InputBroker *inputBroker;
extern bool runASAP;

View File

@@ -120,31 +120,6 @@ void printPartitionTable()
#endif // DEBUG_PARTITION_TABLE
#endif // ARCH_ESP32
#if HAS_BUTTON || defined(ARCH_PORTDUINO)
#include "input/ButtonThread.h"
#if defined(BUTTON_PIN_TOUCH)
ButtonThread *TouchButtonThread = nullptr;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
static bool touchBacklightWasOn = false;
static bool touchBacklightActive = false;
#endif
#endif
#if defined(BUTTON_PIN) || defined(ARCH_PORTDUINO)
ButtonThread *UserButtonThread = nullptr;
#endif
#if defined(ALT_BUTTON_PIN)
ButtonThread *BackButtonThread = nullptr;
#endif
#if defined(CANCEL_BUTTON_PIN)
ButtonThread *CancelButtonThread = nullptr;
#endif
#endif
#include "AmbientLightingThread.h"
#include "PowerFSMThread.h"
@@ -509,30 +484,6 @@ void setup()
LOG_INFO("Wait for peripherals to stabilize");
delay(PERIPHERAL_WARMUP_MS);
#endif
#ifdef BUTTON_PIN
#ifdef ARCH_ESP32
#if ESP_ARDUINO_VERSION_MAJOR >= 3
#ifdef BUTTON_NEED_PULLUP
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT_PULLUP);
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#endif
#else
pinMode(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN, INPUT); // default to BUTTON_PIN
#ifdef BUTTON_NEED_PULLUP
gpio_pullup_en((gpio_num_t)(config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN));
delay(10);
#endif
#ifdef BUTTON_NEED_PULLUP2
gpio_pullup_en((gpio_num_t)BUTTON_NEED_PULLUP2);
delay(10);
#endif
#endif
#endif
#endif
initSPI();
OSThread::setup();
@@ -999,180 +950,9 @@ void setup()
nodeDB->hasWarned = true;
}
#endif
// buttons are now inputBroker, so have to come after setupModules
#if HAS_BUTTON
int pullup_sense = 0;
#ifdef INPUT_PULLUP_SENSE
// Some platforms (nrf52) have a SENSE variant which allows wake from sleep - override what OneButton did
#ifdef BUTTON_SENSE_TYPE
pullup_sense = BUTTON_SENSE_TYPE;
#else
pullup_sense = INPUT_PULLUP_SENSE;
#endif
#endif
#if defined(ARCH_PORTDUINO)
if (portduino_config.userButtonPin.enabled) {
LOG_DEBUG("Use GPIO%02d for button", portduino_config.userButtonPin.pin);
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig config;
config.pinNumber = (uint8_t)portduino_config.userButtonPin.pin;
config.activeLow = true;
config.activePullup = true;
config.pullupSense = INPUT_PULLUP;
config.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
config.singlePress = INPUT_BROKER_USER_PRESS;
config.longPress = INPUT_BROKER_SELECT;
UserButtonThread->initButton(config);
}
}
#endif
#ifdef BUTTON_PIN_TOUCH
TouchButtonThread = new ButtonThread("BackButton");
ButtonConfig touchConfig;
touchConfig.pinNumber = BUTTON_PIN_TOUCH;
touchConfig.activeLow = true;
touchConfig.activePullup = true;
touchConfig.pullupSense = pullup_sense;
touchConfig.intRoutine = []() {
TouchButtonThread->userButton.tick();
TouchButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
touchConfig.singlePress = INPUT_BROKER_NONE;
touchConfig.longPress = INPUT_BROKER_BACK;
#if defined(TTGO_T_ECHO_PLUS) && defined(PIN_EINK_EN)
// On T-Echo Plus the touch pad should only drive the backlight, not UI navigation/sounds
touchConfig.longPress = INPUT_BROKER_NONE;
touchConfig.suppressLeadUpSound = true;
touchConfig.onPress = []() {
touchBacklightWasOn = uiconfig.screen_brightness == 1;
if (!touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, HIGH);
}
touchBacklightActive = true;
};
touchConfig.onRelease = []() {
if (touchBacklightActive && !touchBacklightWasOn) {
digitalWrite(PIN_EINK_EN, LOW);
}
touchBacklightActive = false;
};
#endif
TouchButtonThread->initButton(touchConfig);
#endif
#if defined(CANCEL_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
CancelButtonThread = new ButtonThread("CancelButton");
ButtonConfig cancelConfig;
cancelConfig.pinNumber = CANCEL_BUTTON_PIN;
cancelConfig.activeLow = CANCEL_BUTTON_ACTIVE_LOW;
cancelConfig.activePullup = CANCEL_BUTTON_ACTIVE_PULLUP;
cancelConfig.pullupSense = pullup_sense;
cancelConfig.intRoutine = []() {
CancelButtonThread->userButton.tick();
CancelButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
cancelConfig.singlePress = INPUT_BROKER_CANCEL;
cancelConfig.longPress = INPUT_BROKER_SHUTDOWN;
cancelConfig.longPressTime = 4000;
CancelButtonThread->initButton(cancelConfig);
#endif
#if defined(ALT_BUTTON_PIN)
// Buttons. Moved here cause we need NodeDB to be initialized
BackButtonThread = new ButtonThread("BackButton");
ButtonConfig backConfig;
backConfig.pinNumber = ALT_BUTTON_PIN;
backConfig.activeLow = ALT_BUTTON_ACTIVE_LOW;
backConfig.activePullup = ALT_BUTTON_ACTIVE_PULLUP;
backConfig.pullupSense = pullup_sense;
backConfig.intRoutine = []() {
BackButtonThread->userButton.tick();
BackButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
backConfig.singlePress = INPUT_BROKER_ALT_PRESS;
backConfig.longPress = INPUT_BROKER_ALT_LONG;
backConfig.longPressTime = 500;
BackButtonThread->initButton(backConfig);
#endif
#if defined(BUTTON_PIN)
#if defined(USERPREFS_BUTTON_PIN)
int _pinNum = config.device.button_gpio ? config.device.button_gpio : USERPREFS_BUTTON_PIN;
#else
int _pinNum = config.device.button_gpio ? config.device.button_gpio : BUTTON_PIN;
#endif
#ifndef BUTTON_ACTIVE_LOW
#define BUTTON_ACTIVE_LOW true
#endif
#ifndef BUTTON_ACTIVE_PULLUP
#define BUTTON_ACTIVE_PULLUP true
#endif
// Buttons. Moved here cause we need NodeDB to be initialized
// If your variant.h has a BUTTON_PIN defined, go ahead and define BUTTON_ACTIVE_LOW and BUTTON_ACTIVE_PULLUP
UserButtonThread = new ButtonThread("UserButton");
if (screen) {
ButtonConfig userConfig;
userConfig.pinNumber = (uint8_t)_pinNum;
userConfig.activeLow = BUTTON_ACTIVE_LOW;
userConfig.activePullup = BUTTON_ACTIVE_PULLUP;
userConfig.pullupSense = pullup_sense;
userConfig.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
userConfig.singlePress = INPUT_BROKER_USER_PRESS;
userConfig.longPress = INPUT_BROKER_SELECT;
userConfig.longPressTime = 500;
userConfig.longLongPress = INPUT_BROKER_SHUTDOWN;
UserButtonThread->initButton(userConfig);
} else {
ButtonConfig userConfigNoScreen;
userConfigNoScreen.pinNumber = (uint8_t)_pinNum;
userConfigNoScreen.activeLow = BUTTON_ACTIVE_LOW;
userConfigNoScreen.activePullup = BUTTON_ACTIVE_PULLUP;
userConfigNoScreen.pullupSense = pullup_sense;
userConfigNoScreen.intRoutine = []() {
UserButtonThread->userButton.tick();
UserButtonThread->setIntervalFromNow(0);
runASAP = true;
BaseType_t higherWake = 0;
mainDelay.interruptFromISR(&higherWake);
};
userConfigNoScreen.singlePress = INPUT_BROKER_USER_PRESS;
userConfigNoScreen.longPress = INPUT_BROKER_NONE;
userConfigNoScreen.longPressTime = 500;
userConfigNoScreen.longLongPress = INPUT_BROKER_SHUTDOWN;
userConfigNoScreen.doublePress = INPUT_BROKER_SEND_PING;
userConfigNoScreen.triplePress = INPUT_BROKER_GPS_TOGGLE;
UserButtonThread->initButton(userConfigNoScreen);
}
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
if (inputBroker)
inputBroker->Init();
#endif
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS

View File

@@ -1,6 +1,5 @@
#pragma once
#include <NodeDB.h>
#include <cmath>
#include <cstdint>
#include <meshUtils.h>
#define ONE_DAY 24 * 60 * 60
@@ -58,79 +57,31 @@ class Default
static uint32_t getConfiguredOrMinimumValue(uint32_t configured, uint32_t minValue);
private:
/**
* Calculates a congestion scaling coefficient based on the number of online nodes.
*
* Uses power-law scaling (exponent 1.2) which provides a soft start that accelerates
* as node count increases - matching the superlinear growth of flood routing traffic.
*
* Scaling starts at 20 nodes (simulator shows congestion problems emerging early).
* Different modem presets have different channel capacities based on airtime per packet.
*
* Examples for LongFast (capacityMultiplier = 1.0):
* 20 nodes: 1.0x, 50 nodes: ~3.0x, 100 nodes: ~6.9x, 200 nodes: ~15.8x
* Examples for ShortFast (capacityMultiplier = 0.5):
* 20 nodes: 1.0x, 50 nodes: ~2.0x, 100 nodes: ~4.0x, 200 nodes: ~8.4x
*/
// Note: Kept as uint32_t to match the public API parameter type
static float congestionScalingCoefficient(uint32_t numOnlineNodes)
{
// Start scaling at 20 nodes - meshes show congestion problems earlier than 40
if (numOnlineNodes <= 20) {
return 1.0f;
}
// Use power-law scaling (p=1.2) - soft start that accelerates with node count,
// matching the superlinear growth of flood routing traffic
float baseScale = powf(static_cast<float>(numOnlineNodes) / 20.0f, 1.2f);
// Apply modem-specific capacity multiplier based on relative channel capacity.
// Capacity is inversely proportional to airtime - faster modems can handle more
// traffic before congestion, so we scale their intervals less aggressively.
// Airtime values are for a typical 237-byte packet (max payload).
float capacityMultiplier = 1.0f;
if (config.lora.use_preset) {
switch (config.lora.modem_preset) {
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO:
capacityMultiplier = 0.3f; // ~28ms airtime, BW500 SF5
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST:
capacityMultiplier = 0.5f; // ~50ms airtime, BW500 SF7
break;
case meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW:
capacityMultiplier = 0.7f; // ~100ms airtime, BW500 SF8
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST:
capacityMultiplier = 0.7f; // ~100ms airtime, BW250 SF7
break;
case meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW:
capacityMultiplier = 0.85f; // ~200ms airtime, BW250 SF8
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO:
capacityMultiplier = 0.85f; // ~150ms airtime, BW250 SF9
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST:
capacityMultiplier = 1.0f; // ~300ms airtime, BW250 SF10 (baseline)
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
capacityMultiplier = 1.0f; // ~350ms airtime, BW125 SF9
break;
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW:
capacityMultiplier = 1.3f; // ~700ms airtime, BW125 SF10
break;
case meshtastic_Config_LoRaConfig_ModemPreset_VERY_LONG_SLOW:
capacityMultiplier = 1.3f; // ~1400ms airtime, BW62.5 SF11
break;
default:
capacityMultiplier = 1.0f;
break;
}
}
if (numOnlineNodes <= 40) {
return 1.0;
} else {
float throttlingFactor = 0.075;
if (config.lora.use_preset && config.lora.modem_preset == meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW)
throttlingFactor = 0.04;
else if (config.lora.use_preset && config.lora.modem_preset == meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST)
throttlingFactor = 0.02;
else if (config.lora.use_preset &&
IS_ONE_OF(config.lora.modem_preset, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST,
meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO,
meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW))
throttlingFactor = 0.01;
#if USERPREFS_EVENT_MODE
// Event mode: more aggressive throttling for dense temporary meshes
capacityMultiplier *= 1.5f;
// If we are in event mode, scale down the throttling factor
throttlingFactor = 0.04;
#endif
return 1.0f + (baseScale - 1.0f) * capacityMultiplier;
// Scaling up traffic based on number of nodes over 40
int nodesOverForty = (numOnlineNodes - 40);
return 1.0 + (nodesOverForty * throttlingFactor); // Each number of online node scales by 0.075 (default)
}
}
};

View File

@@ -1419,6 +1419,15 @@ void NodeDB::loadFromDisk()
if (portduino_config.has_configDisplayMode) {
config.display.displaymode = (_meshtastic_Config_DisplayConfig_DisplayMode)portduino_config.configDisplayMode;
}
if (portduino_config.has_statusMessage) {
moduleConfig.has_statusmessage = true;
strncpy(moduleConfig.statusmessage.node_status, portduino_config.statusMessage.c_str(),
sizeof(moduleConfig.statusmessage.node_status));
moduleConfig.statusmessage.node_status[sizeof(moduleConfig.statusmessage.node_status) - 1] = '\0';
}
if (portduino_config.enable_UDP) {
config.network.enabled_protocols = true;
}
#endif
}
@@ -1559,6 +1568,7 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
moduleConfig.has_ambient_lighting = true;
moduleConfig.has_audio = true;
moduleConfig.has_paxcounter = true;
moduleConfig.has_statusmessage = true;
success &=
saveProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, &meshtastic_LocalModuleConfig_msg, &moduleConfig);

View File

@@ -17,12 +17,6 @@
ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
{
if (p->want_ack) {
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop
// counts and we want this message to get through the whole mesh, so use the default.
if (p->hop_limit == 0) {
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
}
DEBUG_HEAP_BEFORE;
auto copy = packetPool.allocCopy(*p);
DEBUG_HEAP_AFTER("ReliableRouter::send", copy);

View File

@@ -266,6 +266,13 @@ ErrorCode Router::sendLocal(meshtastic_MeshPacket *p, RxSource src)
}
}
// If someone asks for acks on broadcast, we need the hop limit to be at least one, so that first node that receives our
// message will rebroadcast. But asking for hop_limit 0 in that context means the client app has no preference on hop
// counts and we want this message to get through the whole mesh, so use the default.
if (src == RX_SRC_USER && p->want_ack && p->hop_limit == 0) {
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
}
return send(p);
}
}

View File

@@ -905,10 +905,11 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
{
bool shouldReboot = true;
// If we are in an open transaction or configuring MQTT or Serial (which have validation), defer disabling Bluetooth
// Otherwise, disable Bluetooth to prevent the phone from interfering with the config
if (!hasOpenEditTransaction &&
!IS_ONE_OF(c.which_payload_variant, meshtastic_ModuleConfig_mqtt_tag, meshtastic_ModuleConfig_serial_tag)) {
if (!hasOpenEditTransaction && !IS_ONE_OF(c.which_payload_variant, meshtastic_ModuleConfig_mqtt_tag,
meshtastic_ModuleConfig_serial_tag, meshtastic_ModuleConfig_statusmessage_tag)) {
disableBluetooth();
}
@@ -1000,8 +1001,14 @@ bool AdminModule::handleSetModuleConfig(const meshtastic_ModuleConfig &c)
moduleConfig.has_paxcounter = true;
moduleConfig.paxcounter = c.payload_variant.paxcounter;
break;
case meshtastic_ModuleConfig_statusmessage_tag:
LOG_INFO("Set module config: StatusMessage");
moduleConfig.has_statusmessage = true;
moduleConfig.statusmessage = c.payload_variant.statusmessage;
shouldReboot = false;
break;
}
saveChanges(SEGMENT_MODULECONFIG);
saveChanges(SEGMENT_MODULECONFIG, shouldReboot);
return true;
}
@@ -1180,6 +1187,11 @@ void AdminModule::handleGetModuleConfig(const meshtastic_MeshPacket &req, const
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_paxcounter_tag;
res.get_module_config_response.payload_variant.paxcounter = moduleConfig.paxcounter;
break;
case meshtastic_AdminMessage_ModuleConfigType_STATUSMESSAGE_CONFIG:
LOG_INFO("Get module config: StatusMessage");
res.get_module_config_response.which_payload_variant = meshtastic_ModuleConfig_statusmessage_tag;
res.get_module_config_response.payload_variant.statusmessage = moduleConfig.statusmessage;
break;
}
// NOTE: The phone app needs to know the ls_secsvalue so it can properly expect sleep behavior.

View File

@@ -442,6 +442,7 @@ ExternalNotificationModule::ExternalNotificationModule()
ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshPacket &mp)
{
// Trigger external notification if enabled and not muted; isSilenced is from temporary mute toggles
if (moduleConfig.external_notification.enabled && !isSilenced) {
#ifdef T_WATCH_S3
drv.setWaveform(0, 75);
@@ -456,6 +457,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
for (size_t i = 0; i < p.payload.size; i++) {
if (p.payload.bytes[i] == ASCII_BELL) {
containsBell = true;
break;
}
}
@@ -465,90 +467,47 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
// If we receive a broadcast message, apply channel mute setting
// If we receive a direct message and the receipent is us, apply DM mute setting
// Else we just handle it as not muted.
const bool directToUs = !isBroadcast(mp.to) && isToUs(&mp);
bool is_muted = directToUs ? (sender && ((sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0))
: (ch.settings.has_module_settings && ch.settings.module_settings.is_muted);
const bool isDmToUs = !isBroadcast(mp.to) && isToUs(&mp);
bool is_muted = isDmToUs ? (sender && ((sender->bitfield & NODEINFO_BITFIELD_IS_MUTED_MASK) != 0))
: (ch.settings.has_module_settings && ch.settings.module_settings.is_muted);
if (moduleConfig.external_notification.alert_bell) {
if (containsBell) {
LOG_INFO("externalNotificationModule - Notification Bell");
const bool buzzerModeIsDirectOnly =
(config.device.buzzer_mode == meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY);
if (containsBell || !is_muted) {
if (moduleConfig.external_notification.alert_bell || moduleConfig.external_notification.alert_message ||
moduleConfig.external_notification.alert_bell_vibra ||
moduleConfig.external_notification.alert_message_vibra ||
((moduleConfig.external_notification.alert_bell_buzzer ||
moduleConfig.external_notification.alert_message_buzzer) &&
canBuzz())) {
nagCycleCutoff = millis() + (moduleConfig.external_notification.nag_timeout
? (moduleConfig.external_notification.nag_timeout * 1000)
: moduleConfig.external_notification.output_ms);
LOG_INFO("Toggling nagCycleCutoff to %lu", nagCycleCutoff);
isNagging = true;
}
if (moduleConfig.external_notification.alert_bell || moduleConfig.external_notification.alert_message) {
LOG_INFO("externalNotificationModule - Notification Module or Bell");
setExternalState(0, true);
if (moduleConfig.external_notification.nag_timeout) {
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
} else {
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
}
}
if (moduleConfig.external_notification.alert_bell_vibra) {
if (containsBell) {
LOG_INFO("externalNotificationModule - Notification Bell (Vibra)");
isNagging = true;
if (moduleConfig.external_notification.alert_bell_vibra ||
moduleConfig.external_notification.alert_message_vibra) {
LOG_INFO("externalNotificationModule - Notification Module or Bell (Vibra)");
setExternalState(1, true);
if (moduleConfig.external_notification.nag_timeout) {
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
}
if ((moduleConfig.external_notification.alert_bell_buzzer ||
moduleConfig.external_notification.alert_message_buzzer) &&
canBuzz()) {
LOG_INFO("externalNotificationModule - Notification Module or Bell (Buzzer)");
if (buzzerModeIsDirectOnly && !isDmToUs && !containsBell) {
LOG_INFO("Message buzzer was suppressed because buzzer mode DIRECT_MSG_ONLY");
} else {
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
}
}
if (moduleConfig.external_notification.alert_bell_buzzer && canBuzz()) {
if (containsBell) {
LOG_INFO("externalNotificationModule - Notification Bell (Buzzer)");
isNagging = true;
if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) {
setExternalState(2, true);
} else {
#ifdef HAS_I2S
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
} else
#endif
if (moduleConfig.external_notification.use_pwm) {
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
}
}
if (moduleConfig.external_notification.nag_timeout) {
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
} else {
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
}
}
if (moduleConfig.external_notification.alert_message && !is_muted) {
LOG_INFO("externalNotificationModule - Notification Module");
isNagging = true;
setExternalState(0, true);
if (moduleConfig.external_notification.nag_timeout) {
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
} else {
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
}
if (moduleConfig.external_notification.alert_message_vibra && !is_muted) {
LOG_INFO("externalNotificationModule - Notification Module (Vibra)");
isNagging = true;
setExternalState(1, true);
if (moduleConfig.external_notification.nag_timeout) {
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
} else {
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
}
if (moduleConfig.external_notification.alert_message_buzzer && !is_muted) {
LOG_INFO("externalNotificationModule - Notification Module (Buzzer)");
if (config.device.buzzer_mode != meshtastic_Config_DeviceConfig_BuzzerMode_DIRECT_MSG_ONLY ||
(!isBroadcast(mp.to) && isToUs(&mp))) {
// Buzz if buzzer mode is not in DIRECT_MSG_ONLY or is DM to us
isNagging = true;
// Buzz if buzzer mode is not in DIRECT_MSG_ONLY or is DM to us
#ifdef T_LORA_PAGER
if (canBuzz()) {
drv.setWaveform(0, 16); // Long buzzer 100%
drv.setWaveform(1, 0); // Pause
drv.setWaveform(2, 16);
@@ -558,11 +517,7 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
drv.setWaveform(6, 16);
drv.setWaveform(7, 0);
drv.go();
}
#endif
if (!moduleConfig.external_notification.use_pwm && !moduleConfig.external_notification.use_i2s_as_buzzer) {
setExternalState(2, true);
} else {
#ifdef HAS_I2S
if (moduleConfig.external_notification.use_i2s_as_buzzer) {
audioThread->beginRttl(rtttlConfig.ringtone, strlen_P(rtttlConfig.ringtone));
@@ -570,18 +525,13 @@ ProcessMessage ExternalNotificationModule::handleReceived(const meshtastic_MeshP
#endif
if (moduleConfig.external_notification.use_pwm) {
rtttl::begin(config.device.buzzer_gpio, rtttlConfig.ringtone);
} else {
setExternalState(2, true);
}
}
if (moduleConfig.external_notification.nag_timeout) {
nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
} else {
nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
} else {
// Don't beep if buzzer mode is "direct messages only" and it is no direct message
LOG_INFO("Message buzzer was suppressed because buzzer mode DIRECT_MSG_ONLY");
}
}
setIntervalFromNow(0); // run once so we know if we should do something
}
} else {

View File

@@ -1,24 +1,7 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
#include "buzz/BuzzerFeedbackThread.h"
#include "input/ExpressLRSFiveWay.h"
#include "input/InputBroker.h"
#include "input/RotaryEncoderImpl.h"
#include "input/RotaryEncoderInterruptImpl1.h"
#include "input/SerialKeyboardImpl.h"
#include "input/UpDownInterruptImpl1.h"
#include "input/i2cButton.h"
#include "modules/SystemCommandsModule.h"
#if HAS_TRACKBALL
#include "input/TrackballInterruptImpl1.h"
#endif
#include "modules/StatusLEDModule.h"
#if !MESHTASTIC_EXCLUDE_I2C
#include "input/cardKbI2cImpl.h"
#endif
#include "input/kbMatrixImpl.h"
#endif
#if !MESHTASTIC_EXCLUDE_PKI
#include "KeyVerificationModule.h"
@@ -59,8 +42,6 @@
#include "modules/WaypointModule.h"
#endif
#if ARCH_PORTDUINO
#include "input/LinuxInputImpl.h"
#include "input/SeesawRotary.h"
#include "modules/Telemetry/HostMetrics.h"
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
#include "modules/StoreForwardModule.h"
@@ -108,6 +89,9 @@
#if !MESHTASTIC_EXCLUDE_DROPZONE
#include "modules/DropzoneModule.h"
#endif
#if !MESHTASTIC_EXCLUDE_STATUS
#include "modules/StatusMessageModule.h"
#endif
/**
* Create module instances here. If you are adding a new module, you must 'new' it here (or somewhere else)
@@ -165,6 +149,9 @@ void setupModules()
#if !MESHTASTIC_EXCLUDE_DROPZONE
dropzoneModule = new DropzoneModule();
#endif
#if !MESHTASTIC_EXCLUDE_STATUS
statusMessageModule = new StatusMessageModule();
#endif
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
new GenericThreadModule();
#endif
@@ -179,63 +166,6 @@ void setupModules()
#endif
// Example: Put your module here
// new ReplyModule();
#if (HAS_BUTTON || ARCH_PORTDUINO) && !MESHTASTIC_EXCLUDE_INPUTBROKER
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
#if defined(T_LORA_PAGER)
// use a special FSM based rotary encoder version for T-LoRa Pager
rotaryEncoderImpl = new RotaryEncoderImpl();
if (!rotaryEncoderImpl->init()) {
delete rotaryEncoderImpl;
rotaryEncoderImpl = nullptr;
}
#elif defined(INPUTDRIVER_ENCODER_TYPE) && (INPUTDRIVER_ENCODER_TYPE == 2)
upDownInterruptImpl1 = new UpDownInterruptImpl1();
if (!upDownInterruptImpl1->init()) {
delete upDownInterruptImpl1;
upDownInterruptImpl1 = nullptr;
}
#else
rotaryEncoderInterruptImpl1 = new RotaryEncoderInterruptImpl1();
if (!rotaryEncoderInterruptImpl1->init()) {
delete rotaryEncoderInterruptImpl1;
rotaryEncoderInterruptImpl1 = nullptr;
}
#endif
cardKbI2cImpl = new CardKbI2cImpl();
cardKbI2cImpl->init();
#if defined(M5STACK_UNITC6L)
i2cButton = new i2cButtonThread("i2cButtonThread");
#endif
#ifdef INPUTBROKER_MATRIX_TYPE
kbMatrixImpl = new KbMatrixImpl();
kbMatrixImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
#ifdef INPUTBROKER_SERIAL_TYPE
aSerialKeyboardImpl = new SerialKeyboardImpl();
aSerialKeyboardImpl->init();
#endif // INPUTBROKER_MATRIX_TYPE
}
#endif // HAS_BUTTON
#if ARCH_PORTDUINO
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR && portduino_config.i2cdev != "") {
seesawRotary = new SeesawRotary("SeesawRotary");
if (!seesawRotary->init()) {
delete seesawRotary;
seesawRotary = nullptr;
}
aLinuxInputImpl = new LinuxInputImpl();
aLinuxInputImpl->init();
}
#endif
#if !MESHTASTIC_EXCLUDE_INPUTBROKER && HAS_TRACKBALL
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
trackballInterruptImpl1 = new TrackballInterruptImpl1();
trackballInterruptImpl1->init(TB_DOWN, TB_UP, TB_LEFT, TB_RIGHT, TB_PRESS);
}
#endif
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE
expressLRSFiveWayInput = new ExpressLRSFiveWay();
#endif
#if HAS_SCREEN && !MESHTASTIC_EXCLUDE_CANNEDMESSAGES
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
cannedMessageModule = new CannedMessageModule();

View File

@@ -67,6 +67,8 @@ uint8_t RoutingModule::getHopLimitForResponse(const meshtastic_MeshPacket &mp)
#if !(EVENTMODE) // This falls through to the default.
return hopsUsed; // If the request used more hops than the limit, use the same amount of hops
#endif
} else if (mp.hop_start == 0) {
return 0; // The requesting node wanted 0 hops, so the response also uses a direct/local path.
} else if ((uint8_t)(hopsUsed + 2) < config.lora.hop_limit) {
return hopsUsed + 2; // Use only the amount of hops needed with some margin as the way back may be different
}

View File

@@ -63,29 +63,26 @@
SerialModule *serialModule;
SerialModuleRadio *serialModuleRadio;
#if defined(TTGO_T_ECHO) || defined(TTGO_T_ECHO_PLUS) || defined(CANARYONE) || defined(MESHLINK) || \
defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M4) || defined(ELECROW_ThinkNode_M5) || \
defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) || defined(ELECROW_ThinkNode_M3) || defined(MUZI_BASE)
SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &Serial;
#elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL)
SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &Serial1;
#else
SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &Serial2;
#ifndef SERIAL_PRINT_PORT
#define SERIAL_PRINT_PORT 2
#endif
#if SERIAL_PRINT_PORT == 0
#define SERIAL_PRINT_OBJECT Serial
#elif SERIAL_PRINT_PORT == 1
#define SERIAL_PRINT_OBJECT Serial1
#elif SERIAL_PRINT_PORT == 2
#define SERIAL_PRINT_OBJECT Serial2
#else
#error "Unsupported SERIAL_PRINT_PORT value. Allowed values are 0, 1, or 2."
#endif
SerialModule::SerialModule() : StreamAPI(&SERIAL_PRINT_OBJECT), concurrency::OSThread("Serial")
{
api_type = TYPE_SERIAL;
}
static Print *serialPrint = &SERIAL_PRINT_OBJECT;
char serialBytes[512];
size_t serialPayloadSize;
@@ -205,9 +202,7 @@ int32_t SerialModule::runOnce()
Serial.begin(baud);
Serial.setTimeout(moduleConfig.serial.timeout > 0 ? moduleConfig.serial.timeout : TIMEOUT);
}
#elif !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \
!defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M4) && \
!defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
#elif SERIAL_PRINT_PORT != 0
if (moduleConfig.serial.rxd && moduleConfig.serial.txd) {
#ifdef ARCH_RP2040
@@ -264,9 +259,7 @@ int32_t SerialModule::runOnce()
}
}
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && !defined(MESHLINK) && \
!defined(ELECROW_ThinkNode_M1) && !defined(ELECROW_ThinkNode_M3) && !defined(ELECROW_ThinkNode_M4) && \
!defined(ELECROW_ThinkNode_M5) && !defined(MUZI_BASE)
#if SERIAL_PRINT_PORT != 0
else if ((moduleConfig.serial.mode == meshtastic_ModuleConfig_SerialConfig_Serial_Mode_WS85)) {
processWXSerial();
@@ -540,11 +533,7 @@ ParsedLine parseLine(const char *line)
*/
void SerialModule::processWXSerial()
{
#if !defined(TTGO_T_ECHO) && !defined(TTGO_T_ECHO_PLUS) && !defined(T_ECHO_LITE) && !defined(CANARYONE) && \
!defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(MESHLINK) && !defined(ELECROW_ThinkNode_M1) && \
!defined(ELECROW_ThinkNode_M3) && \
!defined(ELECROW_ThinkNode_M4) && \
!defined(ELECROW_ThinkNode_M5) && !defined(ARCH_STM32WL) && !defined(MUZI_BASE)
#if SERIAL_PRINT_PORT != 0 && !defined(ARCH_STM32WL) && !defined(CONFIG_IDF_TARGET_ESP32C6)
static unsigned int lastAveraged = 0;
static unsigned int averageIntervalMillis = 300000; // 5 minutes hard coded.

View File

@@ -0,0 +1,41 @@
#if !MESHTASTIC_EXCLUDE_STATUS
#include "StatusMessageModule.h"
#include "MeshService.h"
#include "ProtobufModule.h"
StatusMessageModule *statusMessageModule;
int32_t StatusMessageModule::runOnce()
{
if (moduleConfig.has_statusmessage && moduleConfig.statusmessage.node_status[0] != '\0') {
// create and send message with the status message set
meshtastic_StatusMessage ourStatus = meshtastic_StatusMessage_init_zero;
strncpy(ourStatus.status, moduleConfig.statusmessage.node_status, sizeof(ourStatus.status));
ourStatus.status[sizeof(ourStatus.status) - 1] = '\0'; // ensure null termination
meshtastic_MeshPacket *p = allocDataPacket();
p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes),
meshtastic_StatusMessage_fields, &ourStatus);
p->to = NODENUM_BROADCAST;
p->decoded.want_response = false;
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
p->channel = 0;
service->sendToMesh(p);
}
return 1000 * 12 * 60 * 60;
}
ProcessMessage StatusMessageModule::handleReceived(const meshtastic_MeshPacket &mp)
{
if (mp.which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
meshtastic_StatusMessage incomingMessage;
if (pb_decode_from_bytes(mp.decoded.payload.bytes, mp.decoded.payload.size, meshtastic_StatusMessage_fields,
&incomingMessage)) {
LOG_INFO("Received a NodeStatus message %s", incomingMessage.status);
}
}
return ProcessMessage::CONTINUE;
}
#endif

View File

@@ -0,0 +1,35 @@
#pragma once
#if !MESHTASTIC_EXCLUDE_STATUS
#include "SinglePortModule.h"
#include "configuration.h"
class StatusMessageModule : public SinglePortModule, private concurrency::OSThread
{
public:
/** Constructor
* name is for debugging output
*/
StatusMessageModule()
: SinglePortModule("statusMessage", meshtastic_PortNum_NODE_STATUS_APP), concurrency::OSThread("StatusMessage")
{
if (moduleConfig.has_statusmessage && moduleConfig.statusmessage.node_status[0] != '\0') {
this->setInterval(2 * 60 * 1000);
} else {
this->setInterval(1000 * 12 * 60 * 60);
}
// TODO: If we have a string, set the initial delay (15 minutes maybe)
}
virtual int32_t runOnce() override;
protected:
/** Called to handle a particular incoming message
*/
virtual ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
private:
};
extern StatusMessageModule *statusMessageModule;
#endif

View File

@@ -529,37 +529,46 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac
bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m)
{
bool valid = true;
bool valid = false;
bool hasSensor = false;
// getMetrics() doesn't always get evaluated because of
// short-circuit evaluation rules in c++
bool get_metrics;
m->time = getTime();
m->which_variant = meshtastic_Telemetry_environment_metrics_tag;
m->variant.environment_metrics = meshtastic_EnvironmentMetrics_init_zero;
for (TelemetrySensor *sensor : sensors) {
valid = valid && sensor->getMetrics(m);
get_metrics = sensor->getMetrics(m); // avoid short-circuit evaluation rules
valid = valid || get_metrics;
hasSensor = true;
}
#ifndef T1000X_SENSOR_EN
if (ina219Sensor.hasSensor()) {
valid = valid && ina219Sensor.getMetrics(m);
get_metrics = ina219Sensor.getMetrics(m);
valid = valid || get_metrics;
hasSensor = true;
}
if (ina260Sensor.hasSensor()) {
valid = valid && ina260Sensor.getMetrics(m);
get_metrics = ina260Sensor.getMetrics(m);
valid = valid || get_metrics;
hasSensor = true;
}
if (ina3221Sensor.hasSensor()) {
valid = valid && ina3221Sensor.getMetrics(m);
get_metrics = ina3221Sensor.getMetrics(m);
valid = valid || get_metrics;
hasSensor = true;
}
if (max17048Sensor.hasSensor()) {
valid = valid && max17048Sensor.getMetrics(m);
get_metrics = max17048Sensor.getMetrics(m);
valid = valid || get_metrics;
hasSensor = true;
}
#endif
#ifdef HAS_RAKPROT
valid = valid && rak9154Sensor.getMetrics(m);
get_metrics = rak9154Sensor.getMetrics(m);
valid = valid || get_metrics;
hasSensor = true;
#endif
return valid && hasSensor;

View File

@@ -168,18 +168,21 @@ bool HealthTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &
bool HealthTelemetryModule::getHealthTelemetry(meshtastic_Telemetry *m)
{
bool valid = true;
bool valid = false;
bool hasSensor = false;
bool get_metrics;
m->time = getTime();
m->which_variant = meshtastic_Telemetry_health_metrics_tag;
m->variant.health_metrics = meshtastic_HealthMetrics_init_zero;
if (max30102Sensor.hasSensor()) {
valid = valid && max30102Sensor.getMetrics(m);
get_metrics = max30102Sensor.getMetrics(m);
valid = valid || get_metrics; // avoid short-circuit evaluation rules
hasSensor = true;
}
if (mlx90614Sensor.hasSensor()) {
valid = valid && mlx90614Sensor.getMetrics(m);
get_metrics = mlx90614Sensor.getMetrics(m);
valid = valid || get_metrics;
hasSensor = true;
}

View File

@@ -872,6 +872,7 @@ bool loadConfig(const char *configPath)
}
if (yamlConfig["Config"]) {
portduino_config.has_config_overrides = true;
if (yamlConfig["Config"]["DisplayMode"]) {
portduino_config.has_configDisplayMode = true;
if ((yamlConfig["Config"]["DisplayMode"]).as<std::string>("") == "TWOCOLOR") {
@@ -884,6 +885,13 @@ bool loadConfig(const char *configPath)
portduino_config.configDisplayMode = meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT;
}
}
if (yamlConfig["Config"]["StatusMessage"]) {
portduino_config.has_statusMessage = true;
portduino_config.statusMessage = (yamlConfig["Config"]["StatusMessage"]).as<std::string>("");
}
if ((yamlConfig["Config"]["EnableUDP"]).as<bool>(false)) {
portduino_config.enable_UDP = true;
}
}
if (yamlConfig["General"]) {

View File

@@ -177,8 +177,12 @@ extern struct portduino_config_struct {
int hostMetrics_channel = 0;
// config
bool has_config_overrides = false;
int configDisplayMode = 0;
bool has_configDisplayMode = false;
std::string statusMessage = "";
bool has_statusMessage = false;
bool enable_UDP = false;
// General
std::string mac_address = "";
@@ -505,21 +509,30 @@ extern struct portduino_config_struct {
}
// config
if (has_configDisplayMode) {
if (has_config_overrides) {
out << YAML::Key << "Config" << YAML::Value << YAML::BeginMap;
switch (configDisplayMode) {
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
break;
if (has_configDisplayMode) {
switch (configDisplayMode) {
case meshtastic_Config_DisplayConfig_DisplayMode_TWOCOLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "TWOCOLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_INVERTED:
out << YAML::Key << "DisplayMode" << YAML::Value << "INVERTED";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_COLOR:
out << YAML::Key << "DisplayMode" << YAML::Value << "COLOR";
break;
case meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT:
out << YAML::Key << "DisplayMode" << YAML::Value << "DEFAULT";
break;
}
}
if (has_statusMessage) {
out << YAML::Key << "StatusMessage" << YAML::Value << statusMessage;
}
if (enable_UDP) {
out << YAML::Key << "EnableUDP" << YAML::Value << true;
}
out << YAML::EndMap; // Config

View File

@@ -12,4 +12,4 @@ build_flags =
lib_deps =
${esp32_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19

View File

@@ -36,4 +36,4 @@ lib_ignore =
lib_deps =
${esp32_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19

View File

@@ -6,8 +6,6 @@
#define LED_GREEN 12
#define LED_BLUE 2
#define LED_BUILTIN LED_GREEN
static const uint8_t TX = 1;
static const uint8_t RX = 3;

View File

@@ -6,8 +6,6 @@
#define LED_GREEN 12
#define LED_BLUE 2
#define LED_BUILTIN LED_GREEN
static const uint8_t TX = 1;
static const uint8_t RX = 3;

View File

@@ -18,6 +18,7 @@ build_flags = ${esp32_base.build_flags}
-I variants/esp32/tbeam
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-ULED_BUILTIN
upload_speed = 921600
[env:tbeam-displayshield]

View File

@@ -11,7 +11,7 @@ build_flags =
lib_deps =
${esp32_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
# renovate: datasource=custom.pio depName=SX1509 IO Expander packageName=sparkfun/library/SX1509 IO Expander
sparkfun/SX1509 IO Expander@3.0.6
# renovate: datasource=custom.pio depName=APA102 packageName=pololu/library/APA102

View File

@@ -50,3 +50,5 @@ void c6l_init();
#endif
#define SCREEN_TRANSITION_FRAMERATE 10
#define BRIGHTNESS_DEFAULT 130 // Medium Low Brightness
#define SERIAL_PRINT_PORT 1

View File

@@ -8,3 +8,4 @@ build_flags =
-I variants/esp32c6/tlora_c6
-DARDUINO_USB_CDC_ON_BOOT=1
-DARDUINO_USB_MODE=1
-ULED_BUILTIN

View File

@@ -19,3 +19,5 @@
#define SX126X_TXEN 14
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define SERIAL_PRINT_PORT 1

View File

@@ -81,4 +81,6 @@
#define BUTTON_PIN PIN_BUTTON1
#define BUTTON_PIN_ALT PIN_BUTTON2
#define SERIAL_PRINT_PORT 0
#endif

View File

@@ -18,3 +18,4 @@ build_flags =
${esp32s3_base.build_flags}
-D HELTEC_V3
-I variants/esp32s3/heltec_v3
-ULED_BUILTIN

View File

@@ -6,10 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
static const uint8_t LED_BUILTIN = 35;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN // allow testing #ifdef LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -126,7 +126,7 @@ build_flags =
lib_deps = ${heltec_v4_base.lib_deps}
; ${device-ui_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.0
lovyan03/LovyanGFX@1.2.19
# renovate: datasource=git-refs depName=Quency-D_chsc6x packageName=https://github.com/Quency-D/chsc6x gitBranch=master
https://github.com/Quency-D/chsc6x/archive/5cbead829d6b432a8d621ed1aafd4eb474fd4f27.zip
; TODO revert to official device-ui (when merged)

View File

@@ -3,10 +3,6 @@
#include <stdint.h>
static const uint8_t LED_BUILTIN = 45; // LED is not populated on earliest board variant
#define BUILTIN_LED LED_BUILTIN // Backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -3,10 +3,6 @@
#include <stdint.h>
static const uint8_t LED_BUILTIN = 45; // LED is not populated on earliest board variant
#define BUILTIN_LED LED_BUILTIN // Backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -3,10 +3,6 @@
#include <stdint.h>
static const uint8_t LED_BUILTIN = 35;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -3,10 +3,6 @@
#include <stdint.h>
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -3,10 +3,6 @@
#include <stdint.h>
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t KEY_BUILTIN = 0;
static const uint8_t TX = 43;

View File

@@ -11,10 +11,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -24,4 +24,4 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19

View File

@@ -11,10 +11,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -22,4 +22,4 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19

View File

@@ -10,10 +10,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -20,4 +20,4 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19

View File

@@ -10,10 +10,7 @@
// Some boards have too low voltage on this pin (board design bug)
// Use different pin with 3V and connect with 48
// and change this setup for the chosen pin (for example 38)
static const uint8_t LED_BUILTIN = SOC_GPIO_PIN_COUNT + 48;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
#define RGB_BUILTIN LED_BUILTIN
#define RGB_BUILTIN SOC_GPIO_PIN_COUNT + 48
#define RGB_BRIGHTNESS 64
static const uint8_t TX = 43;

View File

@@ -49,10 +49,6 @@ static const uint8_t T14 = 14;
static const uint8_t VBAT_SENSE = 2;
static const uint8_t VBUS_SENSE = 34;
// User LED
#define LED_BUILTIN 13
#define BUILTIN_LED LED_BUILTIN // backward compatibility
static const uint8_t RGB_DATA = 40;
// RGB_BUILTIN and RGB_BRIGHTNESS can be used in new Arduino API neopixelWrite()
#define RGB_BUILTIN (RGB_DATA + SOC_GPIO_PIN_COUNT)

View File

@@ -51,7 +51,7 @@ lib_deps =
${esp32s3_base.lib_deps}
${device-ui_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
[mesh_tab_xpt2046]
extends = mesh_tab_base

View File

@@ -24,7 +24,7 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
build_src_filter =
${esp32s3_base.build_src_filter}

View File

@@ -24,9 +24,6 @@ static const uint8_t SCK = 13;
#define SPI_MISO (10)
#define SPI_CS (12)
// LEDs
#define LED_BUILTIN LED_GREEN
#ifdef _VARIANT_RAK3112_
/*
* Serial interfaces

View File

@@ -22,7 +22,4 @@ static const uint8_t SCK = 13;
#define SPI_MISO (10)
#define SPI_CS (12)
// LEDs
#define LED_BUILTIN LED_GREEN
#endif /* Pins_Arduino_h */

View File

@@ -16,7 +16,7 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
[ft5x06]
extends = mesh_tab_base

View File

@@ -3,8 +3,6 @@
#include <stdint.h>
// static const uint8_t LED_BUILTIN = -1;
// static const uint8_t TX = 43;
// static const uint8_t RX = 44;

View File

@@ -6,8 +6,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
// static const uint8_t LED_BUILTIN = -1;
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -28,7 +28,7 @@ build_flags = ${esp32s3_base.build_flags}
lib_deps = ${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
# renovate: datasource=custom.pio depName=ESP8266Audio packageName=earlephilhower/library/ESP8266Audio
earlephilhower/ESP8266Audio@1.9.9
# renovate: datasource=custom.pio depName=ESP8266SAM packageName=earlephilhower/library/ESP8266SAM

View File

@@ -3,8 +3,6 @@
#include <stdint.h>
// static const uint8_t LED_BUILTIN = -1;
// static const uint8_t TX = 43;
// static const uint8_t RX = 44;

View File

@@ -22,7 +22,7 @@ build_flags = ${esp32s3_base.build_flags}
lib_deps = ${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
# renovate: datasource=custom.pio depName=SensorLib packageName=lewisxhe/library/SensorLib
lewisxhe/SensorLib@0.3.4
# renovate: datasource=custom.pio depName=Adafruit DRV2605 packageName=adafruit/library/Adafruit DRV2605 Library

View File

@@ -33,7 +33,7 @@ build_flags = ${esp32s3_base.build_flags}
lib_deps = ${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
# renovate: datasource=custom.pio depName=ESP8266Audio packageName=earlephilhower/library/ESP8266Audio
earlephilhower/ESP8266Audio@1.9.9
# renovate: datasource=custom.pio depName=ESP8266SAM packageName=earlephilhower/library/ESP8266SAM

View File

@@ -11,10 +11,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -11,10 +11,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -11,10 +11,6 @@
#define USB_VID 0x303a
#define USB_PID 0x1001
static const uint8_t LED_BUILTIN = 18;
#define BUILTIN_LED LED_BUILTIN // backward compatibility
#define LED_BUILTIN LED_BUILTIN
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -22,7 +22,7 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
[env:tracksenger-lcd]
custom_meshtastic_hw_model = 48
@@ -48,7 +48,7 @@ build_flags =
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
[env:tracksenger-oled]
custom_meshtastic_hw_model = 48

View File

@@ -6,9 +6,6 @@
#define USB_VID 0x16D0
#define USB_PID 0x1178
#define LED_BUILTIN 13
#define BUILTIN_LED LED_BUILTIN // backward compatibility
static const uint8_t TX = 43;
static const uint8_t RX = 44;

View File

@@ -37,7 +37,7 @@ build_src_filter =
lib_deps = ${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.0
lovyan03/LovyanGFX@1.2.19
# TODO renovate
https://gitlab.com/hamishcunningham/unphonelibrary#meshtastic@9.0.0
# renovate: datasource=custom.pio depName=NeoPixel packageName=adafruit/library/Adafruit NeoPixel

View File

@@ -27,7 +27,7 @@ lib_deps =
# renovate: datasource=custom.pio depName=rweather/Crypto packageName=rweather/library/Crypto
rweather/Crypto@0.4.0
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
lovyan03/LovyanGFX@1.2.7
lovyan03/LovyanGFX@1.2.19
# renovate: datasource=git-refs depName=libch341-spi-userspace packageName=https://github.com/pine64/libch341-spi-userspace gitBranch=main
https://github.com/pine64/libch341-spi-userspace/archive/23c42319a69cffcb65868e3c72e6bed83974a393.zip
# renovate: datasource=custom.pio depName=adafruit/Adafruit seesaw Library packageName=adafruit/library/Adafruit seesaw Library

View File

@@ -50,7 +50,6 @@ extern "C" {
#define RGBLED_BLUE (0 + 12) // Blue of RGB P0.12
#define RGBLED_CA // comment out this line if you have a common cathode type, as defined use common anode logic
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -55,7 +55,6 @@ extern "C" {
#define LED_RED PIN_LED3
#define LED_BLUE PIN_LED1
#define LED_GREEN PIN_LED2
#define LED_BUILTIN LED_BLUE
#define LED_CONN PIN_GREEN
#define LED_STATE_ON 0 // State when LED is lit // LED灯亮时的状态
#define PIN_BUZZER (0 + 6)
@@ -159,6 +158,8 @@ External serial flash WP25R1635FZUIL0
#define PIN_SERIAL1_TX GPS_TX_PIN
#define PIN_SERIAL1_RX GPS_RX_PIN
#define SERIAL_PRINT_PORT 0
/*
* SPI Interfaces
*/

View File

@@ -58,7 +58,6 @@ extern "C" {
#define LED_BLUE 37
#define LED_PAIRING LED_BLUE // Signals the Status LED Module to handle this LED
#define LED_BUILTIN -1
#define LED_STATE_ON LOW
#define LED_STATE_OFF HIGH
@@ -113,6 +112,8 @@ extern "C" {
#define LR11X0_DIO3_TCXO_VOLTAGE 3.3
#define LR11X0_DIO_AS_RF_SWITCH
#define SERIAL_PRINT_PORT 0
// PCF8563 RTC Module
// REVISIT https://github.com/meshtastic/firmware/pull/9084
// #define PCF8563_RTC 0x51

View File

@@ -40,7 +40,6 @@ extern "C" {
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define LED_BUILTIN -1
#define LED_BLUE -1
#define PIN_LED2 (32 + 9)
#define LED_PAIRING (13)
@@ -135,6 +134,8 @@ static const uint8_t A0 = PIN_A0;
#define PIN_SERIAL1_RX GPS_RX_PIN
#define PIN_SERIAL1_TX GPS_TX_PIN
#define SERIAL_PRINT_PORT 0
#ifdef __cplusplus
}
#endif

View File

@@ -40,7 +40,6 @@ extern "C" {
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define LED_BUILTIN -1
#define LED_BLUE -1
#define LED_CHARGE (12)
#define LED_PAIRING (7)

View File

@@ -51,7 +51,6 @@ extern "C" {
#define PIN_LED1 (32 + 7) // P1.07 Blue D2
#define LED_PIN PIN_LED1
#define LED_BUILTIN -1
#define LED_BLUE -1
#define LED_STATE_ON 1 // State when LED is lit

View File

@@ -51,7 +51,6 @@ extern "C" {
#define PIN_LED1 (32 + 7) // P1.07 Blue D2
#define LED_PIN PIN_LED1
#define LED_BUILTIN -1
#define LED_BLUE -1
#define LED_STATE_ON 1 // State when LED is lit

View File

@@ -51,7 +51,6 @@ extern "C" {
#define PIN_LED1 (-1)
#define LED_PIN PIN_LED1
#define LED_BUILTIN -1
#define LED_BLUE -1
#define LED_STATE_ON 1 // State when LED is lit

View File

@@ -29,7 +29,6 @@ extern "C" {
#define PIN_LED1 (32 + 10) // LED P1.15
#define PIN_LED2 (-1) //
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -29,7 +29,6 @@ extern "C" {
#define PIN_LED1 (32 + 10) // LED P1.15
#define PIN_LED2 (-1) //
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -34,7 +34,6 @@ extern "C" {
// #define PIN_LED1 (32 + 9) Green
// #define PIN_LED1 (0 + 12) Blue
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -52,7 +52,6 @@ extern "C" {
#define LED_BLUE PIN_LED1
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED3
#define LED_STATE_ON 0 // State when LED is lit
@@ -170,6 +169,8 @@ static const uint8_t A0 = PIN_A0;
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER (2.0F)
#define SERIAL_PRINT_PORT 0
#ifdef __cplusplus
}
#endif

View File

@@ -81,7 +81,6 @@ NRF52 PRO MICRO PIN ASSIGNMENT
// LED
#define PIN_LED1 (0 + 15) // P0.15
#define LED_BUILTIN PIN_LED1
// Actually red
#define LED_BLUE PIN_LED1
#define LED_STATE_ON 1 // State when LED is lit

View File

@@ -38,7 +38,6 @@ extern "C" {
#define PIN_LED PIN_LED1
#define LED_PWR (PINS_COUNT)
#define LED_BUILTIN PIN_LED
#define LED_STATE_ON 1 // State when LED is lit
// XIAO Wio-SX1262 Shield User button

View File

@@ -44,7 +44,6 @@ extern "C" {
// LED
#define PIN_LED1 (0 + 15)
#define LED_BUILTIN PIN_LED1
// Actually red
#define LED_BLUE PIN_LED1
#define LED_STATE_ON 1

View File

@@ -49,8 +49,6 @@ extern "C" {
#define PIN_LED1 (32 + 15) // P1.15 3
#define PIN_LED2 (32 + 10) // P1.10 4
#define LED_BUILTIN PIN_LED1
#define LED_GREEN PIN_LED2 // Actually red
#define LED_BLUE PIN_LED1

View File

@@ -48,7 +48,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -30,7 +30,6 @@ extern "C" {
#define PIN_LED1 (32 + 3) // green (confirmed on 1.0 board)
#define LED_BLUE PIN_LED1 // fake for bluefruit library
#define LED_GREEN PIN_LED1
#define LED_BUILTIN LED_GREEN
#define LED_STATE_ON 0 // State when LED is lit
#define HAS_NEOPIXEL // Enable the use of neopixels

View File

@@ -74,7 +74,6 @@ extern "C" {
#define PIN_LED1 (32 + 3) // green (confirmed on 1.0 board)
#define LED_BLUE PIN_LED1 // fake for bluefruit library
#define LED_GREEN PIN_LED1
#define LED_BUILTIN LED_GREEN
#define LED_STATE_ON 0 // State when LED is lit
#define HAS_NEOPIXEL // Enable the use of neopixels

View File

@@ -26,7 +26,6 @@ extern "C" {
#define LED_RED PIN_LED1
#define LED_BLUE PIN_LED1
#define LED_GREEN PIN_LED1
#define LED_BUILTIN LED_BLUE
#define LED_CONN LED_BLUE
#define LED_STATE_ON 0 // State when LED is lit

View File

@@ -42,7 +42,6 @@ extern "C" {
#define PIN_LED1 (0 + 4) // green (confirmed on 1.0 board)
#define LED_BLUE PIN_LED1 // fake for bluefruit library
#define LED_GREEN PIN_LED1
#define LED_BUILTIN LED_GREEN
#define LED_STATE_ON 0 // State when LED is lit
#define HAS_NEOPIXEL // Enable the use of neopixels
@@ -142,6 +141,8 @@ No longer populated on PCB
#define BQ4050_SCL_PIN (32 + 0) // I2C clock line pin
#define BQ4050_EMERGENCY_SHUTDOWN_PIN (32 + 3) // Emergency shutdown pin
#define SERIAL_PRINT_PORT 0
#ifdef __cplusplus
}
#endif

View File

@@ -31,7 +31,6 @@ extern "C" {
// LEDs
#define PIN_LED1 (24) // Built in white led for status
#define LED_BLUE PIN_LED1
#define LED_BUILTIN PIN_LED1
#define LED_STATE_ON 0 // State when LED is litted
#define LED_INVERTED 1
@@ -54,6 +53,7 @@ extern "C" {
*/
#define PIN_SERIAL1_RX (32 + 8)
#define PIN_SERIAL1_TX (7)
#define SERIAL_PRINT_PORT 0
/*
* SPI Interfaces

View File

@@ -49,7 +49,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -52,7 +52,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36) // Connected to WWAN host LED (if present)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -45,7 +45,6 @@ extern "C" {
#define PIN_LED1 (32 + 3) // P1.03, Green
#define PIN_LED2 (32 + 4) // P1.04, Blue
#define LED_BUILTIN -1 // PIN_LED1
#define LED_BLUE PIN_LED2
#define LED_STATE_ON 0 // State when LED is lit
@@ -176,6 +175,8 @@ extern "C" {
#define EXTERNAL_FLASH_DEVICES W25Q32JVSS
#define EXTERNAL_FLASH_USE_QSPI
#define SERIAL_PRINT_PORT 0
// NFC is disabled via CONFIG_NFCT_PINS_AS_GPIOS=1 build flag
// This configures P0.09 and P0.10 as regular GPIO pins instead of NFC pins

View File

@@ -50,7 +50,6 @@ extern "C" {
#define LED_BLUE PIN_LED1
#define LED_GREEN PIN_LED2
#define LED_BUILTIN LED_BLUE
#define LED_CONN PIN_GREEN
#define LED_STATE_ON 0 // State when LED is lit

View File

@@ -47,7 +47,6 @@ extern "C" {
#define PIN_LED1 (32 + 4) // P1.04 Controls Green LED
#define PIN_LED2 (28) // P0.28 Controls Blue LED
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -48,7 +48,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -47,7 +47,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -47,7 +47,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -47,7 +47,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -29,7 +29,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -47,7 +47,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -47,7 +47,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

View File

@@ -47,7 +47,6 @@ extern "C" {
#define PIN_LED1 (35)
#define PIN_LED2 (36)
#define LED_BUILTIN PIN_LED1
#define LED_CONN PIN_LED2
#define LED_GREEN PIN_LED1

Some files were not shown because too many files have changed in this diff Show More