Compare commits

..

19 Commits

Author SHA1 Message Date
Jonathan Bennett
2626fe5822 Merge branch 'develop' into LED_POWER 2026-02-04 17:17:26 -06:00
Jonathan Bennett
a6c7c2d690 Remove errant endif 2026-02-04 17:17:15 -06:00
Eric Sesterhenn
94b7149958 Remove unused hmx variable (#9529)
The variable is not used at all in the function, remove it to
silence the compiler warning.

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-02-04 17:11:44 -06:00
Jonathan Bennett
50916bcd6e Merge branch 'develop' into LED_POWER 2026-02-04 17:11:33 -06:00
Jonathan Bennett
ac611c4b62 Add agc reset attempt (#8163)
* Add agc reset attempt

* Add radioLibInterface include

* Trunk

* AGC reset don't crash, don't naively call

* Update src/main.cpp

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

* Use Throttle function

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-04 14:47:44 -06:00
Jonathan Bennett
bffe92b23d Merge branch 'develop' into LED_POWER 2026-02-04 11:40:28 -06:00
Max
89df5ef669 Undefine LED_BUILTIN (#9531)
Keep variant in sync with 
https://github.com/meshtastic/firmware/commit/df40085

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-02-04 11:15:49 -06:00
Jason P
bfc3eebd54 HotFix for ReplyBot - Modules.cpp included and moved configuration.h (#9532) 2026-02-04 08:56:50 -06:00
Mattatat25
538a5f0dfc Add reply bot module with DM-only responses and rate limiting (#9456)
* Implement Meshtastic reply bot module with ping and status features

Adds a reply bot module that listens for /ping, /hello, and /test commands received via direct messages or broadcasts on the primary channel. The module always replies via direct message to the sender only, reporting hop count, RSSI, and SNR. Per-sender cooldowns are enforced to reduce network spam, and the module can be excluded at build time via a compile flag. Updates include the new module source files and required build configuration changes.

* Update ReplyBotModule.cpp

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

* Update src/modules/ReplyBotModule.h

Match the existing MESHTASTIC_EXCLUDE_* guard pattern so the module is excluded by default.

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

* Update src/modules/ReplyBotModule.cpp

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

* Tidying up

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
2026-02-03 20:45:02 -06:00
Vortetty
b7db22055d Inkhud battery icon improvements. (#9513)
* Inkhud battery icon improvements.
Fixes the battery icon draining from the flat side towards the bump, which is backwards from general design language seen on most devices
By request of kr0n05_ on discord, adds the ability to mirror the battery icon which fixes that issue in another way, and is also a common design seen on other devices.

* Remove option for icon mirroring

* Add border + dither to battery to prevent font overlap

* Fix trunk format

* Code cleanup, courtesy of Xaositek.
2026-02-03 20:02:54 -05:00
Jonathan Bennett
4ebc5d433b Merge branch 'develop' into LED_POWER 2026-02-03 12:50:14 -06:00
Eric Sesterhenn
0703e0e6d7 Make sure we always return a value in NodeDB::restorePreferences() (#9516)
In case FScom is not defined there is no return statement. This
moves the return outside of the ifdef to make sure a defined
value is returned.
2026-02-03 06:22:33 -06:00
Jonathan Bennett
d55c652310 Merge branch 'develop' into LED_POWER 2026-02-03 00:14:24 -06:00
Jonathan Bennett
f514bc230b Prefer EXT_PWR_DETECT pin over chargingVolt to detect power unplugged (#9511) 2026-02-03 00:13:49 -06:00
Jonathan Bennett
6028797d3e Misc 2026-02-02 18:02:19 -06:00
Jonathan Bennett
167e9cfde2 Rename LED_PIN to LED_POWER, move handling out of main to dedicated module 2026-02-02 17:15:17 -06:00
Jason P
0022148323 Missed in reviews - fixing send bubble (#9505) 2026-02-01 19:10:00 -06:00
Jonathan Bennett
9d06c1bf34 Add StatusMessage module and config overrides (#9351)
* Add StatusMessage module and config overrides

* Trunk

* Don't reboot node simply for a StatusMessage config update
2026-01-31 14:55:51 -06:00
Jonathan Bennett
1d30342c00 Don't ever define PIN_LED or BLE_LED_INVERTED (#9494)
* Don't ever define PIN_LED

* Deprecate BLE_LED_INVERTED
2026-01-31 12:15:06 -06:00
141 changed files with 633 additions and 428 deletions

View File

@@ -156,8 +156,16 @@ IF %BPS_RESET% EQU 1 (
SET "PROGNAME=!FILENAME:.factory.bin=!"
CALL :LOG_MESSAGE DEBUG "Computed PROGNAME: !PROGNAME!"
@REM Determine OTA filename based on MCU type (unified OTA format)
SET "OTA_FILENAME=mt-!MCU!-ota.bin"
IF "__!MCU!__" == "__esp32s3__" (
@REM We are working with ESP32-S3
SET "OTA_FILENAME=bleota-s3.bin"
) ELSE IF "__!MCU!__" == "__esp32c3__" (
@REM We are working with ESP32-C3
SET "OTA_FILENAME=bleota-c3.bin"
) ELSE (
@REM Everything else
SET "OTA_FILENAME=bleota.bin"
)
CALL :LOG_MESSAGE DEBUG "Set OTA_FILENAME to: !OTA_FILENAME!"
@REM Set SPIFFS filename with "littlefs-" prefix.

View File

@@ -131,8 +131,14 @@ if [[ -f "$FILENAME" && "$FILENAME" == *.factory.bin ]]; then
exit 1
fi
# Determine OTA filename based on MCU type (unified OTA format)
OTAFILE="mt-${MCU}-ota.bin"
# Determine OTA filename based on MCU type
if [ "$MCU" == "esp32s3" ]; then
OTAFILE=bleota-s3.bin
elif [ "$MCU" == "esp32c3" ]; then
OTAFILE=bleota-c3.bin
else
OTAFILE=bleota.bin
fi
# Set SPIFFS filename with "littlefs-" prefix.
SPIFFSFILE="littlefs-${PROGNAME/firmware-/}.bin"

View File

@@ -50,6 +50,7 @@ build_flags = -Wno-missing-field-initializers
-DRADIOLIB_EXCLUDE_APRS=1
-DRADIOLIB_EXCLUDE_LORAWAN=1
-DMESHTASTIC_EXCLUDE_DROPZONE=1
-DMESHTASTIC_EXCLUDE_REPLYBOT=1
-DMESHTASTIC_EXCLUDE_REMOTEHARDWARE=1
-DMESHTASTIC_EXCLUDE_HEALTH_TELEMETRY=1
-DMESHTASTIC_EXCLUDE_POWERSTRESS=1 ; exclude power stress test module from main firmware
@@ -120,7 +121,7 @@ lib_deps =
[device-ui_base]
lib_deps =
# renovate: datasource=git-refs depName=meshtastic/device-ui packageName=https://github.com/meshtastic/device-ui gitBranch=master
https://github.com/meshtastic/device-ui/archive/48e3a59ddfd746dfbde562a7f447cf9da4f369cf.zip
https://github.com/meshtastic/device-ui/archive/63967a4a557d33d56fc5746f9128200dde2d88c5.zip
; Common libs for environmental measurements in telemetry module
[environmental_base]

View File

@@ -89,22 +89,14 @@ class BluetoothStatus : public Status
case ConnectionState::CONNECTED:
LOG_DEBUG("BluetoothStatus CONNECTED");
#ifdef BLE_LED
#ifdef BLE_LED_INVERTED
digitalWrite(BLE_LED, LOW);
#else
digitalWrite(BLE_LED, HIGH);
#endif
digitalWrite(BLE_LED, LED_STATE_ON);
#endif
break;
case ConnectionState::DISCONNECTED:
LOG_DEBUG("BluetoothStatus DISCONNECTED");
#ifdef BLE_LED
#ifdef BLE_LED_INVERTED
digitalWrite(BLE_LED, HIGH);
#else
digitalWrite(BLE_LED, LOW);
#endif
digitalWrite(BLE_LED, LED_STATE_OFF);
#endif
break;
}

View File

@@ -1,66 +0,0 @@
#include "Led.h"
#include "PowerMon.h"
#include "main.h"
#include "power.h"
GpioVirtPin ledForceOn, ledBlink;
#if defined(LED_PIN)
// Most boards have a GPIO for LED control
static GpioHwPin ledRawHwPin(LED_PIN);
#else
static GpioVirtPin ledRawHwPin; // Dummy pin for no hardware
#endif
#if LED_STATE_ON == 0
static GpioVirtPin ledHwPin;
static GpioNotTransformer ledInverter(&ledHwPin, &ledRawHwPin);
#else
static GpioPin &ledHwPin = ledRawHwPin;
#endif
#if defined(HAS_PMU)
/**
* A GPIO controlled by the PMU
*/
class GpioPmuPin : public GpioPin
{
public:
void set(bool value)
{
if (pmu_found && PMU) {
// blink the axp led
PMU->setChargingLedMode(value ? XPOWERS_CHG_LED_ON : XPOWERS_CHG_LED_OFF);
}
}
} ledPmuHwPin;
// In some cases we need to drive a PMU LED and a normal LED
static GpioSplitter ledFinalPin(&ledHwPin, &ledPmuHwPin);
#else
static GpioPin &ledFinalPin = ledHwPin;
#endif
#ifdef USE_POWERMON
/**
* We monitor changes to the LED drive output because we use that as a sanity test in our power monitor stuff.
*/
class MonitoredLedPin : public GpioPin
{
public:
void set(bool value)
{
if (powerMon) {
if (value)
powerMon->setState(meshtastic_PowerMon_State_LED_On);
else
powerMon->clearState(meshtastic_PowerMon_State_LED_On);
}
ledFinalPin.set(value);
}
} monitoredLedPin;
#else
static GpioPin &monitoredLedPin = ledFinalPin;
#endif
static GpioBinaryTransformer ledForcer(&ledForceOn, &ledBlink, &monitoredLedPin, GpioBinaryTransformer::Or);

View File

@@ -1,7 +0,0 @@
#include "GpioLogic.h"
#include "configuration.h"
/**
* ledForceOn and ledForceOff both override the normal ledBlinker behavior (which is controlled by main)
*/
extern GpioVirtPin ledForceOn, ledBlink;

View File

@@ -459,6 +459,8 @@ class AnalogBatteryLevel : public HasBatteryLevel
}
// if it's not HIGH - check the battery
#endif
// If we have an EXT_PWR_DETECT pin and it indicates no external power, believe it.
return false;
// technically speaking this should work for all(?) NRF52 boards
// but needs testing across multiple devices. NRF52 USB would not even work if

View File

@@ -9,13 +9,13 @@
*/
#include "PowerFSM.h"
#include "Default.h"
#include "Led.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerMon.h"
#include "configuration.h"
#include "graphics/Screen.h"
#include "main.h"
#include "modules/StatusLEDModule.h"
#include "sleep.h"
#include "target_specific.h"
@@ -103,7 +103,7 @@ static void lsIdle()
uint32_t sleepTime = SLEEP_TIME;
powerMon->setState(meshtastic_PowerMon_State_CPU_LightSleep);
ledBlink.set(false); // Never leave led on while in light sleep
statusLEDModule->setPowerLED(false);
esp_sleep_source_t wakeCause2 = doLightSleep(sleepTime * 1000LL);
powerMon->clearState(meshtastic_PowerMon_State_CPU_LightSleep);
@@ -111,7 +111,7 @@ static void lsIdle()
case ESP_SLEEP_WAKEUP_TIMER:
// Normal case: timer expired, we should just go back to sleep ASAP
ledBlink.set(true); // briefly turn on led
statusLEDModule->setPowerLED(true);
wakeCause2 = doLightSleep(100); // leave led on for 1ms
secsSlept += sleepTime;
@@ -146,7 +146,7 @@ static void lsIdle()
}
} else {
// Time to stop sleeping!
ledBlink.set(false);
statusLEDModule->setPowerLED(false);
LOG_INFO("Reached ls_secs, service loop()");
powerFSM.trigger(EVENT_WAKE_TIMER);
}

View File

@@ -274,9 +274,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define TCA9535_ADDR 0x20
#define TCA9555_ADDR 0x26
// used for display brightness control
#define STC8H1K28_ADDR 0x30
// -----------------------------------------------------------------------------
// Touchscreen
// -----------------------------------------------------------------------------

View File

@@ -63,7 +63,6 @@ class ScanI2C
NAU7802,
FT6336U,
STK8BAXX,
STC8H1K28,
ICM20948,
SCD4X,
MAX30102,

View File

@@ -243,8 +243,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize)
#endif
#ifdef HAS_LP5562
SCAN_SIMPLE_CASE(LP5562_ADDR, LP5562, "LP5562", (uint8_t)addr.address);
#else
SCAN_SIMPLE_CASE(STC8H1K28_ADDR, LP5562, "STC8H1K28", (uint8_t)addr.address);
#endif
case XPOWERS_AXP192_AXP2101_ADDRESS:
// Do we have the axp2101/192 or the TCA8418

View File

@@ -221,7 +221,6 @@ void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *ti
if (rtc_sec > 0) {
// === Build Time String ===
long hms = (rtc_sec % SEC_PER_DAY + SEC_PER_DAY) % SEC_PER_DAY;
int hour, minute, second;
graphics::decomposeTime(rtc_sec, hour, minute, second);
snprintf(timeStr, sizeof(timeStr), "%d:%02d", hour, minute);

View File

@@ -877,15 +877,15 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Send Message (Right side)
display->drawRect(x1 + 2 - bubbleW, y1 - bubbleH, bubbleW, bubbleH);
// Top Right Corner
display->drawRect(x1, topY, 2, 1);
display->drawRect(x1 - 1, topY, 2, 1);
display->drawRect(x1, topY, 1, 2);
// Bottom Right Corner
display->drawRect(x1 - 1, bottomY - 2, 2, 1);
display->drawRect(x1, bottomY - 3, 1, 2);
// Knock the corners off to make a bubble
display->setColor(BLACK);
display->drawRect(x1 - bubbleW, topY - 1, 1, 1);
display->drawRect(x1 - bubbleW, bottomY - 1, 1, 1);
display->drawRect(x1 - bubbleW + 2, topY - 1, 1, 1);
display->drawRect(x1 - bubbleW + 2, bottomY - 1, 1, 1);
display->setColor(WHITE);
} else {
// Received Message (Left Side)

View File

@@ -1,3 +1,5 @@
#include "graphics/niche/InkHUD/Tile.h"
#include <cstdint>
#ifdef MESHTASTIC_INCLUDE_INKHUD
#include "./Applet.h"
@@ -785,6 +787,16 @@ void InkHUD::Applet::drawHeader(std::string text)
drawPixel(x, 0, BLACK);
drawPixel(x, headerDivY, BLACK); // Dotted 50%
}
// Dither near battery
if (settings->optionalFeatures.batteryIcon) {
constexpr uint16_t ditherSizePx = 4;
Tile *batteryTile = ((Applet *)inkhud->getSystemApplet("BatteryIcon"))->getTile();
const uint16_t batteryTileLeft = batteryTile->getLeft();
const uint16_t batteryTileTop = batteryTile->getTop();
const uint16_t batteryTileHeight = batteryTile->getHeight();
hatchRegion(batteryTileLeft - ditherSizePx, batteryTileTop, ditherSizePx, batteryTileHeight, 2, WHITE);
}
}
// Get the height of the standard applet header

View File

@@ -48,37 +48,27 @@ int InkHUD::BatteryIconApplet::onPowerStatusUpdate(const meshtastic::Status *sta
void InkHUD::BatteryIconApplet::onRender(bool full)
{
// Fill entire tile
// - size of icon controlled by size of tile
int16_t l = 0;
int16_t t = 0;
uint16_t w = width();
int16_t h = height();
// Clear the region beneath the tile
// Clear the region beneath the tile, including the border
// Most applets are drawing onto an empty frame buffer and don't need to do this
// We do need to do this with the battery though, as it is an "overlay"
fillRect(l, t, w, h, WHITE);
// Vertical centerline
const int16_t m = t + (h / 2);
fillRect(0, 0, width(), height(), WHITE);
// =====================
// Draw battery outline
// =====================
// Positive terminal "bump"
const int16_t &bumpL = l;
const uint16_t bumpH = h / 2;
const int16_t bumpT = m - (bumpH / 2);
constexpr uint16_t bumpW = 2;
const int16_t &bumpL = 1;
const uint16_t bumpH = (height() - 2) / 2;
const int16_t bumpT = (1 + ((height() - 2) / 2)) - (bumpH / 2);
fillRect(bumpL, bumpT, bumpW, bumpH, BLACK);
// Main body of battery
const int16_t bodyL = bumpL + bumpW;
const int16_t &bodyT = t;
const int16_t &bodyH = h;
const int16_t bodyW = w - bumpW;
const int16_t bodyL = 1 + bumpW;
const int16_t &bodyT = 1;
const int16_t &bodyH = height() - 2; // Handle top/bottom padding
const int16_t bodyW = (width() - 1) - bumpW; // Handle 1px left pad
drawRect(bodyL, bodyT, bodyW, bodyH, BLACK);
// Erase join between bump and body
@@ -89,12 +79,13 @@ void InkHUD::BatteryIconApplet::onRender(bool full)
// ===================
constexpr int16_t slicePad = 2;
const int16_t sliceL = bodyL + slicePad;
int16_t sliceL = bodyL + slicePad;
const int16_t sliceT = bodyT + slicePad;
const uint16_t sliceH = bodyH - (slicePad * 2);
uint16_t sliceW = bodyW - (slicePad * 2);
sliceW = (sliceW * socRounded) / 100; // Apply percentage
sliceW = (sliceW * socRounded) / 100; // Apply percentage
sliceL += ((bodyW - (slicePad * 2)) - sliceW); // Shift slice to the battery's negative terminal, correcting drain direction
hatchRegion(sliceL, sliceT, sliceW, sliceH, 2, BLACK);
drawRect(sliceL, sliceT, sliceW, sliceH, BLACK);

View File

@@ -510,10 +510,10 @@ void InkHUD::WindowManager::placeSystemTiles()
const uint16_t batteryIconWidth = batteryIconHeight * 1.8;
inkhud->getSystemApplet("BatteryIcon")
->getTile()
->setRegion(inkhud->width() - batteryIconWidth, // x
2, // y
batteryIconWidth, // width
batteryIconHeight); // height
->setRegion(inkhud->width() - batteryIconWidth - 1, // x
1, // y
batteryIconWidth + 1, // width
batteryIconHeight + 2); // height
// Note: the tiles of placeholder and menu applets are manipulated specially
// - menuApplet borrows user tiles

View File

@@ -7,13 +7,13 @@
#include "NodeDB.h"
#include "PowerFSM.h"
#include "PowerMon.h"
#include "RadioLibInterface.h"
#include "ReliableRouter.h"
#include "airtime.h"
#include "buzz.h"
#include "power/PowerHAL.h"
#include "FSCommon.h"
#include "Led.h"
#include "RTC.h"
#include "SPILock.h"
#include "Throttle.h"
@@ -193,6 +193,8 @@ bool kb_found = false;
// global bool to record that on-screen keyboard (OSK) is present
bool osk_found = false;
unsigned long last_listen = 0;
// The I2C address of the RTC Module (if found)
ScanI2C::DeviceAddress rtc_found = ScanI2C::ADDRESS_NONE;
// The I2C address of the Accelerometer (if found)
@@ -242,26 +244,8 @@ const char *getDeviceName()
return name;
}
// TODO remove from main.cpp
static int32_t ledBlinker()
{
// Still set up the blinking (heartbeat) interval but skip code path below, so LED will blink if
// config.device.led_heartbeat_disabled is changed
if (config.device.led_heartbeat_disabled)
return 1000;
static bool ledOn;
ledOn ^= 1;
ledBlink.set(ledOn);
// have a very sparse duty cycle of LED being on, unless charging, then blink 0.5Hz square wave rate to indicate that
return powerStatus->getIsCharging() ? 1000 : (ledOn ? 1 : 1000);
}
uint32_t timeLastPowered = 0;
static Periodic *ledPeriodic;
static OSThread *powerFSMthread;
static OSThread *ambientLightingThread;
@@ -299,21 +283,16 @@ void earlyInitVariant() {}
// blink user led in 3 flashes sequence to indicate what is happening
void waitUntilPowerLevelSafe()
{
#ifdef LED_PIN
pinMode(LED_PIN, OUTPUT);
#endif
while (powerHAL_isPowerLevelSafe() == false) {
#ifdef LED_PIN
#ifdef LED_POWER
// 3x: blink for 300 ms, pause for 300 ms
for (int i = 0; i < 3; i++) {
digitalWrite(LED_PIN, LED_STATE_ON);
digitalWrite(LED_POWER, LED_STATE_ON);
delay(300);
digitalWrite(LED_PIN, LED_STATE_OFF);
digitalWrite(LED_POWER, LED_STATE_OFF);
delay(300);
}
#endif
@@ -337,6 +316,11 @@ void setup()
// initialize power HAL layer as early as possible
powerHAL_init();
#ifdef LED_POWER
pinMode(LED_POWER, OUTPUT);
digitalWrite(LED_POWER, LED_STATE_ON);
#endif
// prevent booting if device is in power failure mode
// boot sequence will follow when battery level raises to safe mode
waitUntilPowerLevelSafe();
@@ -349,11 +333,6 @@ void setup()
digitalWrite(PIN_POWER_EN, HIGH);
#endif
#ifdef LED_POWER
pinMode(LED_POWER, OUTPUT);
digitalWrite(LED_POWER, LED_STATE_ON);
#endif
#ifdef LED_NOTIFICATION
pinMode(LED_NOTIFICATION, OUTPUT);
digitalWrite(LED_NOTIFICATION, HIGH ^ LED_STATE_ON);
@@ -366,11 +345,7 @@ void setup()
#ifdef BLE_LED
pinMode(BLE_LED, OUTPUT);
#ifdef BLE_LED_INVERTED
digitalWrite(BLE_LED, HIGH);
#else
digitalWrite(BLE_LED, LOW);
#endif
digitalWrite(BLE_LED, LED_STATE_OFF);
#endif
concurrency::hasBeenSetup = true;
@@ -488,14 +463,6 @@ void setup()
OSThread::setup();
// TODO make this ifdef based on defined pins and move from main.cpp
#if defined(ELECROW_ThinkNode_M1) || defined(ELECROW_ThinkNode_M2)
// The ThinkNodes have their own blink logic
// ledPeriodic = new Periodic("Blink", elecrowLedBlinker);
#else
ledPeriodic = new Periodic("Blink", ledBlinker);
#endif
fsInit();
#if !MESHTASTIC_EXCLUDE_I2C
@@ -720,13 +687,6 @@ void setup()
setupSDCard();
#endif
// LED init
#ifdef LED_PIN
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LED_STATE_ON); // turn on for now
#endif
// Hello
printInfo();
#ifdef BUILD_EPOCH
@@ -834,7 +794,7 @@ void setup()
SPI.begin();
#endif
#else
// ESP32
// ESP32
#if defined(HW_SPI1_DEVICE)
SPI1.begin(LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
LOG_DEBUG("SPI1.begin(SCK=%d, MISO=%d, MOSI=%d, NSS=%d)", LORA_SCK, LORA_MISO, LORA_MOSI, LORA_CS);
@@ -960,12 +920,6 @@ void setup()
setupNicheGraphics();
#endif
#ifdef LED_PIN
// Turn LED off after boot, if heartbeat by config
if (config.device.led_heartbeat_disabled)
digitalWrite(LED_PIN, HIGH ^ LED_STATE_ON);
#endif
// Do this after service.init (because that clears error_code)
#ifdef HAS_PMU
if (!pmu_found)
@@ -1168,6 +1122,12 @@ void loop()
#endif
power->powerCommandsCheck();
if (RadioLibInterface::instance != nullptr && !Throttle::isWithinTimespanMs(last_listen, 1000 * 60) &&
!(RadioLibInterface::instance->isSending() || RadioLibInterface::instance->isActivelyReceiving())) {
RadioLibInterface::instance->startReceive();
LOG_DEBUG("attempting AGC reset");
}
#ifdef DEBUG_STACK
static uint32_t lastPrint = 0;
if (!Throttle::isWithinTimespanMs(lastPrint, 10 * 1000L)) {

View File

@@ -33,6 +33,7 @@ extern ScanI2C::DeviceAddress cardkb_found;
extern uint8_t kb_model;
extern bool kb_found;
extern bool osk_found;
extern unsigned long last_listen;
extern ScanI2C::DeviceAddress rtc_found;
extern ScanI2C::DeviceAddress accelerometer_found;
extern ScanI2C::FoundDevice rgb_found;

View File

@@ -1404,6 +1404,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
}
@@ -1544,6 +1553,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);
@@ -2213,8 +2223,8 @@ bool NodeDB::restorePreferences(meshtastic_AdminMessage_BackupLocation location,
} else if (location == meshtastic_AdminMessage_BackupLocation_SD) {
// TODO: After more mainline SD card support
}
return success;
#endif
return success;
}
/// Record an error that should be reported via analytics

View File

@@ -514,6 +514,8 @@ void RadioLibInterface::handleReceiveInterrupt()
void RadioLibInterface::startReceive()
{
// Note the updated timestamp, to avoid unneeded AGC resets
last_listen = millis();
isReceiving = true;
powerMon->setState(meshtastic_PowerMon_State_Lora_RXOn);
}

View File

@@ -9,7 +9,6 @@
#if HAS_WIFI
#include "mesh/wifi/WiFiAPClient.h"
#endif
#include "Led.h"
#include "SPILock.h"
#include "power.h"
#include "serialization/JSON.h"
@@ -92,7 +91,6 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload);
ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks);
ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED);
ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport);
ResourceNode *nodeJsonNodes = new ResourceNode("/json/nodes", "GET", &handleNodes);
ResourceNode *nodeJsonFsBrowseStatic = new ResourceNode("/json/fs/browse/static", "GET", &handleFsBrowseStatic);
@@ -110,7 +108,6 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
secureServer->registerNode(nodeRestart);
secureServer->registerNode(nodeFormUpload);
secureServer->registerNode(nodeJsonScanNetworks);
secureServer->registerNode(nodeJsonBlinkLED);
secureServer->registerNode(nodeJsonFsBrowseStatic);
secureServer->registerNode(nodeJsonDelete);
secureServer->registerNode(nodeJsonReport);
@@ -133,7 +130,6 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer)
insecureServer->registerNode(nodeRestart);
insecureServer->registerNode(nodeFormUpload);
insecureServer->registerNode(nodeJsonScanNetworks);
insecureServer->registerNode(nodeJsonBlinkLED);
insecureServer->registerNode(nodeJsonFsBrowseStatic);
insecureServer->registerNode(nodeJsonDelete);
insecureServer->registerNode(nodeJsonReport);
@@ -904,45 +900,6 @@ void handleRestart(HTTPRequest *req, HTTPResponse *res)
webServerThread->requestRestart = (millis() / 1000) + 5;
}
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "application/json");
res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "POST");
ResourceParameters *params = req->getParams();
std::string blink_target;
if (!params->getQueryParameter("blink_target", blink_target)) {
// if no blink_target was supplied in the URL parameters of the
// POST request, then assume we should blink the LED
blink_target = "LED";
}
if (blink_target == "LED") {
uint8_t count = 10;
while (count > 0) {
ledBlink.set(true);
delay(50);
ledBlink.set(false);
delay(50);
count = count - 1;
}
} else {
#if HAS_SCREEN
if (screen)
screen->blink();
#endif
}
JSONObject jsonObjOuter;
jsonObjOuter["status"] = new JSONValue("ok");
JSONValue *value = new JSONValue(jsonObjOuter);
std::string jsonString = value->Stringify();
res->print(jsonString.c_str());
delete value;
}
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
{
res->setHeader("Content-Type", "application/json");

View File

@@ -11,7 +11,6 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res);
void handleScanNetworks(HTTPRequest *req, HTTPResponse *res);
void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res);
void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res);
void handleBlinkLED(HTTPRequest *req, HTTPResponse *res);
void handleReport(HTTPRequest *req, HTTPResponse *res);
void handleNodes(HTTPRequest *req, HTTPResponse *res);
void handleUpdateFs(HTTPRequest *req, HTTPResponse *res);

