27 roo_scheduler::Scheduler& scheduler)
29 interface_(interface),
32 current_network_index_(-1),
35 wifi_listener_(*this),
38 start_scan_(scheduler, [this]() {
startScan(); }),
39 refresh_current_network_(scheduler,
40 [
this]() { periodicRefreshCurrentNetwork(); }) {}
49 if (enabled_ && !ssid.empty()) {
55 model_listeners_.insert(listener);
59 model_listeners_.erase(listener);
63 int count = all_networks_.size();
64 if (current_network_index_ >= 0) --count;
69 return current_network_;
73 const std::string& ssid)
const {
74 for (
const Network& net : all_networks_) {
75 if (net.ssid == ssid)
return &net;
81 return current_network_status_;
85 if (current_network_index_ >= 0 && idx >= current_network_index_) {
88 return all_networks_[idx];
94 for (
auto& l : model_listeners_) {
102 enabled_ = !enabled_;
117 for (
auto& l : model_listeners_) {
118 l->onEnableChanged(enabled_);
123 std::string& passwd)
const {
130 if (!enabled_)
return;
131 refreshCurrentNetwork();
132 if (!refresh_current_network_.is_scheduled()) {
133 refresh_current_network_.scheduleAfter(roo_time::Seconds(2));
136 for (
auto& l : model_listeners_) {
137 l->onScanCompleted();
139 start_scan_.scheduleAfter(roo_time::Seconds(15));
146 const std::string& passwd) {
152 std::string password;
154 return connect(ssid, password);
159 if (ssid != default_ssid) {
162 std::string current_password;
163 if (!passwd.empty() && (!store_.
getPassword(ssid, current_password) ||
164 current_password != passwd)) {
167 if (!interface_.
connect(ssid, passwd))
return false;
170 if (in_range ==
nullptr) {
171 updateCurrentNetwork(ssid, passwd.empty(), -128,
WL_DISCONNECTED,
true);
198 updateCurrentNetwork(current_network_.
ssid, current_network_.
open,
199 current_network_.
rssi, getConnectionStatus(type),
true);
200 for (
auto& l : model_listeners_) {
201 l->onConnectionStateChanged(type);
205void Controller::periodicRefreshCurrentNetwork() {
206 refreshCurrentNetwork();
208 refresh_current_network_.scheduleAfter(roo_time::Seconds(2));
212void Controller::refreshCurrentNetwork() {
214 NetworkDetails current;
216 updateCurrentNetwork(std::string((
const char*)current.ssid,
217 strlen((
const char*)current.ssid)),
219 current.status,
false);
223 const Network* default_network_in_range =
nullptr;
224 if (!default_ssid.empty()) {
231 if (default_network_in_range ==
nullptr) {
233 ? current_network_status_
235 updateCurrentNetwork(default_ssid,
true, -128, new_status,
false);
238 ? current_network_status_
240 updateCurrentNetwork(default_ssid, default_network_in_range->open,
241 default_network_in_range->rssi, new_status,
false);
246void Controller::updateCurrentNetwork(
const std::string& ssid,
bool open,
249 if (!force_notify && rssi == current_network_.
rssi &&
250 ssid == current_network_.
ssid && open == current_network_.
open &&
251 status == current_network_status_) {
254 current_network_.
ssid = ssid;
255 current_network_.
open = open;
256 current_network_.
rssi = rssi;
257 current_network_status_ = status;
258 current_network_index_ = -1;
259 for (
size_t i = 0; i < all_networks_.size(); ++i) {
260 if (all_networks_[i].ssid == ssid) {
261 current_network_index_ =
static_cast<int16_t
>(i);
265 for (
auto& l : model_listeners_) {
266 l->onCurrentNetworkChanged();
270void Controller::onScanCompleted() {
271 current_network_index_ = -1;
272 std::vector<NetworkDetails> raw_data;
274 int raw_count = raw_data.size();
275 if (raw_count == 0) {
276 all_networks_.clear();
281 std::vector<uint8_t> indices(raw_data.size(), 0);
282 for (uint8_t i = 0; i < raw_count; ++i) indices[i] = i;
283 std::sort(&indices[0], &indices[raw_count], [&](
int a,
int b) ->
bool {
284 int ssid_cmp = strncmp((
const char*)raw_data[a].ssid,
285 (
const char*)raw_data[b].ssid, 33);
286 if (ssid_cmp < 0)
return true;
287 if (ssid_cmp > 0)
return false;
288 return raw_data[a].rssi > raw_data[b].rssi;
291 const char* current_ssid = (
const char*)raw_data[indices[0]].ssid;
294 while (src < raw_count) {
295 const char* candidate_ssid = (
const char*)raw_data[indices[src]].ssid;
296 if (strncmp(current_ssid, candidate_ssid, 33) != 0) {
297 current_ssid = candidate_ssid;
298 indices[dst++] = indices[src];
304 std::sort(&indices[0], &indices[dst], [&](
int a,
int b) ->
bool {
305 return raw_data[a].rssi > raw_data[b].rssi;
308 all_networks_.resize(dst);
310 for (uint8_t i = 0; i < dst; ++i) {
311 NetworkDetails& src = raw_data[indices[i]];
312 Network& dst = all_networks_[i];
314 std::string((
const char*)src.ssid, strlen((
const char*)src.ssid));
317 if (dst.ssid == current_network_.
ssid) {
319 current_network_index_ = i;
328 for (
auto& l : model_listeners_) {
329 l->onScanCompleted();
332 start_scan_.scheduleAfter(roo_time::Seconds(15));
Listener for controller events.
const Network & currentNetwork() const
Returns the current network (may be empty if disconnected).
void pause()
Temporarily disables periodic refresh and event processing.
ConnectionStatus currentNetworkStatus() const
Returns the connection status of the current network.
void toggleEnabled()
Toggles the enabled/disabled state and persists it in the store.
void begin()
Initializes the controller and registers for interface events.
void resume()
Resumes periodic refresh and event processing.
bool isEnabled() const
Returns true when the interface is enabled.
bool connect()
Connects using stored SSID/password values.
void removeListener(Listener *listener)
Removes a previously added listener.
void forget(const std::string &ssid)
Forgets the password and SSID association.
bool startScan()
Starts a scan. Returns false if a scan could not be started.
void disconnect()
Disconnects the current connection.
~Controller()
Destroys the controller and detaches listeners.
bool getStoredPassword(const std::string &ssid, std::string &passwd) const
Looks up a stored password for the given SSID.
void setPassword(const std::string &ssid, const std::string &passwd)
Stores a password for the given SSID.
int otherScannedNetworksCount() const
Returns the number of non-current networks in the scan list.
Controller(Store &store, Interface &interface, roo_scheduler::Scheduler &scheduler)
Creates a controller using the provided store, interface, and scheduler.
void addListener(Listener *listener)
Adds a listener for controller events.
const Network * lookupNetwork(const std::string &ssid) const
Returns a network by SSID, or nullptr if not found.
void notifyEnableChanged()
Notifies listeners that enable state changed.
const Network & otherNetwork(int idx) const
Returns the ith non-current network in the scan list.
Abstraction for interacting with the hardware Wi-Fi interface.
virtual void removeEventListener(EventListener *listener)=0
Unregisters an interface event listener.
virtual void disconnect()=0
Disconnects from the current network.
EventType
Interface event types.
virtual bool getApInfo(NetworkDetails *info) const =0
Returns current AP information; false if not connected.
virtual bool startScan()=0
Starts a scan.
virtual void addEventListener(EventListener *listener)=0
Registers an interface event listener.
virtual bool getScanResults(std::vector< NetworkDetails > *list, int max_count) const =0
Returns scan results, up to max_count entries.
virtual bool scanCompleted() const =0
Returns true if the last scan has completed.
virtual bool connect(const std::string &ssid, const std::string &passwd)=0
Connects to the specified SSID/password.
Abstraction for persistently storing Wi-Fi controller data.
virtual void clearDefaultSSID()=0
Clears the default SSID.
virtual bool getPassword(const std::string &ssid, std::string &password)=0
Retrieves a stored password for an SSID.
virtual void setPassword(const std::string &ssid, roo::string_view password)=0
Stores a password for an SSID.
virtual bool getIsInterfaceEnabled()=0
Returns whether the Wi-Fi interface is enabled.
virtual std::string getDefaultSSID()=0
Returns the default SSID, if any.
virtual void clearPassword(const std::string &ssid)=0
Clears a stored password for an SSID.
virtual void setDefaultSSID(const std::string &ssid)=0
Sets the default SSID.
virtual void setIsInterfaceEnabled(bool enabled)=0
Sets whether the Wi-Fi interface is enabled.
ConnectionStatus
Wi-Fi connection status.
Summary of a scanned network.