Public Access
At every join the DNS and NTP setup ran twice in the same pass: the "check now and then" timer compared this pass's time with a stamp taken from millis() a moment later, and the unsigned difference underflowed. Starting SNTP is only queued for the network task, so when the second run looked before the first had been carried out, it queued a second start: "Operating mode must not be set while SNTP client is running", a panic nine seconds after boot. Rare (once in the dozen or so boots of this branch's testing), there since v0.7.0. Rollback caught it: the update was on Probation and the device went back to the build before. The service now remembers that it started SNTP instead of asking esp_sntp_enabled(), and the timer compares signed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
99 lines
4.0 KiB
C++
99 lines
4.0 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
|
|
#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<ScanEntry>& 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<ScanEntry> 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
|