View File

@@ -643,12 +643,6 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
accelerometerThread->enabled = true;
accelerometerThread->start();
}
#endif
#ifdef LED_PIN
// Turn LED off if heartbeat by config
if (c.payload_variant.device.led_heartbeat_disabled) {
digitalWrite(LED_PIN, HIGH ^ LED_STATE_ON);
}
#endif
if (config.device.button_gpio == c.payload_variant.device.button_gpio &&
config.device.buzzer_gpio == c.payload_variant.device.buzzer_gpio &&
@@ -905,10 +899,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 +995,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 +1181,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

@@ -1,9 +1,12 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
#include "buzz/BuzzerFeedbackThread.h"
#include "modules/StatusLEDModule.h"
#include "modules/SystemCommandsModule.h"
#endif
#include "modules/StatusLEDModule.h"
#if !MESHTASTIC_EXCLUDE_REPLYBOT
#include "ReplyBotModule.h"
#endif
#if !MESHTASTIC_EXCLUDE_PKI
#include "KeyVerificationModule.h"
#endif
@@ -90,6 +93,9 @@
#if !MESHTASTIC_EXCLUDE_DROPZONE
#include "modules/DropzoneModule.h"
#endif
#if !MESHTASTIC_EXCLUDE_STATUS
#include "modules/StatusMessageModule.h"
#endif
#if defined(HAS_HARDWARE_WATCHDOG)
#include "watchdog/watchdogThread.h"
@@ -106,10 +112,10 @@ void setupModules()
buzzerFeedbackThread = new BuzzerFeedbackThread();
}
#endif
#if defined(LED_CHARGE) || defined(LED_PAIRING)
statusLEDModule = new StatusLEDModule();
#if !MESHTASTIC_EXCLUDE_REPLYBOT
new ReplyBotModule();
#endif
#if !MESHTASTIC_EXCLUDE_ADMIN
adminModule = new AdminModule();
#endif
@@ -150,6 +156,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

