diff --git a/Documentation/ideas.md b/Documentation/ideas.md index 26595479..6ccf89f7 100644 --- a/Documentation/ideas.md +++ b/Documentation/ideas.md @@ -15,7 +15,6 @@ - Explore LVGL9's FreeRTOS functionality - Explore LVGL9's ILI93414 driver for 2.4" Yellow Board - Bug: in LVGL9 with M5Core2, crash when bottom item is clicked without scrolling first -- De-duplicate WiFi SSIDs. - Replace M5Unified and M5GFX with custom drivers (so we can fix the Core2 SD card mounting bug, and so we regain some firmware space) - Commit fix to esp_lvgl_port to have esp_lvgl_port_disp.c user driver_data instead of user_data @@ -28,10 +27,11 @@ - Wi-Fi using dispatcher to dispatch its main functionality to the dedicated Wi-Fi CPU core (to avoid main loop hack) # App Ideas +- Add FreeRTOS task manager functionality to System Info app - BlueTooth keyboard app - Chip 8 emulator -- BadUSB +- BadUSB (in December 2024, TinyUSB has a bug where uninstalling and re-installing the driver fails) - Discord bot - IR transceiver app - GPS app -- Investigate CSI https://stevenmhernandez.github.io/ESP32-CSI-Tool/ \ No newline at end of file +- Investigate CSI https://stevenmhernandez.github.io/ESP32-CSI-Tool/ diff --git a/Tactility/Source/app/Manifest.h b/Tactility/Source/app/Manifest.h index 03b7e468..e3649133 100644 --- a/Tactility/Source/app/Manifest.h +++ b/Tactility/Source/app/Manifest.h @@ -38,7 +38,7 @@ typedef void (*AppOnShow)(App& app, lv_obj_t* parent); typedef void (*AppOnHide)(App& app); typedef void (*AppOnResult)(App& app, Result result, const Bundle& resultData); -typedef struct Manifest { +struct Manifest { /** * The identifier by which the app is launched by the system and other apps. */ @@ -83,7 +83,7 @@ typedef struct Manifest { * Handle the result for apps that are launched */ const AppOnResult _Nullable onResult = nullptr; -} Manifest; +}; struct { bool operator()(const Manifest* left, const Manifest* right) const { return left->name < right->name; } diff --git a/Tactility/Source/app/wifimanage/WifiManageBindings.h b/Tactility/Source/app/wifimanage/Bindings.h similarity index 57% rename from Tactility/Source/app/wifimanage/WifiManageBindings.h rename to Tactility/Source/app/wifimanage/Bindings.h index b0e79d74..091de0a2 100644 --- a/Tactility/Source/app/wifimanage/WifiManageBindings.h +++ b/Tactility/Source/app/wifimanage/Bindings.h @@ -6,10 +6,10 @@ typedef void (*OnWifiToggled)(bool enable); typedef void (*OnConnectSsid)(const char* ssid); typedef void (*OnDisconnect)(); -typedef struct { - OnWifiToggled on_wifi_toggled; - OnConnectSsid on_connect_ssid; - OnDisconnect on_disconnect; -} WifiManageBindings; +struct Bindings{ + OnWifiToggled onWifiToggled; + OnConnectSsid onConnectSsid; + OnDisconnect onDisconnect; +}; } // namespace diff --git a/Tactility/Source/app/wifimanage/State.cpp b/Tactility/Source/app/wifimanage/State.cpp new file mode 100644 index 00000000..63b44f27 --- /dev/null +++ b/Tactility/Source/app/wifimanage/State.cpp @@ -0,0 +1,33 @@ +#include +#include "WifiManage.h" + +namespace tt::app::wifimanage { + +void State::setScanning(bool isScanning) { + tt_check(mutex.acquire(TtWaitForever) == TtStatusOk); + scanning = isScanning; + tt_check(mutex.release() == TtStatusOk); +} + +void State::setRadioState(service::wifi::WifiRadioState state) { + tt_check(mutex.acquire(TtWaitForever) == TtStatusOk); + radioState = state; + tt_check(mutex.release() == TtStatusOk); +} + +const std::vector& State::lockApRecords() const { + tt_check(mutex.acquire(TtWaitForever) == TtStatusOk); + return apRecords; +} + +void State::unlockApRecords() const { + tt_check(mutex.release() == TtStatusOk); +} + +void State::updateApRecords() { + tt_check(mutex.acquire(TtWaitForever) == TtStatusOk); + apRecords = service::wifi::getScanResults(); + tt_check(mutex.release() == TtStatusOk); +} + +} // namespace diff --git a/Tactility/Source/app/wifimanage/State.h b/Tactility/Source/app/wifimanage/State.h new file mode 100644 index 00000000..5f709100 --- /dev/null +++ b/Tactility/Source/app/wifimanage/State.h @@ -0,0 +1,37 @@ +#pragma once + +#include "service/wifi/Wifi.h" +#include "Mutex.h" + +namespace tt::app::wifimanage { + +/** + * View's state + */ +class State { + + Mutex mutex; + bool scanning; + service::wifi::WifiRadioState radioState; + std::vector apRecords; + std::string connectSsid; + +public: + State() {} + + void setScanning(bool isScanning); + bool isScanning() const { return scanning; } + + void setRadioState(service::wifi::WifiRadioState state); + service::wifi::WifiRadioState getRadioState() const { return radioState; } + + void updateApRecords(); + + const std::vector& lockApRecords() const; + void unlockApRecords() const; + + void setConnectSsid(std::string ssid) { connectSsid = ssid; } + std::string getConnectSsid() const { return connectSsid; } +}; + +} // namespace diff --git a/Tactility/Source/app/wifimanage/View.cpp b/Tactility/Source/app/wifimanage/View.cpp new file mode 100644 index 00000000..69954c0d --- /dev/null +++ b/Tactility/Source/app/wifimanage/View.cpp @@ -0,0 +1,215 @@ +#include "View.h" + +#include "Log.h" +#include "State.h" +#include "service/statusbar/Statusbar.h" +#include "service/wifi/Wifi.h" +#include "lvgl/Style.h" +#include "lvgl/Toolbar.h" + +#include +#include + +namespace tt::app::wifimanage { + +#define TAG "wifi_main_view" +#define SPINNER_HEIGHT 40 + +static void on_enable_switch_changed(lv_event_t* event) { + lv_event_code_t code = lv_event_get_code(event); + auto* enable_switch = static_cast(lv_event_get_target(event)); + if (code == LV_EVENT_VALUE_CHANGED) { + bool is_on = lv_obj_has_state(enable_switch, LV_STATE_CHECKED); + auto* bindings = static_cast(lv_event_get_user_data(event)); + bindings->onWifiToggled(is_on); + } +} + +static void on_disconnect_pressed(lv_event_t* event) { + auto* bindings = static_cast(lv_event_get_user_data(event)); + bindings->onDisconnect(); +} + +// region Secondary updates + +static void connect(lv_event_t* event) { + lv_obj_t* button = lv_event_get_current_target_obj(event); + // Assumes that the second child of the button is a label ... risky + lv_obj_t* label = lv_obj_get_child(button, 1); + // We get the SSID from the button label because it's safer than alloc'ing + // our own and passing it as the event data + const char* ssid = lv_label_get_text(label); + TT_LOG_I(TAG, "Clicked AP: %s", ssid); + auto* bindings = static_cast(lv_event_get_user_data(event)); + bindings->onConnectSsid(ssid); +} + +void View::createNetworkButton(Bindings* bindings, const service::wifi::WifiApRecord& record) { + const char* icon = service::statusbar::getWifiStatusIconForRssi(record.rssi, record.auth_mode != WIFI_AUTH_OPEN); + lv_obj_t* ap_button = lv_list_add_btn( + networks_list, + icon, + record.ssid.c_str() + ); + lv_obj_add_event_cb(ap_button, &connect, LV_EVENT_CLICKED, bindings); +} + +void View::updateNetworkList(State* state, Bindings* bindings) { + lv_obj_clean(networks_list); + switch (state->getRadioState()) { + case service::wifi::WIFI_RADIO_ON_PENDING: + case service::wifi::WIFI_RADIO_ON: + case service::wifi::WIFI_RADIO_CONNECTION_PENDING: + case service::wifi::WIFI_RADIO_CONNECTION_ACTIVE: { + lv_obj_clear_flag(networks_label, LV_OBJ_FLAG_HIDDEN); + auto& ap_records = state->lockApRecords(); + std::set used_ssids; + if (!ap_records.empty()) { + for (auto& record : ap_records) { + if (used_ssids.find(record.ssid) == used_ssids.end()) { + createNetworkButton(bindings, record); + used_ssids.insert(record.ssid); + } + } + lv_obj_clear_flag(networks_list, LV_OBJ_FLAG_HIDDEN); + } else if (state->isScanning()) { + lv_obj_add_flag(networks_list, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_clear_flag(networks_list, LV_OBJ_FLAG_HIDDEN); + lv_obj_t* label = lv_label_create(networks_list); + lv_label_set_text(label, "No networks found."); + } + state->unlockApRecords(); + break; + } + case service::wifi::WIFI_RADIO_OFF_PENDING: + case service::wifi::WIFI_RADIO_OFF: { + lv_obj_add_flag(networks_list, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(networks_label, LV_OBJ_FLAG_HIDDEN); + break; + } + } +} + +void View::updateScanning(State* state) { + if (state->getRadioState() == service::wifi::WIFI_RADIO_ON && state->isScanning()) { + lv_obj_clear_flag(scanning_spinner, LV_OBJ_FLAG_HIDDEN); + } else { + lv_obj_add_flag(scanning_spinner, LV_OBJ_FLAG_HIDDEN); + } +} + +void View::updateWifiToggle(State* state) { + lv_obj_clear_state(enable_switch, LV_STATE_ANY); + switch (state->getRadioState()) { + case service::wifi::WIFI_RADIO_ON: + case service::wifi::WIFI_RADIO_CONNECTION_PENDING: + case service::wifi::WIFI_RADIO_CONNECTION_ACTIVE: + lv_obj_add_state(enable_switch, LV_STATE_CHECKED); + break; + case service::wifi::WIFI_RADIO_ON_PENDING: + lv_obj_add_state(enable_switch, LV_STATE_CHECKED | LV_STATE_DISABLED); + break; + case service::wifi::WIFI_RADIO_OFF: + lv_obj_remove_state(enable_switch, LV_STATE_CHECKED | LV_STATE_DISABLED); + break; + case service::wifi::WIFI_RADIO_OFF_PENDING: + lv_obj_remove_state(enable_switch, LV_STATE_CHECKED); + lv_obj_add_state(enable_switch, LV_STATE_DISABLED); + break; + } +} + +void View::updateConnectedAp(State* state, TT_UNUSED Bindings* bindings) { + switch (state->getRadioState()) { + case service::wifi::WIFI_RADIO_CONNECTION_PENDING: + case service::wifi::WIFI_RADIO_CONNECTION_ACTIVE: + lv_obj_clear_flag(connected_ap_container, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(connected_ap_label, state->getConnectSsid().c_str()); + break; + default: + lv_obj_add_flag(connected_ap_container, LV_OBJ_FLAG_HIDDEN); + break; + } +} + +// endregion Secondary updates + +// region Main + +void View::init(const App& app, Bindings* bindings, lv_obj_t* parent) { + root = parent; + + lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); + lvgl::toolbar_create(parent, app); + + lv_obj_t* wrapper = lv_obj_create(parent); + lv_obj_set_width(wrapper, LV_PCT(100)); + lv_obj_set_flex_grow(wrapper, 1); + lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN); + + // Top row: enable/disable + lv_obj_t* switch_container = lv_obj_create(wrapper); + lv_obj_set_width(switch_container, LV_PCT(100)); + lv_obj_set_height(switch_container, LV_SIZE_CONTENT); + lvgl::obj_set_style_no_padding(switch_container); + lvgl::obj_set_style_bg_invisible(switch_container); + + lv_obj_t* enable_label = lv_label_create(switch_container); + lv_label_set_text(enable_label, "Wi-Fi"); + lv_obj_set_align(enable_label, LV_ALIGN_LEFT_MID); + + enable_switch = lv_switch_create(switch_container); + lv_obj_add_event_cb(enable_switch, on_enable_switch_changed, LV_EVENT_ALL, bindings); + lv_obj_set_align(enable_switch, LV_ALIGN_RIGHT_MID); + + connected_ap_container = lv_obj_create(wrapper); + lv_obj_set_size(connected_ap_container, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_style_min_height(connected_ap_container, SPINNER_HEIGHT, 0); + lvgl::obj_set_style_no_padding(connected_ap_container); + lv_obj_set_style_border_width(connected_ap_container, 0, 0); + + connected_ap_label = lv_label_create(connected_ap_container); + lv_obj_align(connected_ap_label, LV_ALIGN_LEFT_MID, 0, 0); + + lv_obj_t* disconnect_button = lv_btn_create(connected_ap_container); + lv_obj_add_event_cb(disconnect_button, &on_disconnect_pressed, LV_EVENT_CLICKED, bindings); + lv_obj_t* disconnect_label = lv_label_create(disconnect_button); + lv_label_set_text(disconnect_label, "Disconnect"); + lv_obj_align(disconnect_button, LV_ALIGN_RIGHT_MID, 0, 0); + + // Networks + + lv_obj_t* networks_header = lv_obj_create(wrapper); + lv_obj_set_size(networks_header, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_style_min_height(networks_header, SPINNER_HEIGHT, 0); + lvgl::obj_set_style_no_padding(networks_header); + lv_obj_set_style_border_width(networks_header, 0, 0); + + networks_label = lv_label_create(networks_header); + lv_label_set_text(networks_label, "Networks"); + lv_obj_align(networks_label, LV_ALIGN_LEFT_MID, 0, 0); + + scanning_spinner = lv_spinner_create(networks_header); + lv_spinner_set_anim_params(scanning_spinner, 1000, 60); + lv_obj_set_size(scanning_spinner, SPINNER_HEIGHT, SPINNER_HEIGHT); + lv_obj_set_style_pad_top(scanning_spinner, 4, 0); + lv_obj_set_style_pad_bottom(scanning_spinner, 4, 0); + lv_obj_align_to(scanning_spinner, networks_label, LV_ALIGN_OUT_RIGHT_MID, 8, 0); + + networks_list = lv_obj_create(wrapper); + lv_obj_set_flex_flow(networks_list, LV_FLEX_FLOW_COLUMN); + lv_obj_set_width(networks_list, LV_PCT(100)); + lv_obj_set_height(networks_list, LV_SIZE_CONTENT); + lv_obj_set_style_pad_top(networks_list, 8, 0); + lv_obj_set_style_pad_bottom(networks_list, 8, 0); +} + +void View::update(Bindings* bindings, State* state) { + updateWifiToggle(state); + updateScanning(state); + updateNetworkList(state, bindings); + updateConnectedAp(state, bindings); +} + +} // namespace diff --git a/Tactility/Source/app/wifimanage/View.h b/Tactility/Source/app/wifimanage/View.h new file mode 100644 index 00000000..eab212d3 --- /dev/null +++ b/Tactility/Source/app/wifimanage/View.h @@ -0,0 +1,34 @@ +#pragma once + +#include "app/App.h" +#include "Bindings.h" +#include "State.h" +#include "lvgl.h" + +namespace tt::app::wifimanage { + +class View { +private: + lv_obj_t* root = nullptr; + lv_obj_t* enable_switch = nullptr; + lv_obj_t* scanning_spinner = nullptr; + lv_obj_t* networks_label = nullptr; + lv_obj_t* networks_list = nullptr; + lv_obj_t* connected_ap_container = nullptr; + lv_obj_t* connected_ap_label = nullptr; +public: + View() {} + void init(const App& app, Bindings* bindings, lv_obj_t* parent); + void update(Bindings* bindings, State* state); + +private: + + void updateConnectedAp(State* state, TT_UNUSED Bindings* bindings); + void updateWifiToggle(State* state); + void updateScanning(State* state); + void updateNetworkList(State* state, Bindings* bindings); + void createNetworkButton(Bindings* bindings, const service::wifi::WifiApRecord& record); +}; + + +} // namespace diff --git a/Tactility/Source/app/wifimanage/WifiManage.cpp b/Tactility/Source/app/wifimanage/WifiManage.cpp index d17fba7c..a393ec74 100644 --- a/Tactility/Source/app/wifimanage/WifiManage.cpp +++ b/Tactility/Source/app/wifimanage/WifiManage.cpp @@ -6,17 +6,14 @@ #include "service/loader/Loader.h" #include "service/wifi/WifiSettings.h" #include "lvgl/LvglSync.h" -#include "WifiManageStateUpdating.h" -#include "WifiManageView.h" +#include "View.h" +#include "State.h" namespace tt::app::wifimanage { #define TAG "wifi_manage" -// Forward declarations -static void event_callback(const void* message, void* context); - -static void on_connect(const char* ssid) { +static void onConnect(const char* ssid) { service::wifi::settings::WifiApSettings settings; if (service::wifi::settings::load(ssid, &settings)) { TT_LOG_I(TAG, "Connecting with known credentials"); @@ -30,79 +27,55 @@ static void on_connect(const char* ssid) { } } -static void on_disconnect() { +static void onDisconnect() { service::wifi::disconnect(); } -static void on_wifi_toggled(bool enabled) { +static void onWifiToggled(bool enabled) { service::wifi::setEnabled(enabled); } -static WifiManage* wifi_manage_alloc() { - auto* wifi = static_cast(malloc(sizeof(WifiManage))); - - wifi->wifi_subscription = nullptr; - wifi->mutex = tt_mutex_alloc(MutexTypeNormal); - wifi->state = (WifiManageState) { - .scanning = service::wifi::isScanning(), - .radio_state = service::wifi::getRadioState(), - .connect_ssid = { 0 }, - .ap_records = { }, - .ap_records_count = 0 +WifiManage::WifiManage() { + bindings = (Bindings) { + .onWifiToggled = &onWifiToggled, + .onConnectSsid = &onConnect, + .onDisconnect = &onDisconnect }; - wifi->view_enabled = false; - wifi->bindings = (WifiManageBindings) { - .on_wifi_toggled = &on_wifi_toggled, - .on_connect_ssid = &on_connect, - .on_disconnect = &on_disconnect - }; - - return wifi; } -static void wifi_manage_free(WifiManage* wifi) { - tt_mutex_free(wifi->mutex); - - free(wifi); +void WifiManage::lock() { + tt_check(mutex.acquire(TtWaitForever) == TtStatusOk); } -void lock(WifiManage* wifi) { - tt_assert(wifi); - tt_assert(wifi->mutex); - tt_mutex_acquire(wifi->mutex, TtWaitForever); +void WifiManage::unlock() { + tt_check(mutex.release() == TtStatusOk); } -void unlock(WifiManage* wifi) { - tt_assert(wifi); - tt_assert(wifi->mutex); - tt_mutex_release(wifi->mutex); -} - -void request_view_update(WifiManage* wifi) { - lock(wifi); - if (wifi->view_enabled) { +void WifiManage::requestViewUpdate() { + lock(); + if (isViewEnabled) { if (lvgl::lock(1000)) { - view_update(&wifi->view, &wifi->bindings, &wifi->state); + view.update(&bindings, &state); lvgl::unlock(); } else { TT_LOG_E(TAG, "failed to lock lvgl"); } } - unlock(wifi); + unlock(); } -static void wifi_manage_event_callback(const void* message, void* context) { +static void wifiManageEventCallback(const void* message, void* context) { auto* event = (service::wifi::WifiEvent*)message; auto* wifi = (WifiManage*)context; TT_LOG_I(TAG, "Update with state %d", service::wifi::getRadioState()); - state_set_radio_state(wifi, service::wifi::getRadioState()); + wifi->getState().setRadioState(service::wifi::getRadioState()); switch (event->type) { case tt::service::wifi::WifiEventTypeScanStarted: - state_set_scanning(wifi, true); + wifi->getState().setScanning(true); break; case tt::service::wifi::WifiEventTypeScanFinished: - state_set_scanning(wifi, false); - state_update_scanned_records(wifi); + wifi->getState().setScanning(false); + wifi->getState().updateApRecords(); break; case tt::service::wifi::WifiEventTypeRadioStateOn: if (!service::wifi::isScanning()) { @@ -113,27 +86,25 @@ static void wifi_manage_event_callback(const void* message, void* context) { break; } - request_view_update(wifi); + wifi->requestViewUpdate(); } -static void app_show(App& app, lv_obj_t* parent) { - auto* wifi = (WifiManage*)app.getData(); - +void WifiManage::onShow(App& app, lv_obj_t* parent) { PubSub* wifi_pubsub = service::wifi::getPubsub(); - wifi->wifi_subscription = tt_pubsub_subscribe(wifi_pubsub, &wifi_manage_event_callback, wifi); + wifiSubscription = tt_pubsub_subscribe(wifi_pubsub, &wifiManageEventCallback, this); // State update (it has its own locking) - state_set_radio_state(wifi, service::wifi::getRadioState()); - state_set_scanning(wifi, service::wifi::isScanning()); - state_update_scanned_records(wifi); + state.setRadioState(service::wifi::getRadioState()); + state.setScanning(service::wifi::isScanning()); + state.updateApRecords(); // View update - lock(wifi); - wifi->view_enabled = true; - strcpy((char*)wifi->state.connect_ssid, "Connected"); // TODO update with proper SSID - view_create(app, &wifi->view, &wifi->bindings, parent); - view_update(&wifi->view, &wifi->bindings, &wifi->state); - unlock(wifi); + lock(); + isViewEnabled = true; + state.setConnectSsid("Connected"); // TODO update with proper SSID + view.init(app, &bindings, parent); + view.update(&bindings, &state); + unlock(); service::wifi::WifiRadioState radio_state = service::wifi::getRadioState(); bool can_scan = radio_state == service::wifi::WIFI_RADIO_ON || @@ -144,36 +115,50 @@ static void app_show(App& app, lv_obj_t* parent) { } } -static void app_hide(App& app) { - auto* wifi = (WifiManage*)app.getData(); - lock(wifi); +void WifiManage::onHide(TT_UNUSED App& app) { + lock(); PubSub* wifi_pubsub = service::wifi::getPubsub(); - tt_pubsub_unsubscribe(wifi_pubsub, wifi->wifi_subscription); - wifi->wifi_subscription = nullptr; - wifi->view_enabled = false; - unlock(wifi); + tt_pubsub_unsubscribe(wifi_pubsub, wifiSubscription); + wifiSubscription = nullptr; + isViewEnabled = false; + unlock(); } -static void app_start(App& app) { - WifiManage* wifi = wifi_manage_alloc(); +// region Manifest methods + +static void onStart(App& app) { + auto* wifi = new WifiManage(); app.setData(wifi); } -static void app_stop(App& app) { +static void onStop(App& app) { auto* wifi = (WifiManage*)app.getData(); tt_assert(wifi != nullptr); - wifi_manage_free(wifi); + delete wifi; } +static void onShow(App& app, lv_obj_t* parent) { + auto* wifi = (WifiManage*)app.getData(); + wifi->onShow(app, parent); +} + +static void onHide(App& app) { + auto* wifi = (WifiManage*)app.getData(); + wifi->onHide(app); +} + + +// endregion + extern const Manifest manifest = { .id = "WifiManage", .name = "Wi-Fi", .icon = LV_SYMBOL_WIFI, .type = TypeSettings, - .onStart = &app_start, - .onStop = &app_stop, - .onShow = &app_show, - .onHide = &app_hide + .onStart = onStart, + .onStop = onStop, + .onShow = onShow, + .onHide = onHide }; } // namespace diff --git a/Tactility/Source/app/wifimanage/WifiManage.h b/Tactility/Source/app/wifimanage/WifiManage.h index 036a44cf..50043ff8 100644 --- a/Tactility/Source/app/wifimanage/WifiManage.h +++ b/Tactility/Source/app/wifimanage/WifiManage.h @@ -1,24 +1,34 @@ #pragma once #include "Mutex.h" -#include "WifiManageView.h" +#include "View.h" +#include "State.h" #include "service/wifi/Wifi.h" namespace tt::app::wifimanage { -typedef struct { - PubSubSubscription* wifi_subscription; - Mutex* mutex; - WifiManageState state; - WifiManageView view; - bool view_enabled; - WifiManageBindings bindings; -} WifiManage; +class WifiManage { -void lock(WifiManage* wifi); + PubSubSubscription* wifiSubscription = nullptr; + Mutex mutex; + tt::app::wifimanage::State state; + tt::app::wifimanage::View view; + Bindings bindings = { }; + bool isViewEnabled = false; -void unlock(WifiManage* wifi); +public: -void request_view_update(WifiManage* wifi); + WifiManage(); + + void lock(); + void unlock(); + + void onShow(App& app, lv_obj_t* parent); + void onHide(App& app); + + State& getState() { return state; } + + void requestViewUpdate(); +}; } // namespace diff --git a/Tactility/Source/app/wifimanage/WifiManageState.h b/Tactility/Source/app/wifimanage/WifiManageState.h deleted file mode 100644 index 0aa71488..00000000 --- a/Tactility/Source/app/wifimanage/WifiManageState.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "service/wifi/Wifi.h" - -namespace tt::app::wifimanage { - -#define WIFI_SCAN_AP_RECORD_COUNT 16 - -/** - * View's state - */ -typedef struct { - bool scanning; - service::wifi::WifiRadioState radio_state; - uint8_t connect_ssid[33]; - service::wifi::WifiApRecord ap_records[WIFI_SCAN_AP_RECORD_COUNT]; - uint16_t ap_records_count; -} WifiManageState; - -} // namespace diff --git a/Tactility/Source/app/wifimanage/WifiManageStateUpdating.cpp b/Tactility/Source/app/wifimanage/WifiManageStateUpdating.cpp deleted file mode 100644 index cd4f8456..00000000 --- a/Tactility/Source/app/wifimanage/WifiManageStateUpdating.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "WifiManage.h" - -namespace tt::app::wifimanage { - -void state_set_scanning(WifiManage* wifi, bool is_scanning) { - lock(wifi); - wifi->state.scanning = is_scanning; - unlock(wifi); -} - -void state_set_radio_state(WifiManage* wifi, service::wifi::WifiRadioState state) { - lock(wifi); - wifi->state.radio_state = state; - unlock(wifi); -} - -void state_update_scanned_records(WifiManage* wifi) { - lock(wifi); - service::wifi::getScanResults( - wifi->state.ap_records, - WIFI_SCAN_AP_RECORD_COUNT, - &wifi->state.ap_records_count - ); - unlock(wifi); -} - -} // namespace diff --git a/Tactility/Source/app/wifimanage/WifiManageStateUpdating.h b/Tactility/Source/app/wifimanage/WifiManageStateUpdating.h deleted file mode 100644 index 6fd4cd11..00000000 --- a/Tactility/Source/app/wifimanage/WifiManageStateUpdating.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "WifiManage.h" - -namespace tt::app::wifimanage { - -void state_set_scanning(WifiManage* wifi, bool is_scanning); -void state_set_radio_state(WifiManage* wifi, service::wifi::WifiRadioState state); -void state_update_scanned_records(WifiManage* wifi); - -} // namespace diff --git a/Tactility/Source/app/wifimanage/WifiManageView.cpp b/Tactility/Source/app/wifimanage/WifiManageView.cpp deleted file mode 100644 index 6d705a05..00000000 --- a/Tactility/Source/app/wifimanage/WifiManageView.cpp +++ /dev/null @@ -1,207 +0,0 @@ -#include "WifiManageView.h" - -#include "Log.h" -#include "WifiManageState.h" -#include "service/statusbar/Statusbar.h" -#include "service/wifi/Wifi.h" -#include "lvgl/Style.h" -#include "lvgl/Toolbar.h" - -namespace tt::app::wifimanage { - -#define TAG "wifi_main_view" -#define SPINNER_HEIGHT 40 - -static void on_enable_switch_changed(lv_event_t* event) { - lv_event_code_t code = lv_event_get_code(event); - auto* enable_switch = static_cast(lv_event_get_target(event)); - if (code == LV_EVENT_VALUE_CHANGED) { - bool is_on = lv_obj_has_state(enable_switch, LV_STATE_CHECKED); - auto* bindings = static_cast(lv_event_get_user_data(event)); - bindings->on_wifi_toggled(is_on); - } -} - -static void on_disconnect_pressed(lv_event_t* event) { - auto* bindings = static_cast(lv_event_get_user_data(event)); - bindings->on_disconnect(); -} - -// region Secondary updates - -static void connect(lv_event_t* event) { - lv_obj_t* button = lv_event_get_current_target_obj(event); - // Assumes that the second child of the button is a label ... risky - lv_obj_t* label = lv_obj_get_child(button, 1); - // We get the SSID from the button label because it's safer than alloc'ing - // our own and passing it as the event data - const char* ssid = lv_label_get_text(label); - TT_LOG_I(TAG, "Clicked AP: %s", ssid); - auto* bindings = static_cast(lv_event_get_user_data(event)); - bindings->on_connect_ssid(ssid); -} - -static void create_network_button(WifiManageView* view, WifiManageBindings* bindings, service::wifi::WifiApRecord* record) { - const char* ssid = (const char*)record->ssid; - const char* icon = service::statusbar::getWifiStatusIconForRssi(record->rssi, record->auth_mode != WIFI_AUTH_OPEN); - lv_obj_t* ap_button = lv_list_add_btn( - view->networks_list, - icon, - ssid - ); - lv_obj_add_event_cb(ap_button, &connect, LV_EVENT_CLICKED, bindings); -} - -static void update_network_list(WifiManageView* view, WifiManageState* state, WifiManageBindings* bindings) { - lv_obj_clean(view->networks_list); - switch (state->radio_state) { - case service::wifi::WIFI_RADIO_ON_PENDING: - case service::wifi::WIFI_RADIO_ON: - case service::wifi::WIFI_RADIO_CONNECTION_PENDING: - case service::wifi::WIFI_RADIO_CONNECTION_ACTIVE: { - lv_obj_clear_flag(view->networks_label, LV_OBJ_FLAG_HIDDEN); - if (state->ap_records_count > 0) { - for (int i = 0; i < state->ap_records_count; ++i) { - create_network_button(view, bindings, &state->ap_records[i]); - } - lv_obj_clear_flag(view->networks_list, LV_OBJ_FLAG_HIDDEN); - } else if (state->scanning) { - lv_obj_add_flag(view->networks_list, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_clear_flag(view->networks_list, LV_OBJ_FLAG_HIDDEN); - lv_obj_t* label = lv_label_create(view->networks_list); - lv_label_set_text(label, "No networks found."); - } - break; - } - case service::wifi::WIFI_RADIO_OFF_PENDING: - case service::wifi::WIFI_RADIO_OFF: { - lv_obj_add_flag(view->networks_list, LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(view->networks_label, LV_OBJ_FLAG_HIDDEN); - break; - } - } -} - -void update_scanning(WifiManageView* view, WifiManageState* state) { - if (state->radio_state == service::wifi::WIFI_RADIO_ON && state->scanning) { - lv_obj_clear_flag(view->scanning_spinner, LV_OBJ_FLAG_HIDDEN); - } else { - lv_obj_add_flag(view->scanning_spinner, LV_OBJ_FLAG_HIDDEN); - } -} - -static void update_wifi_toggle(WifiManageView* view, WifiManageState* state) { - lv_obj_clear_state(view->enable_switch, LV_STATE_ANY); - switch (state->radio_state) { - case service::wifi::WIFI_RADIO_ON: - case service::wifi::WIFI_RADIO_CONNECTION_PENDING: - case service::wifi::WIFI_RADIO_CONNECTION_ACTIVE: - lv_obj_add_state(view->enable_switch, LV_STATE_CHECKED); - break; - case service::wifi::WIFI_RADIO_ON_PENDING: - lv_obj_add_state(view->enable_switch, LV_STATE_CHECKED | LV_STATE_DISABLED); - break; - case service::wifi::WIFI_RADIO_OFF: - lv_obj_remove_state(view->enable_switch, LV_STATE_CHECKED | LV_STATE_DISABLED); - break; - case service::wifi::WIFI_RADIO_OFF_PENDING: - lv_obj_remove_state(view->enable_switch, LV_STATE_CHECKED); - lv_obj_add_state(view->enable_switch, LV_STATE_DISABLED); - break; - } -} - -static void update_connected_ap(WifiManageView* view, WifiManageState* state, TT_UNUSED WifiManageBindings* bindings) { - switch (state->radio_state) { - case service::wifi::WIFI_RADIO_CONNECTION_PENDING: - case service::wifi::WIFI_RADIO_CONNECTION_ACTIVE: - lv_obj_clear_flag(view->connected_ap_container, LV_OBJ_FLAG_HIDDEN); - lv_label_set_text(view->connected_ap_label, (const char*)state->connect_ssid); - break; - default: - lv_obj_add_flag(view->connected_ap_container, LV_OBJ_FLAG_HIDDEN); - break; - } -} - -// endregion Secondary updates - -// region Main - -void view_create(const App& app, WifiManageView* view, WifiManageBindings* bindings, lv_obj_t* parent) { - view->root = parent; - - lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); - lvgl::toolbar_create(parent, app); - - lv_obj_t* wrapper = lv_obj_create(parent); - lv_obj_set_width(wrapper, LV_PCT(100)); - lv_obj_set_flex_grow(wrapper, 1); - lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN); - - // Top row: enable/disable - lv_obj_t* switch_container = lv_obj_create(wrapper); - lv_obj_set_width(switch_container, LV_PCT(100)); - lv_obj_set_height(switch_container, LV_SIZE_CONTENT); - lvgl::obj_set_style_no_padding(switch_container); - lvgl::obj_set_style_bg_invisible(switch_container); - - lv_obj_t* enable_label = lv_label_create(switch_container); - lv_label_set_text(enable_label, "Wi-Fi"); - lv_obj_set_align(enable_label, LV_ALIGN_LEFT_MID); - - view->enable_switch = lv_switch_create(switch_container); - lv_obj_add_event_cb(view->enable_switch, on_enable_switch_changed, LV_EVENT_ALL, bindings); - lv_obj_set_align(view->enable_switch, LV_ALIGN_RIGHT_MID); - - view->connected_ap_container = lv_obj_create(wrapper); - lv_obj_set_size(view->connected_ap_container, LV_PCT(100), LV_SIZE_CONTENT); - lv_obj_set_style_min_height(view->connected_ap_container, SPINNER_HEIGHT, 0); - lvgl::obj_set_style_no_padding(view->connected_ap_container); - lv_obj_set_style_border_width(view->connected_ap_container, 0, 0); - - view->connected_ap_label = lv_label_create(view->connected_ap_container); - lv_obj_align(view->connected_ap_label, LV_ALIGN_LEFT_MID, 0, 0); - - lv_obj_t* disconnect_button = lv_btn_create(view->connected_ap_container); - lv_obj_add_event_cb(disconnect_button, &on_disconnect_pressed, LV_EVENT_CLICKED, bindings); - lv_obj_t* disconnect_label = lv_label_create(disconnect_button); - lv_label_set_text(disconnect_label, "Disconnect"); - lv_obj_align(disconnect_button, LV_ALIGN_RIGHT_MID, 0, 0); - - // Networks - - lv_obj_t* networks_header = lv_obj_create(wrapper); - lv_obj_set_size(networks_header, LV_PCT(100), LV_SIZE_CONTENT); - lv_obj_set_style_min_height(networks_header, SPINNER_HEIGHT, 0); - lvgl::obj_set_style_no_padding(networks_header); - lv_obj_set_style_border_width(networks_header, 0, 0); - - view->networks_label = lv_label_create(networks_header); - lv_label_set_text(view->networks_label, "Networks"); - lv_obj_align(view->networks_label, LV_ALIGN_LEFT_MID, 0, 0); - - view->scanning_spinner = lv_spinner_create(networks_header); - lv_spinner_set_anim_params(view->scanning_spinner, 1000, 60); - lv_obj_set_size(view->scanning_spinner, SPINNER_HEIGHT, SPINNER_HEIGHT); - lv_obj_set_style_pad_top(view->scanning_spinner, 4, 0); - lv_obj_set_style_pad_bottom(view->scanning_spinner, 4, 0); - lv_obj_align_to(view->scanning_spinner, view->networks_label, LV_ALIGN_OUT_RIGHT_MID, 8, 0); - - view->networks_list = lv_obj_create(wrapper); - lv_obj_set_flex_flow(view->networks_list, LV_FLEX_FLOW_COLUMN); - lv_obj_set_width(view->networks_list, LV_PCT(100)); - lv_obj_set_height(view->networks_list, LV_SIZE_CONTENT); - lv_obj_set_style_pad_top(view->networks_list, 8, 0); - lv_obj_set_style_pad_bottom(view->networks_list, 8, 0); -} - -void view_update(WifiManageView* view, WifiManageBindings* bindings, WifiManageState* state) { - update_wifi_toggle(view, state); - update_scanning(view, state); - update_network_list(view, state, bindings); - update_connected_ap(view, state, bindings); -} - -} // namespace diff --git a/Tactility/Source/app/wifimanage/WifiManageView.h b/Tactility/Source/app/wifimanage/WifiManageView.h deleted file mode 100644 index 08ae4712..00000000 --- a/Tactility/Source/app/wifimanage/WifiManageView.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "app/App.h" -#include "WifiManageBindings.h" -#include "WifiManageState.h" -#include "lvgl.h" - -namespace tt::app::wifimanage { - -typedef struct { - lv_obj_t* root; - lv_obj_t* enable_switch; - lv_obj_t* scanning_spinner; - lv_obj_t* networks_label; - lv_obj_t* networks_list; - lv_obj_t* connected_ap_container; - lv_obj_t* connected_ap_label; -} WifiManageView; - -void view_create(const App& app, WifiManageView* view, WifiManageBindings* bindings, lv_obj_t* parent); -void view_update(WifiManageView* view, WifiManageBindings* bindings, WifiManageState* state); - -} // namespace diff --git a/TactilityCore/Source/Check.h b/TactilityCore/Source/Check.h index 86ecc14c..151ce283 100644 --- a/TactilityCore/Source/Check.h +++ b/TactilityCore/Source/Check.h @@ -53,7 +53,7 @@ TT_NORETURN void tt_crash_implementation(); * @param optional message (const char*) */ -#define tt_check(x, ...) if (!(x)) { TT_LOG_E("check", "Failed: %s", #x); tt_crash_implementation(); }; +#define tt_check(x, ...) if (!(x)) { TT_LOG_E("check", "Failed: %s", #x); tt_crash_implementation(); } /** Only in debug build: Assert condition and crash if assert failed */ #ifdef TT_DEBUG diff --git a/TactilityHeadless/Source/service/wifi/Wifi.h b/TactilityHeadless/Source/service/wifi/Wifi.h index 0c03ac2f..992341d8 100644 --- a/TactilityHeadless/Source/service/wifi/Wifi.h +++ b/TactilityHeadless/Source/service/wifi/Wifi.h @@ -4,6 +4,8 @@ #include "WifiGlobals.h" #include "WifiSettings.h" #include +#include +#include #ifdef ESP_PLATFORM #include "esp_wifi.h" @@ -32,7 +34,7 @@ typedef enum { namespace tt::service::wifi { -typedef enum { +enum WifiEventType { /** Radio was turned on */ WifiEventTypeRadioStateOn, /** Radio is turning on. */ @@ -49,26 +51,26 @@ typedef enum { WifiEventTypeConnectionPending, WifiEventTypeConnectionSuccess, WifiEventTypeConnectionFailed -} WifiEventType; +}; -typedef enum { +enum WifiRadioState { WIFI_RADIO_ON_PENDING, WIFI_RADIO_ON, WIFI_RADIO_CONNECTION_PENDING, WIFI_RADIO_CONNECTION_ACTIVE, WIFI_RADIO_OFF_PENDING, WIFI_RADIO_OFF -} WifiRadioState; +}; -typedef struct { +struct WifiEvent { WifiEventType type; -} WifiEvent; +}; -typedef struct { - uint8_t ssid[TT_WIFI_SSID_LIMIT + 1]; +struct WifiApRecord { + std::string ssid; int8_t rssi; wifi_auth_mode_t auth_mode; -} WifiApRecord; +}; /** * @brief Get wifi pubsub @@ -89,10 +91,8 @@ bool isScanning(); /** * @brief Returns the access points from the last scan (if any). It only contains public APs. - * @param records the allocated buffer to store the records in - * @param limit the maximum amount of records to store */ -void getScanResults(WifiApRecord records[], uint16_t limit, uint16_t* result_count); +std::vector getScanResults(); /** * @brief Overrides the default scan result size of 16. diff --git a/TactilityHeadless/Source/service/wifi/WifiEsp.cpp b/TactilityHeadless/Source/service/wifi/WifiEsp.cpp index 6e956316..54f0b95b 100644 --- a/TactilityHeadless/Source/service/wifi/WifiEsp.cpp +++ b/TactilityHeadless/Source/service/wifi/WifiEsp.cpp @@ -21,6 +21,7 @@ namespace tt::service::wifi { #define TAG "wifi_service" #define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 +#define AUTO_SCAN_INTERVAL 10000 // ms typedef enum { WifiMessageTypeRadioOn, @@ -65,6 +66,8 @@ public: /** @brief Maximum amount of records to scan (value > 0) */ uint16_t scan_list_limit = TT_WIFI_SCAN_RECORD_LIMIT; bool scan_active = false; + /** @brief when we last requested a scan. Loops around every 50 days. */ + TickType_t last_scan_time; bool secure_connection = false; esp_event_handler_instance_t event_handler_any_id = nullptr; esp_event_handler_instance_t event_handler_got_ip = nullptr; @@ -74,6 +77,7 @@ public: .password = { 0 }, .auto_connect = false }; + bool pause_auto_connect = false; // Pause when manually disconnecting until manually connecting again bool connection_target_remember = false; // Whether to store the connection_target on successful connection or not }; @@ -113,6 +117,7 @@ WifiRadioState getRadioState() { } void scan() { + TT_LOG_I(TAG, "scan()"); tt_assert(wifi_singleton); lock(wifi_singleton); WifiMessage message = {.type = WifiMessageTypeScan}; @@ -130,16 +135,19 @@ bool isScanning() { } void connect(const settings::WifiApSettings* ap, bool remember) { + TT_LOG_I(TAG, "connect(%s, %d)", ap->ssid, remember); tt_assert(wifi_singleton); lock(wifi_singleton); memcpy(&wifi_singleton->connection_target, ap, sizeof(settings::WifiApSettings)); wifi_singleton->connection_target_remember = remember; + wifi_singleton->pause_auto_connect = false; WifiMessage message = {.type = WifiMessageTypeConnect}; wifi_singleton->queue.put(&message, 100 / portTICK_PERIOD_MS); unlock(wifi_singleton); } void disconnect() { + TT_LOG_I(TAG, "disconnect()"); tt_assert(wifi_singleton); lock(wifi_singleton); wifi_singleton->connection_target = (settings::WifiApSettings) { @@ -147,12 +155,14 @@ void disconnect() { .password = { 0 }, .auto_connect = false }; + wifi_singleton->pause_auto_connect = true; WifiMessage message = {.type = WifiMessageTypeDisconnect}; wifi_singleton->queue.put(&message, 100 / portTICK_PERIOD_MS); unlock(wifi_singleton); } void setScanRecords(uint16_t records) { + TT_LOG_I(TAG, "setScanRecords(%d)", records); tt_assert(wifi_singleton); lock(wifi_singleton); if (records != wifi_singleton->scan_list_limit) { @@ -162,30 +172,30 @@ void setScanRecords(uint16_t records) { unlock(wifi_singleton); } -void getScanResults(WifiApRecord records[], uint16_t limit, uint16_t* result_count) { +std::vector getScanResults() { + TT_LOG_I(TAG, "getScanResults()"); tt_assert(wifi_singleton); - tt_assert(result_count); + + std::vector records; lock(wifi_singleton); - if (wifi_singleton->scan_list_count == 0) { - *result_count = 0; - } else { + if (wifi_singleton->scan_list_count > 0) { uint16_t i = 0; - TT_LOG_I(TAG, "processing up to %d APs", wifi_singleton->scan_list_count); - uint16_t last_index = TT_MIN(wifi_singleton->scan_list_count, limit); - for (; i < last_index; ++i) { - memcpy(records[i].ssid, wifi_singleton->scan_list[i].ssid, 33); - records[i].rssi = wifi_singleton->scan_list[i].rssi; - records[i].auth_mode = wifi_singleton->scan_list[i].authmode; + for (; i < wifi_singleton->scan_list_count; ++i) { + records.push_back((WifiApRecord) { + .ssid = (const char*)wifi_singleton->scan_list[i].ssid, + .rssi = wifi_singleton->scan_list[i].rssi, + .auth_mode = wifi_singleton->scan_list[i].authmode + }); } - // The index already overflowed right before the for-loop was terminated, - // so it effectively became the list count: - *result_count = i; } unlock(wifi_singleton); + + return records; } void setEnabled(bool enabled) { + TT_LOG_I(TAG, "setEnabled(%d)", enabled); tt_assert(wifi_singleton); lock(wifi_singleton); if (enabled) { @@ -196,7 +206,10 @@ void setEnabled(bool enabled) { WifiMessage message = {.type = WifiMessageTypeRadioOff}; // No need to lock for queue wifi_singleton->queue.put(&message, 100 / portTICK_PERIOD_MS); + // Reset pause state } + wifi_singleton->pause_auto_connect = false; + wifi_singleton->last_scan_time = 0; unlock(wifi_singleton); } @@ -282,6 +295,7 @@ static bool copy_scan_list(Wifi* wifi) { } static void auto_connect(Wifi* wifi) { + TT_LOG_I(TAG, "auto_connect()"); for (int i = 0; i < wifi->scan_list_count; ++i) { auto ssid = reinterpret_cast(wifi->scan_list[i].ssid); if (settings::contains(ssid)) { @@ -489,6 +503,7 @@ static void scan_internal(Wifi* wifi) { } if (!wifi->scan_active) { + wifi->last_scan_time = tt::get_ticks(); if (esp_wifi_scan_start(nullptr, false) == ESP_OK) { TT_LOG_I(TAG, "Starting scan"); wifi->scan_active = true; @@ -664,6 +679,18 @@ static void disconnect_internal_but_keep_active(Wifi* wifi) { TT_LOG_I(TAG, "Disconnected"); } +static bool shouldScanForAutoConnect(Wifi* wifi) { + bool is_radio_in_scannable_state = wifi->radio_state == WIFI_RADIO_ON && !wifi->scan_active; + if (!wifi->pause_auto_connect && is_radio_in_scannable_state) { + TickType_t current_time = tt::get_ticks(); + bool scan_time_has_looped = (current_time < wifi->last_scan_time); + bool no_recent_scan = (current_time - wifi->last_scan_time) > (AUTO_SCAN_INTERVAL / portTICK_PERIOD_MS); + return scan_time_has_looped || no_recent_scan; + } else { + return false; + } +} + // ESP Wi-Fi APIs need to run from the main task, so we can't just spawn a thread _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) { TT_LOG_I(TAG, "Started main loop"); @@ -678,6 +705,7 @@ _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) { WifiMessage message; while (true) { + TT_LOG_I(TAG, "Message queue %ld", queue.getCount()); if (queue.get(&message, 10000 / portTICK_PERIOD_MS) == TtStatusOk) { TT_LOG_I(TAG, "Processing message of type %d", message.type); switch (message.type) { @@ -708,7 +736,9 @@ _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) { break; case WifiMessageTypeAutoConnect: lock(wifi); - auto_connect(wifi_singleton); + if (!wifi->pause_auto_connect) { + auto_connect(wifi_singleton); + } unlock(wifi); break; } @@ -716,9 +746,9 @@ _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) { // Automatic scanning is done so we can automatically connect to access points lock(wifi); - bool should_start_scan = wifi->radio_state == WIFI_RADIO_ON && !wifi->scan_active; + bool should_auto_scan = shouldScanForAutoConnect(wifi); unlock(wifi); - if (should_start_scan) { + if (should_auto_scan) { scan_internal(wifi); } } diff --git a/TactilityHeadless/Source/service/wifi/WifiMock.cpp b/TactilityHeadless/Source/service/wifi/WifiMock.cpp index 419eebfe..9a9394e4 100644 --- a/TactilityHeadless/Source/service/wifi/WifiMock.cpp +++ b/TactilityHeadless/Source/service/wifi/WifiMock.cpp @@ -100,34 +100,41 @@ void setScanRecords(uint16_t records) { // TODO: implement } -void getScanResults(WifiApRecord records[], uint16_t limit, uint16_t* result_count) { +std::vector getScanResults() { tt_check(wifi); - tt_check(result_count); - if (limit >= 5) { - strcpy((char*)records[0].ssid, "Home WiFi"); - records[0].auth_mode = WIFI_AUTH_WPA2_PSK; - records[0].rssi = -30; - strcpy((char*)records[1].ssid, "Living Room"); - records[1].auth_mode = WIFI_AUTH_WPA2_PSK; - records[1].rssi = -67; - strcpy((char*)records[2].ssid, "No place like 127.0.0.1"); - records[2].auth_mode = WIFI_AUTH_WPA2_PSK; - records[2].rssi = -70; - strcpy((char*)records[3].ssid, "Public Wi-Fi"); - records[3].auth_mode = WIFI_AUTH_WPA2_PSK; - records[3].rssi = -80; - strcpy((char*)records[4].ssid, "Bad Reception"); - records[4].auth_mode = WIFI_AUTH_WPA2_PSK; - records[4].rssi = -90; - *result_count = 5; - } else { - *result_count = 0; - } + std::vector records; + records.push_back((WifiApRecord) { + .ssid = "Home Wifi", + .rssi = -30, + .auth_mode = WIFI_AUTH_WPA2_PSK + }); + records.push_back((WifiApRecord) { + .ssid = "Living Room", + .rssi = -67, + .auth_mode = WIFI_AUTH_WPA2_PSK + }); + records.push_back((WifiApRecord) { + .ssid = "No place like 127.0.0.1", + .rssi = -70, + .auth_mode = WIFI_AUTH_WPA2_PSK + }); + records.push_back((WifiApRecord) { + .ssid = "Public Wi-Fi", + .rssi = -80, + .auth_mode = WIFI_AUTH_WPA2_PSK + }); + records.push_back((WifiApRecord) { + .ssid = "Bad Reception", + .rssi = -90, + .auth_mode = WIFI_AUTH_OPEN + }); + + return records; } void setEnabled(bool enabled) { - tt_assert(wifi != NULL); + tt_assert(wifi != nullptr); if (enabled) { wifi->radio_state = WIFI_RADIO_ON; wifi->secure_connection = true;