#pragma once #include #include "event_bus.h" #include "saved_networks.h" #include "scan_entry.h" #include "service.h" #include "services/clock_service.h" #include "settings.h" #include "wifi_controller.h" namespace roro { // Owns the Wi-Fi radio: carries out the WifiController's decisions with the ESP32 Wi-Fi stack, // syncs the clock over NTP once Connected, and runs scans for the Settings network list. class WifiService : public Service { public: WifiService(Settings& settings, SavedNetworks& saved, ClockService& clock) : settings_(settings), saved_(saved), clock_(clock), controller_(saved) {} const char* name() const override { return "wifi"; } uint32_t tickIntervalMs() const override { return 250; } void tick(uint32_t nowMs) override; WifiController::State state() const { return controller_.state(); } const std::string& ssid() const { return controller_.ssid(); } int rssi() const; std::string ip() const; // empty unless Connected // Scans for a list of nearby networks (all channels, or just one for a quick refresh); results // arrive in listScan() when listScanDone(), and listScanSeq() counts completed scans. void startListScan(int channel = 0); bool listScanDone() const { return !listScanPending_; } const std::vector& listScan() const { return listScan_; } uint32_t listScanSeq() const { return listScanSeq_; } // Done with list scans: switch the radio back off if Wi-Fi itself is off. void endListScans(); // What the device is using and where each part came from (S1, Q113). struct Connection { bool connected = false; bool fixed = false; // the address: Fixed, or from DHCP bool dnsFromSettings = false; // DNS: from Settings, or from DHCP std::string address, mask, gateway; int prefix = 0; std::string dns[2]; struct Ntp { std::string server; bool fromDhcp = false; bool answered = false; // it has replied since the last (re)start } ntp[3]; int ntpCount = 0; }; Connection connection() const; // A Saved Network's IP setting changed: if it's the one in use, join it again with it (Q114). void ipSettingChanged(const std::string& ssid); // The DNS or NTP settings changed: use them now. void serversChanged() { applyServers(Why::SettingsChanged); } #ifdef RORO_DEBUG // The noise self-test switches the radio off for a few seconds. Not saved anywhere: a restart // during the test brings Wi-Fi back, which a changed setting wouldn't. void debugPause(bool paused) { paused_ = paused; } #endif // A Saved Network was added: try it now rather than after the retry delay. void savedNetworksChanged() { controller_.retryNow(millis()); } void requestMonitor() { apply(controller_.requestMonitor()); } void releaseMonitor() { apply(controller_.releaseMonitor(settings_.getBool(Setting::WifiEnabled))); } private: void apply(const WifiController::Step& step); void startScan(int channel = 0); void finishScan(uint32_t nowMs); void startNtp(); void join(const std::string& ssid, const std::string& password); enum class Why { Joined, SettingsChanged, Check }; void applyServers(Why why); // DNS and NTP, as Settings and the network say Settings& settings_; SavedNetworks& saved_; ClockService& clock_; WifiController controller_; bool scanRunning_ = false; bool listScanPending_ = false; std::vector listScan_; uint32_t listScanSeq_ = 0; bool ntpWaiting_ = false; bool sntpStarted_ = false; bool radioInitialised_ = false; bool paused_ = false; // Debug Builds: off for a moment, whatever the setting says bool fixed_ = false; // the network in use has a Fixed address bool dnsFromSettings_ = false; std::string ntpNames_[2]; // lwIP keeps the pointers, so the names live here uint32_t serversCheckedMs_ = 0; }; } // namespace roro