#include "wifi_controller.h" namespace roro { namespace { const uint32_t kRetryDelaysMs[] = {10000, 30000, 60000}; const int kRetrySteps = sizeof(kRetryDelaysMs) / sizeof(kRetryDelaysMs[0]); } // namespace WifiController::Step WifiController::wait(uint32_t nowMs) { state_ = State::Waiting; retryAtMs_ = nowMs + kRetryDelaysMs[retries_ < kRetrySteps ? retries_ : kRetrySteps - 1]; retries_++; return act(Action::None); } WifiController::Step WifiController::update(uint32_t nowMs, bool enabled) { if (state_ == State::Monitoring) return act(Action::None); if (!enabled || saved_.count() == 0) { // nothing to join: keep the radio off if (state_ == State::Off) return act(Action::None); state_ = State::Off; ssid_.clear(); return act(Action::RadioOff); } switch (state_) { case State::Off: state_ = State::Scanning; return act(Action::StartScan); case State::Waiting: if (static_cast(nowMs - retryAtMs_) < 0) return act(Action::None); state_ = State::Scanning; return act(Action::StartScan); case State::Connecting: if (nowMs - sinceMs_ < kConnectTimeoutMs) return act(Action::None); wait(nowMs); return act(Action::Disconnect); default: return act(Action::None); } } WifiController::Step WifiController::scanDone(const std::vector& results, uint32_t nowMs) { if (state_ != State::Scanning) return act(Action::None); const ScanResult* best = nullptr; for (auto& r : results) if (saved_.find(r.ssid) && (!best || r.rssi > best->rssi)) best = &r; const SavedNetwork* net = best ? saved_.find(best->ssid) : nullptr; if (!net) { // Hidden networks never appear in scans: try them one at a time. for (int i = 0; i < saved_.count() && !net; i++) { const SavedNetwork& candidate = saved_.at((nextHidden_ + i) % saved_.count()); if (candidate.hidden) { net = &candidate; nextHidden_ = (nextHidden_ + i + 1) % saved_.count(); } } } if (!net) return wait(nowMs); state_ = State::Connecting; ssid_ = net->ssid; sinceMs_ = nowMs; return Step{Action::Connect, net->ssid, net->password}; } WifiController::Step WifiController::connected(uint32_t) { if (state_ != State::Connecting) return act(Action::None); state_ = State::Connected; retries_ = 0; return act(Action::None); } WifiController::Step WifiController::disconnected(uint32_t nowMs) { if (state_ == State::Connected) { state_ = State::Scanning; return act(Action::StartScan); } if (state_ == State::Connecting) return wait(nowMs); // e.g. wrong password return act(Action::None); } WifiController::Step WifiController::requestMonitor() { state_ = State::Monitoring; ssid_.clear(); return act(Action::StartMonitor); } WifiController::Step WifiController::releaseMonitor(bool enabled) { if (state_ != State::Monitoring) return act(Action::None); retries_ = 0; if (enabled) { state_ = State::Scanning; return act(Action::StopMonitorAndScan); } state_ = State::Off; return act(Action::StopMonitorAndOff); } } // namespace roro