diff --git a/CONTEXT.md b/CONTEXT.md index 8318b4c..65e3324 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -61,7 +61,7 @@ A Wi-Fi network the device may join on its own (name, password). When several ar _Avoid_: profile, known network **IRC Service**: -The Service that keeps the IRC connection alive in the background once the IRC App has started it, until the user disconnects. It reconnects after drops, and pauses while the Wi-Fi Service is Monitoring. It does not start by itself after a reboot. +The Service that keeps the IRC connection alive in the background once the IRC App has started it, until the user stops it (`/quit`, or `irc stop` on the console). Once stopped by hand, opening the App again doesn't reconnect; typing a line does. It reconnects after drops, and pauses while the Wi-Fi Service is Monitoring. It does not start by itself after a reboot. _Avoid_: IRC client (that's the App) **Buffer**: diff --git a/README.md b/README.md index a952dd6..81c7ebd 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ To install from the SD card instead, copy the `.ota` file from `.pio/build/cardp | `sd list` | Lists the files of each Storage Clean-up category | | `cat ` | Prints the first ~1.2 KB of a file on the SD card | | `irc start` | Starts the IRC Service (normally done by opening the IRC App) | +| `irc stop` | Stops it, as `/quit` does: QUIT if connected, no more retries, and the App stays disconnected until you type | | `irc say ` | Types into a Buffer, commands included (`irc say 0 /join #test`) | | `irc dump` | Prints IRC status, memory, and the last lines of each Buffer | | `wifi status` | Prints Wi-Fi state, network, signal, clock and free heap | diff --git a/docs/milestones/OTA.md b/docs/milestones/OTA.md index 1031a89..d2e0651 100644 --- a/docs/milestones/OTA.md +++ b/docs/milestones/OTA.md @@ -8,7 +8,7 @@ |---|---| | Q52 | Two sources: **push over Wi-Fi** from the PC, and **from the SD card**. Pulling from Gitea releases is deferred. | | Q53 | **Signed Update Files** (ECDSA P-256 over SHA-256). The private key stays in `~/.config/roro9stack/`, and the firmware embeds the public key (ADR 0003). | -| Q54 | The device **always listens** for pushes on the LAN while Wi-Fi is Connected, announced as `roro9stack-.local`. | +| Q54 | The device **always listens** for pushes on the LAN while Wi-Fi is Connected. *Revised in M2:* it was announced over mDNS as `roro9stack-.local`; mDNS was removed to save RAM (it never crossed the dev box's routed network anyway). Pushes go to the IP shown in Settings → Firmware. | | Q55 | New firmware runs on **Probation**. It's confirmed once booted, UI drawn, Services started, 30 s without a crash, and Wi-Fi connected (if configured). Otherwise **Rollback**. A Toast reports either outcome. | | Q56 | **Downgrades are allowed**, with "older than the installed version" shown. | | Q57 | A valid push **installs right away**: progress screen, then reboot. The reboot waits for Text Entry to end, 60 s at most. | diff --git a/scripts/ota_push.py b/scripts/ota_push.py index 8ebc7f2..c2846dd 100755 --- a/scripts/ota_push.py +++ b/scripts/ota_push.py @@ -2,7 +2,7 @@ """Pushes a signed Update File to a Cardputer over Wi-Fi (TCP 3232) and reports the result. Usage: scripts/ota_push.py - is the device's IP (shown in Settings > About), or its name when mDNS works on your network. + is the device's IP (shown in Settings > Firmware). """ import socket import sys diff --git a/src/apps/firmware_page.cpp b/src/apps/firmware_page.cpp index 5b4fa22..ead3b64 100644 --- a/src/apps/firmware_page.cpp +++ b/src/apps/firmware_page.cpp @@ -78,7 +78,6 @@ void FirmwarePage::draw(Canvas& c) { case kVersion: return "Version"; case kStatus: return "Status"; case kAddress: return "Push to"; - case kName: return "Name"; case kSdHeader: return listed ? (found.empty() ? "No .ota files in /updates" : "On the SD card:") : "Looking on the SD card..."; default: return " " + found[i - kFixed].substr(std::string(kUpdatesFolder).size() + 1); } @@ -88,7 +87,6 @@ void FirmwarePage::draw(Canvas& c) { case kVersion: return versionString(); case kStatus: return update_.onProbation() ? "on probation" : "confirmed"; case kAddress: return ip.empty() ? "Wi-Fi not connected" : ip + ":" + std::to_string(UpdateService::kPort); - case kName: return update_.hostname() + ".local"; case kSdHeader: return ""; default: return "install >"; } diff --git a/src/apps/firmware_page.h b/src/apps/firmware_page.h index b13af51..e59b05d 100644 --- a/src/apps/firmware_page.h +++ b/src/apps/firmware_page.h @@ -28,7 +28,7 @@ class FirmwarePage { void draw(Canvas& c); private: - enum Row { kVersion, kStatus, kAddress, kName, kSdHeader, kFixed }; + enum Row { kVersion, kStatus, kAddress, kSdHeader, kFixed }; std::vector files(); diff --git a/src/apps/irc_app.cpp b/src/apps/irc_app.cpp index cff1930..6635c10 100644 --- a/src/apps/irc_app.cpp +++ b/src/apps/irc_app.cpp @@ -42,7 +42,7 @@ std::string lowered(std::string s) { void IrcApp::onEnter() { page_ = Page::Chat; editing_ = false; - irc_.connect(); + if (!irc_.stoppedByUser()) irc_.connect(); // stopped by hand: stay stopped, typing reconnects view(current_); } diff --git a/src/main.cpp b/src/main.cpp index 0143b9f..9d0324f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -347,7 +347,7 @@ static const char* const kHelp = "coredump erase forget the core dump in flash\n" "key press a key: up down left right select back home del tab, or one character\n" "wifi status | wifi add \n" - "irc start | irc dump | irc say \n" + "irc start | irc stop | irc dump | irc say \n" "ls [folder] | rm | install (Update from SD)\n" "sd list | cat | log | burst | sound on|off | short | normal\n" #ifdef RORO_DEBUG @@ -463,6 +463,7 @@ static void runCommand(String line) { listingWanted = true; } if (line == "irc start") irc->connect(); + if (line == "irc stop") irc->disconnect(); if (line.startsWith("irc say ")) { // irc say String rest = line.substring(8); int space = rest.indexOf(' '); diff --git a/src/services/irc_service.cpp b/src/services/irc_service.cpp index b0dfcda..63733dd 100644 --- a/src/services/irc_service.cpp +++ b/src/services/irc_service.cpp @@ -37,12 +37,19 @@ void IrcService::start() { } void IrcService::connect() { + stoppedByUser_ = false; if (wanted_) return; retryAtMs_ = millis(); backoff_.reset(); wanted_ = true; } +void IrcService::disconnect() { + stoppedByUser_ = true; + stopRequested_ = true; // the IRC task says QUIT and closes; nothing to do if it never started + if (!task_) wanted_ = false; +} + int IrcService::totalUnread() { Lock l(lock_); return session_->totalUnread(); @@ -176,13 +183,10 @@ void IrcService::flushEffects() { status_ = Status::Online; backoff_.reset(); } - if (quit && open_) { - delay(300); // let QUIT reach the server - close(""); - wanted_ = false; - status_ = Status::Stopped; - Lock l(lock_); - session_->disconnected(clock_.utcNow(), "disconnected"); + if (quit) { // /quit: QUIT is already on its way if connected; stop in any state + stoppedByUser_ = true; + stopRequested_ = true; + quitSent_ = true; } } @@ -192,6 +196,19 @@ void IrcService::loop() { bool wifiUp = wifi_.state() == WifiController::State::Connected; bool monitoring = wifi_.state() == WifiController::State::Monitoring; + if (stopRequested_) { + stopRequested_ = false; + if (open_) { + if (!quitSent_) conn_->print("QUIT :roro9stack\r\n"); + vTaskDelay(pdMS_TO_TICKS(300)); // let QUIT reach the server + close(""); + } + quitSent_ = false; + wanted_ = false; + status_ = Status::Stopped; + Lock l(lock_); + session_->disconnected(clock_.utcNow(), "disconnected (Enter reconnects)"); + } if (restart_) { restart_ = false; if (open_) { diff --git a/src/services/irc_service.h b/src/services/irc_service.h index 5db3e79..733f650 100644 --- a/src/services/irc_service.h +++ b/src/services/irc_service.h @@ -31,9 +31,12 @@ class IrcService : public Service { const char* name() const override { return "irc"; } void start() override; - // Starts the session (the IRC App does this when opened); /quit stops it. + // Starts the session (the IRC App does this when opened, unless you stopped it). void connect(); + // Stops it, from any state: says QUIT if connected, and stops retrying. /quit, `irc stop`. + void disconnect(); bool running() const { return wanted_; } + bool stoppedByUser() const { return stoppedByUser_; } Status status() const { return status_; } // Read or act on the session while holding its lock: withSession([](IrcSession& s) { ... }). @@ -78,6 +81,9 @@ class IrcService : public Service { ReconnectPolicy backoff_; std::string partial_; volatile bool wanted_ = false; + volatile bool stoppedByUser_ = false; // a manual stop: opening the App doesn't reconnect + volatile bool stopRequested_ = false; + bool quitSent_ = false; // /quit already queued its QUIT volatile bool restart_ = false; volatile Status status_ = Status::Stopped; bool open_ = false; diff --git a/src/services/update_service.cpp b/src/services/update_service.cpp index 1b3e9ee..f6be3ba 100644 --- a/src/services/update_service.cpp +++ b/src/services/update_service.cpp @@ -1,13 +1,11 @@ #include "update_service.h" -#include #include #include #include #include -#include "platform/identity.h" #include "platform/ota_device.h" #include "platform/system_info.h" #include "probation.h" @@ -66,7 +64,6 @@ class FileSource : public UpdateSource { UpdateService::UpdateService(KeyValueStore& store, WifiService& wifi, SavedNetworks& saved, StorageService& storage, EventBus& bus, const Settings& settings) : store_(store), wifi_(wifi), saved_(saved), storage_(storage), bus_(bus), settings_(settings) { - hostname_ = "roro9stack-" + identity::defaultShortName(); } void UpdateService::notify(const std::string& text, NotificationLevel level) { @@ -196,11 +193,9 @@ void UpdateService::listen() { bool connected = wifi_.state() == WifiController::State::Connected; if (connected && !listening) { server.begin(); - if (MDNS.begin(hostname_.c_str())) MDNS.addService("roro9stack", "tcp", kPort); listening = true; } else if (!connected && listening) { server.end(); - MDNS.end(); listening = false; } // The main loop restarts into an installed update when it's safe. If it never does (stuck, diff --git a/src/services/update_service.h b/src/services/update_service.h index eab80fa..066b77c 100644 --- a/src/services/update_service.h +++ b/src/services/update_service.h @@ -35,7 +35,6 @@ class UpdateService : public Service { int percent() const { return percent_; } std::string incomingVersion() const; bool onProbation() const { return probation_; } - const std::string& hostname() const { return hostname_; } // Installs an Update File from the SD card (runs on the storage task). void installFromSd(const std::string& path); @@ -58,7 +57,6 @@ class UpdateService : public Service { EventBus& bus_; const Settings& settings_; TaskHandle_t task_ = nullptr; - std::string hostname_; volatile Phase phase_ = Phase::Idle; volatile int percent_ = 0; std::string incoming_;