View File

@@ -1,5 +1,4 @@
#include "PowerStressModule.h"
#include "Led.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "PowerMon.h"
@@ -78,10 +77,12 @@ int32_t PowerStressModule::runOnce()
switch (p.cmd) {
case meshtastic_PowerStressMessage_Opcode_LED_ON:
ledForceOn.set(true);
// FIXME - implement
// ledForceOn.set(true);
break;
case meshtastic_PowerStressMessage_Opcode_LED_OFF:
ledForceOn.set(false);
// FIXME - implement
// ledForceOn.set(false);
break;
case meshtastic_PowerStressMessage_Opcode_GPS_ON:
// FIXME - implement

View File

@@ -0,0 +1,183 @@
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_REPLYBOT
/*
* ReplyBotModule.cpp
*
* This module implements a simple reply bot for the Meshtastic firmware. It listens for
* specific text commands ("/ping", "/hello" and "/test") delivered either via a direct
* message (DM) or a broadcast on the primary channel. When a supported command is
* received the bot responds with a short status message that includes the hop count
* (minimum number of relays), RSSI and SNR of the received packet. To avoid spamming
* the network it enforces a persender cooldown between responses. By default the
* module is enabled; define MESHTASTIC_EXCLUDE_REPLYBOT at build time to exclude it
* entirely. See the official firmware documentation for guidance on adding modules.
*/
#include "Channels.h"
#include "MeshService.h"
#include "NodeDB.h"
#include "ReplyBotModule.h"
#include "mesh/MeshTypes.h"
#include <Arduino.h>
#include <cctype>
#include <cstring>
//
// Rate limiting data structures
//
// Each sender is tracked in a small ring buffer. When a message arrives from a
// sender we check the last time we responded to them. If the difference is
// less than the configured cooldown (different values for DM vs broadcast)
// the message is ignored; otherwise we update the last response time and
// proceed with replying.
struct ReplyBotCooldownEntry {
uint32_t from = 0;
uint32_t lastMs = 0;
};
static constexpr uint8_t REPLYBOT_COOLDOWN_SLOTS = 8; // ring buffer size
static constexpr uint32_t REPLYBOT_DM_COOLDOWN_MS = 15 * 1000; // 15 seconds for DMs
static constexpr uint32_t REPLYBOT_LF_COOLDOWN_MS = 60 * 1000; // 60 seconds for LongFast broadcasts
static ReplyBotCooldownEntry replybotCooldown[REPLYBOT_COOLDOWN_SLOTS];
static uint8_t replybotCooldownIdx = 0;
// Return true if a reply should be ratelimited for this sender, updating the
// entry table as needed.
static bool replybotRateLimited(uint32_t from, uint32_t cooldownMs)
{
const uint32_t now = millis();
for (auto &e : replybotCooldown) {
if (e.from == from) {
// Found existing entry; check if cooldown expired
if ((uint32_t)(now - e.lastMs) < cooldownMs) {
return true;
}
e.lastMs = now;
return false;
}
}
// No entry found insert new sender into the ring
replybotCooldown[replybotCooldownIdx].from = from;
replybotCooldown[replybotCooldownIdx].lastMs = now;
replybotCooldownIdx = (replybotCooldownIdx + 1) % REPLYBOT_COOLDOWN_SLOTS;
return false;
}
// Constructor registers a single text port and marks the module promiscuous
// so that broadcast messages on the primary channel are visible.
ReplyBotModule::ReplyBotModule() : SinglePortModule("replybot", meshtastic_PortNum_TEXT_MESSAGE_APP)
{
isPromiscuous = true;
}
void ReplyBotModule::setup()
{
// In future we may add a protobuf configuration; for now the module is
// always enabled when compiled in.
}
// Determine whether we want to process this packet. We only care about
// plain text messages addressed to our port.
bool ReplyBotModule::wantPacket(const meshtastic_MeshPacket *p)
{
return (p && p->decoded.portnum == ourPortNum);
}
ProcessMessage ReplyBotModule::handleReceived(const meshtastic_MeshPacket &mp)
{
// Accept only direct messages to us or broadcasts on the Primary channel
// (regardless of modem preset: LongFast, MediumFast, etc).
const uint32_t ourNode = nodeDB->getNodeNum();
const bool isDM = (mp.to == ourNode);
const bool isPrimaryChannel = (mp.channel == channels.getPrimaryIndex()) && isBroadcast(mp.to);
if (!isDM && !isPrimaryChannel) {
return ProcessMessage::CONTINUE;
}
// Ignore empty payloads
if (mp.decoded.payload.size == 0) {
return ProcessMessage::CONTINUE;
}
// Copy payload into a nullterminated buffer
char buf[260];
memset(buf, 0, sizeof(buf));
size_t n = mp.decoded.payload.size;
if (n > sizeof(buf) - 1)
n = sizeof(buf) - 1;
memcpy(buf, mp.decoded.payload.bytes, n);
// React only to supported slash commands
if (!isCommand(buf)) {
return ProcessMessage::CONTINUE;
}
// Apply rate limiting per sender depending on DM/broadcast
const uint32_t cooldownMs = isDM ? REPLYBOT_DM_COOLDOWN_MS : REPLYBOT_LF_COOLDOWN_MS;
if (replybotRateLimited(mp.from, cooldownMs)) {
return ProcessMessage::CONTINUE;
}
// Compute hop count indicator if the relay_node is nonzero we know
// there was at least one relay. Some firmware builds support a hop_start
// field which could be used for more accurate counts, but here we use
// the available relay_node flag only.
// int hopsAway = mp.hop_start - mp.hop_limit;
int hopsAway = getHopsAway(mp);
// Normalize RSSI: if positive adjust down by 200 to align with typical values
int rssi = mp.rx_rssi;
if (rssi > 0) {
rssi -= 200;
}
float snr = mp.rx_snr;
// Build the reply message and send it back via DM
char reply[96];
snprintf(reply, sizeof(reply), "🎙️ Mic Check : %d Hops away | RSSI %d | SNR %.1f", hopsAway, rssi, snr);
sendDm(mp, reply);
return ProcessMessage::CONTINUE;
}
// Check if the message starts with one of the supported commands. Leading
// whitespace is skipped and commands must be followed by endofstring or
// whitespace.
bool ReplyBotModule::isCommand(const char *msg) const
{
if (!msg)
return false;
while (*msg == ' ' || *msg == '\t')
msg++;
auto isEndOrSpace = [](char c) { return c == '\0' || std::isspace(static_cast<unsigned char>(c)); };
if (strncmp(msg, "/ping", 5) == 0 && isEndOrSpace(msg[5]))
return true;
if (strncmp(msg, "/hello", 6) == 0 && isEndOrSpace(msg[6]))
return true;
if (strncmp(msg, "/test", 5) == 0 && isEndOrSpace(msg[5]))
return true;
return false;
}
// Send a direct message back to the originating node.
void ReplyBotModule::sendDm(const meshtastic_MeshPacket &rx, const char *text)
{
if (!text)
return;
meshtastic_MeshPacket *p = allocDataPacket();
p->to = rx.from;
p->channel = rx.channel;
p->want_ack = false;
p->decoded.want_response = false;
size_t len = strlen(text);
if (len > sizeof(p->decoded.payload.bytes)) {
len = sizeof(p->decoded.payload.bytes);
}
p->decoded.payload.size = len;
memcpy(p->decoded.payload.bytes, text, len);
service->sendToMesh(p);
}
#endif // MESHTASTIC_EXCLUDE_REPLYBOT

View File

@@ -0,0 +1,19 @@
#pragma once
#include "configuration.h"
#if !MESHTASTIC_EXCLUDE_REPLYBOT
#include "SinglePortModule.h"
#include "mesh/generated/meshtastic/mesh.pb.h"
class ReplyBotModule : public SinglePortModule
{
public:
ReplyBotModule();
void setup() override;
bool wantPacket(const meshtastic_MeshPacket *p) override;
ProcessMessage handleReceived(const meshtastic_MeshPacket &mp) override;
protected:
bool isCommand(const char *msg) const;
void sendDm(const meshtastic_MeshPacket &rx, const char *text);
};
#endif // MESHTASTIC_EXCLUDE_REPLYBOT

View File

@@ -13,8 +13,10 @@ StatusLEDModule::StatusLEDModule() : concurrency::OSThread("StatusLEDModule")
{
bluetoothStatusObserver.observe(&bluetoothStatus->onNewStatus);
powerStatusObserver.observe(&powerStatus->onNewStatus);
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
if (inputBroker)
inputObserver.observe(inputBroker);
#endif
}
int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
@@ -62,19 +64,22 @@ int StatusLEDModule::handleStatusUpdate(const meshtastic::Status *arg)
}
return 0;
};
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
int StatusLEDModule::handleInputEvent(const InputEvent *event)
{
lastUserbuttonTime = millis();
return 0;
}
#endif
int32_t StatusLEDModule::runOnce()
{
my_interval = 1000;
if (power_state == charging) {
#ifndef POWER_LED_HARDWARE_BLINKS_WHILE_CHARGING
CHARGE_LED_state = !CHARGE_LED_state;
#endif
} else if (power_state == charged) {
CHARGE_LED_state = LED_STATE_ON;
} else if (power_state == critical) {
@@ -94,7 +99,15 @@ int32_t StatusLEDModule::runOnce()
}
} else {
CHARGE_LED_state = LED_STATE_OFF;
if (doing_fast_blink) {
CHARGE_LED_state = LED_STATE_OFF;
doing_fast_blink = false;
my_interval = 999;
} else {
CHARGE_LED_state = LED_STATE_ON;
doing_fast_blink = true;
my_interval = 1;
}
}
if (!config.bluetooth.enabled || PAIRING_LED_starttime + 30 * 1000 < millis() || doing_fast_blink) {
@@ -112,6 +125,11 @@ int32_t StatusLEDModule::runOnce()
PAIRING_LED_state = LED_STATE_ON;
}
// Override if disabled in config
if (config.device.led_heartbeat_disabled) {
CHARGE_LED_state = LED_STATE_OFF;
}
#ifdef Battery_LED_1
bool chargeIndicatorLED1 = LED_STATE_OFF;
bool chargeIndicatorLED2 = LED_STATE_OFF;
bool chargeIndicatorLED3 = LED_STATE_OFF;
@@ -126,9 +144,23 @@ int32_t StatusLEDModule::runOnce()
if (powerStatus && powerStatus->getBatteryChargePercent() >= 75)
chargeIndicatorLED4 = LED_STATE_ON;
}
#endif
#ifdef LED_CHARGE
digitalWrite(LED_CHARGE, CHARGE_LED_state);
#if defined(HAS_PMU)
if (pmu_found && PMU) {
// blink the axp led
PMU->setChargingLedMode(CHARGE_LED_state ? XPOWERS_CHG_LED_ON : XPOWERS_CHG_LED_OFF);
}
#endif
#ifdef PCA_LED_POWER
io.digitalWrite(PCA_LED_POWER, CHARGE_LED_state);
#endif
#ifdef PCA_LED_ENABLE
io.digitalWrite(PCA_LED_ENABLE, CHARGE_LED_state);
#endif
#ifdef LED_POWER
digitalWrite(LED_POWER, CHARGE_LED_state);
#endif
#ifdef LED_PAIRING
digitalWrite(LED_PAIRING, PAIRING_LED_state);
@@ -149,3 +181,43 @@ int32_t StatusLEDModule::runOnce()
return (my_interval);
}
void StatusLEDModule::setPowerLED(bool LEDon)
{
#if defined(HAS_PMU)
if (pmu_found && PMU) {
// blink the axp led
PMU->setChargingLedMode(LEDon ? XPOWERS_CHG_LED_ON : XPOWERS_CHG_LED_OFF);
}
#endif
if (LEDon)
LEDon = LED_STATE_ON;
else
LEDon = LED_STATE_OFF;
#ifdef PCA_LED_POWER
io.digitalWrite(PCA_LED_POWER, LEDon);
#endif
#ifdef PCA_LED_ENABLE
io.digitalWrite(PCA_LED_ENABLE, LEDon);
#endif
#ifdef LED_POWER
digitalWrite(LED_POWER, LEDon);
#endif
#ifdef LED_PAIRING
digitalWrite(LED_PAIRING, LEDon);
#endif
#ifdef Battery_LED_1
digitalWrite(Battery_LED_1, LEDon);
#endif
#ifdef Battery_LED_2
digitalWrite(Battery_LED_2, LEDon);
#endif
#ifdef Battery_LED_3
digitalWrite(Battery_LED_3, LEDon);
#endif
#ifdef Battery_LED_4
digitalWrite(Battery_LED_4, LEDon);
#endif
}

