Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c183050
Add heltec -v4-r8 board
Quency-D May 15, 2026
1ac5f35
Added touch reset
Quency-D May 16, 2026
e5a3839
Optimize ADC readout
Quency-D May 27, 2026
8ed7be9
Merge pull request #11 from meshcore-dev/dev
Quency-D May 27, 2026
341aa5e
Merge pull request #14 from meshcore-dev/dev
Quency-D Jun 26, 2026
2efb3af
repeater: poweroff on long press
fdlamotte Jul 3, 2026
369016a
introduce shutdownPeripherals in NRF52Board to prepare for shutdown
fdlamotte Jul 7, 2026
10d2d2a
Merge pull request #16 from meshcore-dev/dev
Quency-D Jul 8, 2026
17d68e3
Add heltec rc32 board
Quency-D Jul 8, 2026
6c9f090
Merge pull request #17 from meshcore-dev/dev
Quency-D Jul 15, 2026
05d4bd2
Add a rotary encoder
Quency-D Jul 15, 2026
3469e92
Enable patch reception
Quency-D Jul 16, 2026
a472cd7
Delete duplicate pin definitions
Quency-D Jul 16, 2026
61a8821
Optimize battery voltage reading
Quency-D Jul 16, 2026
41f4d6b
Merge pull request #2560 from Quency-D/heltec-v4-r8
ripplebiz Jul 17, 2026
b26f53a
Avoid waking display from rotary input
Quency-D Jul 17, 2026
fd7b35f
Move the rotation input to target.cpp
Quency-D Jul 17, 2026
3eb5451
Merge pull request #2906 from fdlamotte/shutdown_peripherals
fdlamotte Jul 17, 2026
76c6e73
Merge branch 'dev' into repeater_btn
fdlamotte Jul 17, 2026
3a67685
Merge pull request #2883 from fdlamotte/repeater_btn
fdlamotte Jul 17, 2026
84d1e24
nrf52_variants: override shutdownPeripherals instead of powerOff for …
fdlamotte Jul 17, 2026
8f5a393
Merge pull request #2975 from fdlamotte/nrf52_boards--use-shutdownPer…
fdlamotte Jul 17, 2026
c644720
uitask: screen and radio poweroff moved to board
fdlamotte Jul 17, 2026
4aec46b
Merge pull request #2976 from fdlamotte/UITask_poweroff_radio_display
fdlamotte Jul 17, 2026
795989b
Merge pull request #2966 from Quency-D/heltec-rc32
ripplebiz Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions boards/heltec-rc32.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_16MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"psram_type": "opi",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "heltec_rc32"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "Heltec RC32 (16 MB FLASH, 8 MB PSRAM)",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://heltec.org/",
"vendor": "Heltec"
}
43 changes: 43 additions & 0 deletions boards/heltec_v4_r8.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_16MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"-DBOARD_HAS_PSRAM",
"-DARDUINO_USB_CDC_ON_BOOT=1",
"-DARDUINO_USB_MODE=1",
"-DARDUINO_RUNNING_CORE=1",
"-DARDUINO_EVENT_RUNNING_CORE=1"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"psram_type": "opi",
"hwids": [["0x303A", "0x1001"]],
"mcu": "esp32s3",
"variant": "heltec_v4_r8"
},
"connectivity": ["wifi", "bluetooth", "lora"],
"debug": {
"default_tool": "esp-builtin",
"onboard_tools": ["esp-builtin"],
"openocd_target": "esp32s3.cfg"
},
"frameworks": ["arduino", "espidf"],
"name": "heltec_wifi_lora_32 v4 r8 (16 MB FLASH, 8 MB PSRAM)",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"use_1200bps_touch": true,
"wait_for_upload_port": true,
"require_upload_port": true,
"speed": 921600
},
"url": "https://heltec.org/",
"vendor": "heltec"
}
13 changes: 10 additions & 3 deletions examples/companion_radio/ui-new/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -697,9 +697,6 @@ void UITask::shutdown(bool restart){
if (restart) {
_board->reboot();
} else {
// still necessary until all boards are refactored to use poweroff
_display->turnOff();
radio_driver.powerOff();
// Power off board including radio, display, GPS and components
_board->powerOff();
}
Expand Down Expand Up @@ -750,6 +747,16 @@ void UITask::loop() {
c = handleTripleClick(KEY_SELECT);
}
#endif
#if defined(UI_HAS_ROTARY_INPUT)
RotaryInputEvent rotaryEv = rotary_input.poll();
if (c == 0 && _display != NULL && _display->isOn()) {
if (rotaryEv == RotaryInputEvent::Next) {
c = KEY_NEXT;
} else if (rotaryEv == RotaryInputEvent::Prev) {
c = KEY_PREV;
}
}
#endif
#if defined(PIN_USER_BTN_ANA)
if (abs(millis() - _analogue_pin_read_millis) > 10) {
int ev = analog_btn.check();
Expand Down
2 changes: 0 additions & 2 deletions examples/companion_radio/ui-orig/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,6 @@ void UITask::shutdown(bool restart){
if (restart) {
_board->reboot();
} else {
_display->turnOff();
radio_driver.powerOff();
// Power off board including radio, display, GPS and components
_board->powerOff();
}
Expand Down
2 changes: 0 additions & 2 deletions examples/companion_radio/ui-tiny/UITask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,6 @@ void UITask::shutdown(bool restart){
if (restart) {
_board->reboot();
} else {
_display->turnOff();
radio_driver.powerOff();
// Power off board including radio, display, GPS and components
_board->powerOff();
}
Expand Down
77 changes: 51 additions & 26 deletions examples/simple_repeater/UITask.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "UITask.h"
#include "target.h"
#include <Arduino.h>
#include <helpers/CommonCLI.h>

Expand All @@ -9,6 +10,8 @@
#define AUTO_OFF_MILLIS 20000 // 20 seconds
#define BOOT_SCREEN_MILLIS 4000 // 4 seconds

#define POWEROFF_DELAY 3000

// 'meshcore', 128x13px
static const uint8_t meshcore_logo [] PROGMEM = {
0x3c, 0x01, 0xe3, 0xff, 0xc7, 0xff, 0x8f, 0x03, 0x87, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe,
Expand All @@ -29,9 +32,14 @@ static const uint8_t meshcore_logo [] PROGMEM = {
void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* firmware_version) {
_prevBtnState = HIGH;
_auto_off = millis() + AUTO_OFF_MILLIS;
_started_at = millis();
_node_prefs = node_prefs;
_display->turnOn();

#if defined(PIN_USER_BTN) && defined(DISPLAY_CLASS)
user_btn.begin();
#endif

// strip off dash and commit hash by changing dash to null terminator
// e.g: v1.2.3-abcdef -> v1.2.3
char *version = strdup(firmware_version);
Expand All @@ -47,7 +55,7 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi

void UITask::renderCurrScreen() {
char tmp[80];
if (millis() < BOOT_SCREEN_MILLIS) { // boot screen
if (millis() < _started_at + BOOT_SCREEN_MILLIS) { // boot screen
// meshcore logo
_display->setColor(DisplayDriver::BLUE);
int logoWidth = 128;
Expand All @@ -57,24 +65,34 @@ void UITask::renderCurrScreen() {
const char* website = "https://meshcore.io";
_display->setColor(DisplayDriver::LIGHT);
_display->setTextSize(1);
uint16_t websiteWidth = _display->getTextWidth(website);
_display->setCursor((_display->width() - websiteWidth) / 2, 22);
_display->print(website);
_display->drawTextCentered(_display->width() / 2, 22, website);

// version info
_display->setColor(DisplayDriver::LIGHT);
_display->setTextSize(1);
uint16_t versionWidth = _display->getTextWidth(_version_info);
_display->setCursor((_display->width() - versionWidth) / 2, 35);
_display->print(_version_info);
_display->drawTextCentered(_display->width() / 2, 35, _version_info);

// node type
const char* node_type = "< Repeater >";
uint16_t typeWidth = _display->getTextWidth(node_type);
_display->setCursor((_display->width() - typeWidth) / 2, 48);
_display->print(node_type);
} else { // home screen
// node name
_display->drawTextCentered(_display->width() / 2, 48, node_type);
} else if (_powering_off_at > 0) {
// meshcore logo
_display->setColor(DisplayDriver::BLUE);
int logoWidth = 128;
_display->drawXbm((_display->width() - logoWidth) / 2, 3, meshcore_logo, logoWidth, 13);

// meshcore website
const char* website = "https://meshcore.io";
_display->setColor(DisplayDriver::LIGHT);
_display->setTextSize(1);
_display->drawTextCentered(_display->width()/ 2, 22, website);

// Powering off
const char* poweroff_string = "Turning OFF";
uint16_t poffWidth = _display->getTextWidth(poweroff_string);
_display->setCursor((_display->width() - poffWidth) / 2, 48);
_display->drawTextCentered(_display->width()/2, 48, poweroff_string);
} else {
_display->setCursor(0, 0);
_display->setTextSize(1);
_display->setColor(DisplayDriver::GREEN);
Expand All @@ -94,21 +112,19 @@ void UITask::renderCurrScreen() {
}

void UITask::loop() {
#ifdef PIN_USER_BTN
if (millis() >= _next_read) {
int btnState = digitalRead(PIN_USER_BTN);
if (btnState != _prevBtnState) {
if (btnState == USER_BTN_PRESSED) { // pressed?
if (_display->isOn()) {
// TODO: any action ?
} else {
_display->turnOn();
}
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
}
_prevBtnState = btnState;
#if defined(PIN_USER_BTN) && defined(DISPLAY_CLASS)
int ev = user_btn.check();
if (ev == BUTTON_EVENT_CLICK) {
if (_display->isOn()) {
// TODO: any action ?
} else {
_display->turnOn();
}
_next_read = millis() + 200; // 5 reads per second
_auto_off = millis() + AUTO_OFF_MILLIS; // extend auto-off timer
} else if (ev == BUTTON_EVENT_LONG_PRESS) {
_display->turnOn();
Serial.println("Powering Off");
_powering_off_at = millis() + POWEROFF_DELAY;
}
#endif

Expand All @@ -124,4 +140,13 @@ void UITask::loop() {
_display->turnOff();
}
}

if (_powering_off_at > 0) { // power off timer armed
#ifdef LED_PIN
digitalWrite(LED_PIN, LED_STATE_ON); // switch on the led until poweroff
#endif
if (millis() > _powering_off_at) {
_board->powerOff(); // should not return
}
}
}
5 changes: 4 additions & 1 deletion examples/simple_repeater/UITask.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
#include <helpers/CommonCLI.h>

class UITask {
mesh::MainBoard* _board;
DisplayDriver* _display;
unsigned long _next_read, _next_refresh, _auto_off;
int _prevBtnState;
NodePrefs* _node_prefs;
char _version_info[32];
unsigned long _powering_off_at = 0;
unsigned long _started_at = 0;

void renderCurrScreen();
public:
UITask(DisplayDriver& display) : _display(&display) { _next_read = _next_refresh = 0; }
UITask(mesh::MainBoard& board, DisplayDriver& display) : _board(&board), _display(&display) { _next_read = _next_refresh = 0; }
void begin(NodePrefs* node_prefs, const char* build_date, const char* firmware_version);

void loop();
Expand Down
4 changes: 2 additions & 2 deletions examples/simple_repeater/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#ifdef DISPLAY_CLASS
#include "UITask.h"
static UITask ui_task(display);
static UITask ui_task(board, display);
#endif

#ifdef ETHERNET_ENABLED
Expand Down Expand Up @@ -170,7 +170,7 @@ void loop() {
}
#endif

#if defined(PIN_USER_BTN) && defined(_SEEED_SENSECAP_SOLAR_H_)
#if defined(PIN_USER_BTN) && defined(_SEEED_SENSECAP_SOLAR_H_) && !defined(DISPLAY_CLASS)
// Hold the user button to power off the SenseCAP Solar repeater.
int btnState = digitalRead(PIN_USER_BTN);
if (btnState == LOW) {
Expand Down
6 changes: 5 additions & 1 deletion src/helpers/NRF52Board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ float NRF52Board::getMCUTemperature() {
return temp * 0.25f; // Convert to *C
}

void NRF52Board::powerOff() {
void NRF52Board::shutdownPeripherals() {
// Power off the display if any
#ifdef DISPLAY_CLASS
display.turnOff();
Expand All @@ -331,6 +331,10 @@ void NRF52Board::powerOff() {
// Flush serial buffers
Serial.flush();
delay(100);
}

void NRF52Board::powerOff() {
shutdownPeripherals();

// Enter SYSTEMOFF
uint8_t sd_enabled = 0;
Expand Down
1 change: 1 addition & 0 deletions src/helpers/NRF52Board.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class NRF52Board : public mesh::MainBoard {
virtual uint8_t getStartupReason() const override { return startup_reason; }
virtual float getMCUTemperature() override;
virtual void reboot() override { NVIC_SystemReset(); }
virtual void shutdownPeripherals();
virtual void powerOff() override;
virtual bool getBootloaderVersion(char* version, size_t max_len) override;
virtual bool startOTAUpdate(const char *id, char reply[]) override;
Expand Down
Loading
Loading