* Companion: long-press in first 8 seconds now enters CLI Rescue mode

This commit is contained in:
Scott Powell
2025-06-04 21:33:48 +10:00
parent 5d15a68d0d
commit 647d712ae8
5 changed files with 99 additions and 5 deletions

View File

@@ -728,6 +728,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
: BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables),
_serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4) {
_iter_started = false;
_cli_rescue = false;
offline_queue_len = 0;
app_target_ver = 0;
_identity_store = NULL;
@@ -1529,9 +1530,78 @@ void MyMesh::handleCmdFrame(size_t len) {
}
}
void MyMesh::loop() {
BaseChatMesh::loop();
void MyMesh::enterCLIRescue() {
_cli_rescue = true;
cli_command[0] = 0;
Serial.println("========= CLI Rescue =========");
}
bool MyMesh::formatFileSystem() {
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
return InternalFS.format();
#elif defined(RP2040_PLATFORM)
return LittleFS.format();
#elif defined(ESP32)
return SPIFFS.format();
#else
#error "need to implement file system erase"
return false;
#endif
}
void MyMesh::checkCLIRescueCmd() {
int len = strlen(cli_command);
while (Serial.available() && len < sizeof(cli_command)-1) {
char c = Serial.read();
if (c != '\n') {
cli_command[len++] = c;
cli_command[len] = 0;
}
Serial.print(c); // echo
}
if (len == sizeof(cli_command)-1) { // command buffer full
cli_command[sizeof(cli_command)-1] = '\r';
}
if (len > 0 && cli_command[len - 1] == '\r') { // received complete line
cli_command[len - 1] = 0; // replace newline with C string null terminator
if (memcmp(cli_command, "set ", 4) == 0) {
const char* config = &cli_command[4];
if (memcmp(config, "pin ", 4) == 0) {
_prefs.ble_pin = atoi(&config[4]);
savePrefs();
Serial.printf(" > pin is now %06d\n", _prefs.ble_pin);
} else {
Serial.printf(" Error: unknown config: %s\n", config);
}
} else if (strcmp(cli_command, "rebuild") == 0) {
bool success = formatFileSystem();
if (success) {
saveMainIdentity(self_id);
saveContacts();
Serial.println(" > erase and rebuild done");
} else {
Serial.println(" Error: erase failed");
}
} else if (strcmp(cli_command, "erase") == 0) {
bool success = formatFileSystem();
if (success) {
Serial.println(" > erase done");
} else {
Serial.println(" Error: erase failed");
}
} else if (strcmp(cli_command, "reboot") == 0) {
board.reboot(); // doesn't return
} else {
Serial.println(" Error: unknown command");
}
cli_command[0] = 0; // reset command buffer
}
}
void MyMesh::checkSerialInterface() {
size_t len = _serial->checkRecvFrame(cmd_frame);
if (len > 0) {
handleCmdFrame(len);
@@ -1556,6 +1626,16 @@ void MyMesh::loop() {
} else if (!_serial->isWriteBusy()) {
checkConnections();
}
}
void MyMesh::loop() {
BaseChatMesh::loop();
if (_cli_rescue) {
checkCLIRescueCmd();
} else {
checkSerialInterface();
}
// is there are pending dirty contacts write needed?
if (dirty_contacts_expiry && millisHasNowPassed(dirty_contacts_expiry)) {

View File

@@ -92,6 +92,7 @@ public:
void loop();
void handleCmdFrame(size_t len);
bool advert();
void enterCLIRescue();
protected:
float getAirtimeBudgetFactor() const override;
@@ -143,6 +144,10 @@ private:
int getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) override;
bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], int len) override;
void checkCLIRescueCmd();
void checkSerialInterface();
bool formatFileSystem();
private:
FILESYSTEM *_fs;
IdentityStore *_identity_store;
@@ -157,6 +162,8 @@ private:
uint32_t _most_recent_lastmod;
uint32_t _active_ble_pin;
bool _iter_started;
bool _cli_rescue;
char cli_command[80];
uint8_t app_target_ver;
uint8_t *sign_data;
uint32_t sign_data_len;

View File

@@ -75,6 +75,7 @@ void UITask::begin(DisplayDriver* display, NodePrefs* node_prefs) {
_userButton->onLongPress([this]() { handleButtonLongPress(); });
_userButton->onAnyPress([this]() { handleButtonAnyPress(); });
#endif
ui_started_at = millis();
}
void UITask::soundBuzzer(UIEventType bet) {
@@ -365,5 +366,9 @@ void UITask::handleButtonTriplePress() {
void UITask::handleButtonLongPress() {
MESH_DEBUG_PRINTLN("UITask: long press triggered");
shutdown();
if (millis() - ui_started_at < 8000) { // long press in first 8 seconds since startup -> CLI/rescue
the_mesh.enterCLIRescue();
} else {
shutdown();
}
}

View File

@@ -36,6 +36,7 @@ class UITask {
int _msgcount;
bool _need_refresh = true;
bool _displayWasOn = false; // Track display state before button press
unsigned long ui_started_at;
// Button handlers
#if defined(PIN_USER_BTN) || defined(PIN_USER_BTN_ANA)
@@ -57,7 +58,8 @@ class UITask {
public:
UITask(mesh::MainBoard* board) : _board(board), _display(NULL) {
_next_refresh = 0;
_next_refresh = 0;
ui_started_at = 0;
_connected = false;
}
void begin(DisplayDriver* display, NodePrefs* node_prefs);

View File

@@ -39,7 +39,7 @@ extends = Heltec_tracker_base
build_flags =
${Heltec_tracker_base.build_flags}
-I src/helpers/ui
; -D ARDUINO_USB_CDC_ON_BOOT=1 ; need for debugging
-D ARDUINO_USB_CDC_ON_BOOT=1 ; need for Serial
-D DISPLAY_ROTATION=1
-D DISPLAY_CLASS=ST7735Display
-D MAX_CONTACTS=100