View File

@@ -5,10 +5,14 @@
#include "PowerStatus.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
#include "input/InputBroker.h"
#include "main.h"
#include <Arduino.h>
#include <functional>
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
#include "input/InputBroker.h"
#endif
class StatusLEDModule : private concurrency::OSThread
{
bool slowTrack = false;
@@ -17,8 +21,11 @@ class StatusLEDModule : private concurrency::OSThread
StatusLEDModule();
int handleStatusUpdate(const meshtastic::Status *);
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
int handleInputEvent(const InputEvent *arg);
#endif
void setPowerLED(bool);
protected:
unsigned int my_interval = 1000; // interval in millisconds
@@ -28,8 +35,10 @@ class StatusLEDModule : private concurrency::OSThread
CallbackObserver<StatusLEDModule, const meshtastic::Status *>(this, &StatusLEDModule::handleStatusUpdate);
CallbackObserver<StatusLEDModule, const meshtastic::Status *> powerStatusObserver =
CallbackObserver<StatusLEDModule, const meshtastic::Status *>(this, &StatusLEDModule::handleStatusUpdate);
#if !MESHTASTIC_EXCLUDE_INPUTBROKER
CallbackObserver<StatusLEDModule, const InputEvent *> inputObserver =
CallbackObserver<StatusLEDModule, const InputEvent *>(this, &StatusLEDModule::handleInputEvent);
#endif
private:
bool CHARGE_LED_state = LED_STATE_OFF;

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

@@ -757,11 +757,7 @@ void NimbleBluetooth::deinit()
isDeInit = true;
#ifdef BLE_LED
#ifdef BLE_LED_INVERTED
digitalWrite(BLE_LED, HIGH);
#else
digitalWrite(BLE_LED, LOW);
#endif
digitalWrite(BLE_LED, LED_STATE_OFF);
#endif
#ifndef NIMBLE_TWO
NimBLEDevice::deinit();

View File

@@ -158,7 +158,7 @@
#endif
#ifdef PIN_LED1
#define LED_PIN PIN_LED1 // LED1 on nrf52840-DK
#define LED_POWER PIN_LED1 // LED1 on nrf52840-DK
#endif
#ifdef PIN_BUTTON1

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

@@ -5,7 +5,6 @@
#endif
#include "Default.h"
#include "Led.h"
#include "MeshRadio.h"
#include "MeshService.h"
#include "NodeDB.h"
@@ -13,6 +12,7 @@
#include "detect/LoRaRadioType.h"
#include "error.h"
#include "main.h"
#include "modules/StatusLEDModule.h"
#include "sleep.h"
#include "target_specific.h"
@@ -268,8 +268,7 @@ void doDeepSleep(uint32_t msecToWake, bool skipPreflight = false, bool skipSaveN
digitalWrite(PIN_WD_EN, LOW);
#endif
#endif
ledBlink.set(false);
statusLEDModule->setPowerLED(false);
#ifdef RESET_OLED
digitalWrite(RESET_OLED, 1); // put the display in reset before killing its power
#endif

View File

@@ -14,7 +14,7 @@
#define LORA_CS 5
#define RF95_FAN_EN 17
// #define LED_PIN 16 // This is a LED_WS2812 not a standard LED
// This is a LED_WS2812 not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 16 // gpio pin used to send data to the neopixels

View File

@@ -20,7 +20,7 @@
#define LORA_DIO2
#define LORA_DIO3
#define LED_PIN 16 // green - blue is at 17
#define LED_POWER 16 // green - blue is at 17
#define BUTTON_PIN 25
#define BUTTON_NEED_PULLUP

View File

@@ -23,8 +23,6 @@
#define SX126X_TXEN RADIOLIB_NC
#define SX126X_RXEN RADIOLIB_NC
// Status
// #define LED_PIN 1
// External notification
// FIXME: Check if EXT_NOTIFY_OUT actualy has any effect and removes the need for setting the external notication pin in the
// app/preferences

View File

@@ -21,8 +21,8 @@
#define BUTTON_PIN 15 // Right side button - if not available, set device.button_gpio to 0 from Meshtastic client
// LEDs
#define LED_PIN 13 // Tx LED
#define USER_LED 2 // Rx LED
#define LED_POWER 13 // Tx LED
#define USER_LED 2 // Rx LED
// Buzzer
#define PIN_BUZZER 33

View File

@@ -15,7 +15,7 @@
#define ADC_MULTIPLIER 1.85 // (R1 = 470k, R2 = 680k)
#define EXT_PWR_DETECT 4 // Pin to detect connected external power source for LILYGO® TTGO T-Energy T18 and other DIY boards
#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Module (#975).
#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets)
#define LED_POWER 2 // add status LED (compatible with core-pcb and DIY targets)
// Radio
#define USE_SX1262 // E22-900M30S uses SX1262

View File

@@ -15,7 +15,7 @@
#define ADC_MULTIPLIER 1.85 // (R1 = 470k, R2 = 680k)
#define EXT_PWR_DETECT 4 // Pin to detect connected external power source for LILYGO® TTGO T-Energy T18 and other DIY boards
#define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Module (#975).
#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets)
#define LED_POWER 2 // add status LED (compatible with core-pcb and DIY targets)
#define LORA_DIO0 26 // a No connect on the SX1262/SX1268 module
#define LORA_RESET 23 // RST for SX1276, and for SX1262/SX1268

View File

@@ -3,7 +3,7 @@
// HACKBOX LoRa IO Kit
// Uses a ESP-32-WROOM and a RA-01SH (SX1262) LoRa Board
#define LED_PIN 2 // LED
#define LED_POWER 2 // LED
#define LED_STATE_ON 1 // State when LED is lit
#define HAS_SCREEN 0

View File

@@ -12,7 +12,7 @@
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define LED_PIN 25 // If defined we will blink this LED
#define LED_POWER 25 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define USE_RF95

View File

@@ -18,7 +18,7 @@
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define LED_POWER 25 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define USE_RF95

View File

@@ -13,7 +13,7 @@
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define LED_POWER 25 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define USE_RF95

View File

@@ -15,7 +15,7 @@
#undef GPS_TX_PIN
// Green / Lora = PIN 22 / GPIO2, Yellow / Wifi = PIN 23 / GPIO0, Blue / BLE = PIN 25 / GPIO16
#define LED_PIN 22
#define LED_POWER 22
#define WIFI_LED 23
#define BLE_LED 25

View File

@@ -1,7 +1,7 @@
#define I2C_SCL SCL
#define I2C_SDA SDA
#define LED_PIN LED
#define LED_POWER LED
// active low, powers the Battery reader, but no lora antenna boost (?)
// #define VEXT_ENABLE Vext

View File

@@ -11,7 +11,7 @@
// Green LED
#define LED_STATE_ON 1 // State when LED is lit
#define LED_PIN 10
#define LED_POWER 10
// PCF8563 RTC Module
#define PCF8563_RTC 0x51

View File

@@ -37,7 +37,7 @@
/*
LED PIN setup.
*/
#define LED_PIN 15
#define LED_POWER 15
/*
Five way button when using ADC.

View File

@@ -43,7 +43,7 @@ static const uint8_t SCK = 33;
#undef GPS_TX_PIN
#define GPS_TX_PIN (TX1)
#define LED_PIN LED_BLUE
#define LED_POWER LED_BLUE
#define PIN_VBAT WB_A0
#define BATTERY_PIN PIN_VBAT

View File

@@ -9,7 +9,7 @@
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Module.
#define LED_STATE_ON 0 // State when LED is lit
#define LED_PIN 4 // Newer tbeams (1.1) have an extra led on GPIO4
#define LED_POWER 4 // Newer tbeams (1.1) have an extra led on GPIO4
// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
// not found then probe for SX1262
@@ -49,7 +49,7 @@
#undef EXT_NOTIFY_OUT
#undef LED_STATE_ON
#undef LED_PIN
#undef LED_POWER
#define HAS_CST226SE 1
#define HAS_TOUCHSCREEN 1

View File

@@ -5,7 +5,7 @@
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define VEXT_ON_VALUE LOW
#define LED_PIN 2 // If defined we will blink this LED
#define LED_POWER 2 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define BUTTON_NEED_PULLUP
#define EXT_NOTIFY_OUT 13 // Default pin to use for Ext Notify Module.

View File

@@ -7,7 +7,7 @@
#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define LED_POWER 25 // If defined we will blink this LED
#define BUTTON_PIN 36
#define BUTTON_NEED_PULLUP

View File

@@ -5,7 +5,7 @@
#define I2C_SCL 22
#define VEXT_ENABLE 21 // active low, powers the oled display and the lora antenna boost
#define LED_PIN 25 // If defined we will blink this LED
#define LED_POWER 25 // If defined we will blink this LED
#define BUTTON_PIN \
0 // If defined, this will be used for user button presses, if your board doesn't have a physical switch, you can wire one
// between this pin and ground

View File

@@ -22,4 +22,4 @@ build_flags =
${env:tlora-v2-1-1_6.build_flags}
-DBUTTON_PIN=0
-DPIN_BUZZER=25
-DLED_PIN=-1
-DLED_POWER=-1

View File

@@ -8,10 +8,10 @@
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
#if defined(LED_PIN) && LED_PIN == -1
#undef LED_PIN
#if defined(LED_POWER) && LED_POWER == -1
#undef LED_POWER
#else
#define LED_PIN 25 // If defined we will blink this LED
#define LED_POWER 25 // If defined we will blink this LED
#endif
#define USE_RF95

View File

@@ -7,4 +7,5 @@ build_flags =
-D TLORA_V2_1_16
-I variants/esp32/tlora_v2_1_16
-D LORA_TCXO_GPIO=33
upload_speed = 115200
-ULED_BUILTIN
upload_speed = 115200

View File

@@ -6,7 +6,7 @@
#define I2C_SDA 21 // I2C pins for this board
#define I2C_SCL 22
#define LED_PIN 25 // If defined we will blink this LED
#define LED_POWER 25 // If defined we will blink this LED
#define BUTTON_PIN 12 // If defined, this will be used for user button presses,
#define BUTTON_NEED_PULLUP

View File

@@ -8,7 +8,7 @@
#define GPS_RX_PIN 9
#define GPS_TX_PIN 10
#define LED_PIN 13 // 13 red, 2 blue, 15 red
#define LED_POWER 13 // 13 red, 2 blue, 15 red
#define BUTTON_PIN 0
#define BUTTON_NEED_PULLUP

View File

@@ -26,7 +26,6 @@
#undef GPS_TX_PIN
#define NO_GPS 1
#define HAS_GPS 0
#define NO_SCREEN
#define HAS_SCREEN 0
// Default SPI1 will be mapped to the display

View File

@@ -4,7 +4,7 @@
#define I2C_SCL SCL
#define BUTTON_PIN 9 // BOOT button
#define LED_PIN 30 // RGB LED
#define LED_POWER 30 // RGB LED
#define USE_RF95
#define LORA_SCK 4

View File

@@ -3,7 +3,7 @@
// Hackerboxes LoRa ESP32-C3 OLED Kit
// Uses a ESP32-C3 OLED Board and a RA-01SH (SX1262) LoRa Board
#define LED_PIN 8 // LED
#define LED_POWER 8 // LED
#define LED_STATE_ON 1 // State when LED is lit
#define HAS_SCREEN 0

View File

@@ -3,7 +3,7 @@
// LED pin on HT-DEV-ESP_V2 and HT-DEV-ESP_V3
// https://resource.heltec.cn/download/HT-CT62/HT-CT62_Reference_Design.pdf
// https://resource.heltec.cn/download/HT-DEV-ESP/HT-DEV-ESP_V3_Sch.pdf
#define LED_PIN 2 // LED
#define LED_POWER 2 // LED
#define LED_STATE_ON 1 // State when LED is lit
#define HAS_SCREEN 0

View File

@@ -1,7 +1,7 @@
#define I2C_SDA 8 // I2C pins for this board
#define I2C_SCL 9
#define LED_PIN 7 // If defined we will blink this LED
#define LED_POWER 7 // If defined we will blink this LED
#define LED_STATE_ON 0 // State when LED is lit
#define USE_SX1262

View File

@@ -1,7 +1,7 @@
#define I2C_SDA 34 // I2C pins for this board
#define I2C_SCL 36
#define LED_PIN 15 // If defined we will blink this LED
#define LED_POWER 15 // If defined we will blink this LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 3 // How many neopixels are connected

View File

@@ -1,7 +1,7 @@
// EByte EoRA-Hub
// Uses E80 (LR1121) LoRa module
#define LED_PIN 35
#define LED_POWER 35
// Button - user interface
#define BUTTON_PIN 0 // BOOT button

View File

@@ -1,5 +1,5 @@
// LED - status indication
#define LED_PIN 37
#define LED_POWER 37
// Button - user interface
#define BUTTON_PIN 0 // This is the BOOT button, and it has its own pull-up resistor

View File

@@ -100,7 +100,7 @@
*/
// Status
#define LED_PIN 1
#define LED_POWER 1
#define LED_STATE_ON 1 // State when LED is lit
// External notification
// FIXME: Check if EXT_NOTIFY_OUT actualy has any effect and removes the need for setting the external notication pin in the

View File

@@ -1,5 +1,5 @@
// Status
#define LED_PIN 1
#define LED_POWER 1
#define PIN_BUTTON1 47 // 功能键
#define PIN_BUTTON2 4 // 电源键

View File

@@ -8,5 +8,11 @@ void earlyInitVariant()
Wire.begin(48, 47);
io.pinMode(PCA_PIN_EINK_EN, OUTPUT);
io.pinMode(PCA_PIN_POWER_EN, OUTPUT);
io.pinMode(PCA_LED_POWER, OUTPUT);
io.pinMode(PCA_LED_USER, OUTPUT);
io.pinMode(PCA_LED_ENABLE, OUTPUT);
io.digitalWrite(PCA_PIN_POWER_EN, HIGH);
io.digitalWrite(PCA_LED_USER, LOW);
io.digitalWrite(PCA_LED_ENABLE, LOW);
}

View File

@@ -8,8 +8,10 @@
// LED
// Both of these are on the GPIO expander
#define PCA_LED_USER 1 // the Blue LED
#define PCA_LED_POWER 3 // the Red LED? Seems to have hardware logic to blink when USB is plugged in.
#define PCA_LED_USER 1 // the Blue LED
#define PCA_LED_ENABLE 2 // the power supply to the LEDs, in an OR arrangement with VBUS power
#define PCA_LED_POWER 3 // the Red LED? Seems to have hardware logic to blink when USB is plugged in.
#define POWER_LED_HARDWARE_BLINKS_WHILE_CHARGING
// USB_CHECK
#define EXT_PWR_DETECT 12

View File

@@ -11,7 +11,7 @@
#define I2C_SDA 12
#define I2C_SCL 14
#define LED_PIN 46
#define LED_POWER 46
#define LED_STATE_ON 0 // State when LED is litted
// #define BUTTON_PIN 15 // Pico OLED 1.3 User key 0 - removed User key 1 (17)

View File

@@ -26,7 +26,7 @@
// #define GPS_RX_PIN 44
// #define GPS_TX_PIN 43
#define LED_PIN 41
#define LED_POWER 41
#define BUTTON_PIN 2
#define BUTTON_NEED_PULLUP

View File

@@ -11,7 +11,7 @@
#define I2C_SDA 18 // 1 // I2C pins for this board
#define I2C_SCL 17 // 2
// #define LED_PIN 38 // This is a RGB LED not a standard LED
// #define LED_POWER 38 // This is a RGB LED not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels

View File

@@ -11,7 +11,7 @@
#define I2C_SDA 18 // 1 // I2C pins for this board
#define I2C_SCL 17 // 2
// #define LED_PIN 38 // This is a RGB LED not a standard LED
// #define LED_POWER 38 // This is a RGB LED not a standard LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected
#define NEOPIXEL_DATA 38 // gpio pin used to send data to the neopixels

View File

@@ -6,7 +6,7 @@
#define I2C_SDA1 45
#define I2C_SCL1 46
#define LED_PIN 6
#define LED_POWER 6
#define LED_STATE_ON 1
#define BUTTON_PIN 0

View File

@@ -164,6 +164,3 @@ build_flags =
${crowpanel_large_esp32s3_base.build_flags}
-D VIEW_320x240
-D DISPLAY_SIZE=800x480 ; landscape mode
build_src_filter =
${esp32s3_base.build_src_filter}
+<../variants/esp32s3/elecrow_panel>

View File

@@ -1,21 +0,0 @@
// meshtastic/firmware/variants/elecrow_panel/variant.cpp
#include "variant.h"
#include "Arduino.h"
#include "Wire.h"
bool elecrow_v2 = false; // false = v1, true = v2
extern "C" {
void initVariant()
{
Wire.begin(I2C_SDA, I2C_SCL, 100000);
delay(50);
Wire.beginTransmission(0x30);
if (Wire.endTransmission() == 0) {
elecrow_v2 = true;
}
Wire.end();
}
}

View File

@@ -1,8 +1,6 @@
#define I2C_SDA 15
#define I2C_SCL 16
extern bool elecrow_v2; // false = v1, true = v2
#if CROW_SELECT == 1
#define WAKE_ON_TOUCH
#define SCREEN_TOUCH_INT 47
@@ -19,7 +17,7 @@ extern bool elecrow_v2; // false = v1, true = v2
#define DAC_I2S_DOUT 12
#define DAC_I2S_MCLK 8 // don't use GPIO0 because it's assigned to LoRa or button
#else
#define PIN_BUZZER (elecrow_v2 ? 0 : 8)
#define PIN_BUZZER 8
#endif
// GPS via UART1 connector
@@ -74,7 +72,7 @@ extern bool elecrow_v2; // false = v1, true = v2
#define SENSOR_POWER_ON LOW
#else
// 4.3", 5.0", 7.0"
#define LORA_CS (elecrow_v2 ? 8 : 0)
#define LORA_CS 0
#define LORA_SCK 5
#define LORA_MISO 4
#define LORA_MOSI 6

View File

@@ -8,7 +8,6 @@
#define EXT_NOTIFY_OUT 22
#define BUTTON_PIN 0 // 17
// #define LED_PIN PIN_LED
// Board has RGB LED 21
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 1 // How many neopixels are connected

View File

@@ -1,5 +1,5 @@
#define LED_PIN 33
#define LED_PIN2 34
#define LED_POWER 33
#define LED_POWER2 34
#define EXT_PWR_DETECT 35
#define BUTTON_PIN 18

View File

@@ -1,4 +1,4 @@
#define LED_PIN LED
#define LED_POWER LED
#define USE_SSD1306 // Heltec_v3 has a SSD1306 display

View File

@@ -26,7 +26,7 @@ build_flags =
${heltec_v4_base.build_flags}
-D HELTEC_V4_OLED
-D USE_SSD1306 ; Heltec_v4 has an SSD1315 display (compatible with SSD1306 driver)
-D LED_PIN=35
-D LED_POWER=35
-D RESET_OLED=21
-D I2C_SDA=17
-D I2C_SCL=18

View File

@@ -1,4 +1,4 @@
#define LED_PIN 45 // LED is not populated on earliest board variant
#define LED_POWER 45 // LED is not populated on earliest board variant
#define BUTTON_PIN 0
#define PIN_BUTTON2 21 // Second built-in button
#define ALT_BUTTON_PIN PIN_BUTTON2 // Send the up event

View File

@@ -1,4 +1,4 @@
#define LED_PIN 45 // LED is not populated on earliest board variant
#define LED_POWER 45 // LED is not populated on earliest board variant
#define BUTTON_PIN 0
#define PIN_BUTTON2 21 // Second built-in button
#define ALT_BUTTON_PIN PIN_BUTTON2 // Send the up event

View File

@@ -1,4 +1,4 @@
#define LED_PIN 18
#define LED_POWER 18
#define BUTTON_PIN 0
// I2C

View File

@@ -1,4 +1,4 @@
#define LED_PIN 18
#define LED_POWER 18
#define BUTTON_PIN 0
// I2C

View File

@@ -1,4 +1,4 @@
#define LED_PIN 18
#define LED_POWER 18
#define _VARIANT_HELTEC_WIRELESS_TRACKER
#define HELTEC_TRACKER_V1_X

View File

@@ -1,4 +1,4 @@
#define LED_PIN 18
#define LED_POWER 18
#define HELTEC_TRACKER_V1_X

View File

@@ -1,4 +1,4 @@
#define LED_PIN 18
#define LED_POWER 18
#define _VARIANT_HELTEC_WIRELESS_TRACKER

View File

@@ -1,7 +1,7 @@
#define I2C_SCL SCL
#define I2C_SDA SDA
#define LED_PIN LED
#define LED_POWER LED
#define VEXT_ENABLE Vext // active low, powers the oled display and the lora antenna boost
#define VEXT_ON_VALUE LOW

View File

@@ -13,7 +13,7 @@
#define ADC_CHANNEL ADC1_GPIO4_CHANNEL
// LED
#define LED_PIN 21
#define LED_POWER 21
// Button
#define BUTTON_PIN 0

View File

@@ -1,7 +1,7 @@
#define I2C_SDA 11 // I2C pins for this board
#define I2C_SCL 10
#define LED_PIN 1 // If defined we will blink this LED
#define LED_POWER 1 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses
#define BUTTON_NEED_PULLUP

View File

@@ -4,7 +4,7 @@
#define USE_SSD1306
#define DISPLAY_FLIP_SCREEN
#define LED_PIN 15 // If defined we will blink this LED
#define LED_POWER 15 // If defined we will blink this LED
#define HAS_NEOPIXEL // Enable the use of neopixels
#define NEOPIXEL_COUNT 3 // How many neopixels are connected

View File

@@ -24,7 +24,7 @@
#define PIN_LED1 LED_GREEN
#define LED_NOTIFICATION LED_BLUE
#define LED_PIN LED_GREEN
#define LED_POWER LED_GREEN
#define ledOff(pin) pinMode(pin, INPUT)
#define LED_STATE_ON 1 // State when LED is litted

View File

@@ -32,7 +32,7 @@
#define PIN_LED1 LED_GREEN
#define LED_NOTIFICATION LED_BLUE
#define LED_PIN LED_GREEN
#define LED_POWER LED_GREEN
#define ledOff(pin) pinMode(pin, INPUT)
#define LED_STATE_ON 1 // State when LED is litted

View File

@@ -30,7 +30,7 @@ Expansion Board Infomation : https://www.seeedstudio.com/Seeeduino-XIAO-Expansio
L76K GPS Module Information : https://www.seeedstudio.com/L76K-GNSS-Module-for-Seeed-Studio-XIAO-p-5864.html
*/
#define LED_PIN 48
#define LED_POWER 48
#define LED_STATE_ON 1 // State when LED is lit
#define BUTTON_PIN 21 // This is the Program Button

View File

@@ -67,7 +67,7 @@
#endif
// LED
#define LED_PIN 18
#define LED_POWER 18
#define LED_STATE_ON 1 // HIGH = ON
// Battery ADC

View File

@@ -12,7 +12,7 @@
#define HAS_SCREEN 1 // Allow for OLED Screens on I2C Header of shield
#define LED_PIN 38 // If defined we will blink this LED
#define LED_POWER 38 // If defined we will blink this LED
#define BUTTON_PIN 0 // If defined, this will be used for user button presses,
#define BUTTON_NEED_PULLUP

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