diff --git a/app-sim/src/lv_conf.h b/app-sim/src/lv_conf.h index facf78d8..d67011c4 100644 --- a/app-sim/src/lv_conf.h +++ b/app-sim/src/lv_conf.h @@ -572,8 +572,8 @@ /*API for fopen, fread, etc*/ #define LV_USE_FS_STDIO 1 #if LV_USE_FS_STDIO - #define LV_FS_STDIO_LETTER 'A' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ - #define LV_FS_STDIO_PATH "" /*Set the working directory. File/directory paths will be appended to it.*/ + #define LV_FS_STDIO_LETTER 'A' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/ + #define LV_FS_STDIO_PATH "." /*Set the working directory. File/directory paths will be appended to it.*/ #define LV_FS_STDIO_CACHE_SIZE 0 /*>0 to cache this number of bytes in lv_fs_read()*/ #endif diff --git a/boards/lilygo_tdeck/sdcard.c b/boards/lilygo_tdeck/sdcard.c index c662c4e6..93d896e4 100644 --- a/boards/lilygo_tdeck/sdcard.c +++ b/boards/lilygo_tdeck/sdcard.c @@ -54,7 +54,7 @@ static bool sdcard_init() { return true; } -static void* sdcard_mount(const char* mount_point) { +static void* _Nullable sdcard_mount(const char* mount_point) { TT_LOG_I(TAG, "Mounting %s", mount_point); esp_vfs_fat_sdmmc_mount_config_t mount_config = { @@ -64,8 +64,6 @@ static void* sdcard_mount(const char* mount_point) { .disk_status_check_enable = TDECK_SDCARD_STATUS_CHECK_ENABLED }; - sdmmc_card_t* card; - // Init without card detect (CD) and write protect (WD) sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT(); slot_config.gpio_cs = TDECK_SDCARD_PIN_CS; @@ -76,6 +74,8 @@ static void* sdcard_mount(const char* mount_point) { // https://github.com/Xinyuan-LilyGO/T-Deck/blob/master/examples/UnitTest/UnitTest.ino // Observation: Using this automatically sets the bus to 20MHz host.max_freq_khz = TDECK_SDCARD_SPI_FREQUENCY; + + sdmmc_card_t* card; esp_err_t ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card); if (ret != ESP_OK) { @@ -101,7 +101,6 @@ static void* sdcard_init_and_mount(const char* mount_point) { TT_LOG_E(TAG, "Failed to set SPI CS pins high. This is a pre-requisite for mounting."); return NULL; } - MountData* data = sdcard_mount(mount_point); if (data == NULL) { TT_LOG_E(TAG, "Mount failed for %s", mount_point); @@ -125,8 +124,14 @@ static void sdcard_unmount(void* context) { free(data); } +static bool sdcard_is_mounted(void* context) { + MountData* data = (MountData*)context; + return (data != NULL) && (sdmmc_get_status(data->card) == ESP_OK); +} + const SdCard tdeck_sdcard = { .mount = &sdcard_init_and_mount, .unmount = &sdcard_unmount, + .is_mounted = &sdcard_is_mounted, .mount_behaviour = SDCARD_MOUNT_BEHAVIOUR_AT_BOOT }; diff --git a/boards/yellow_board/sdcard.c b/boards/yellow_board/sdcard.c index c8cc18e1..d9aaec08 100644 --- a/boards/yellow_board/sdcard.c +++ b/boards/yellow_board/sdcard.c @@ -66,8 +66,14 @@ static void sdcard_unmount(void* context) { free(data); } +static bool sdcard_is_mounted(void* context) { + MountData* data = (MountData*)context; + return (data != NULL) && (sdmmc_get_status(data->card) == ESP_OK); +} + const SdCard twodotfour_sdcard = { .mount = &sdcard_mount, .unmount = &sdcard_unmount, + .is_mounted = &sdcard_is_mounted, .mount_behaviour = SDCARD_MOUNT_BEHAVIOUR_ANYTIME }; diff --git a/data/assets/sdcard.png b/data/assets/sdcard.png new file mode 100644 index 00000000..6c222e11 Binary files /dev/null and b/data/assets/sdcard.png differ diff --git a/data/assets/sdcard_alert.png b/data/assets/sdcard_alert.png new file mode 100644 index 00000000..933c8465 Binary files /dev/null and b/data/assets/sdcard_alert.png differ diff --git a/data/assets/wifi_connection_issue.png b/data/assets/wifi_connection_issue.png new file mode 100644 index 00000000..5c79dbdb Binary files /dev/null and b/data/assets/wifi_connection_issue.png differ diff --git a/data/assets/wifi_find.png b/data/assets/wifi_find.png new file mode 100644 index 00000000..f20ab74f Binary files /dev/null and b/data/assets/wifi_find.png differ diff --git a/data/assets/wifi_off.png b/data/assets/wifi_off.png new file mode 100644 index 00000000..983b1792 Binary files /dev/null and b/data/assets/wifi_off.png differ diff --git a/data/assets/wifi_perm_scan.png b/data/assets/wifi_perm_scan.png new file mode 100644 index 00000000..c6b668d7 Binary files /dev/null and b/data/assets/wifi_perm_scan.png differ diff --git a/data/assets/wifi_signal_0.png b/data/assets/wifi_signal_0.png new file mode 100644 index 00000000..964d0ee2 Binary files /dev/null and b/data/assets/wifi_signal_0.png differ diff --git a/data/assets/wifi_signal_0_lock.png b/data/assets/wifi_signal_0_lock.png new file mode 100644 index 00000000..6c569446 Binary files /dev/null and b/data/assets/wifi_signal_0_lock.png differ diff --git a/data/assets/wifi_signal_1.png b/data/assets/wifi_signal_1.png new file mode 100644 index 00000000..7799eeda Binary files /dev/null and b/data/assets/wifi_signal_1.png differ diff --git a/data/assets/wifi_signal_1_locked.png b/data/assets/wifi_signal_1_locked.png new file mode 100644 index 00000000..7f3759d7 Binary files /dev/null and b/data/assets/wifi_signal_1_locked.png differ diff --git a/data/assets/wifi_signal_2.png b/data/assets/wifi_signal_2.png new file mode 100644 index 00000000..1da91111 Binary files /dev/null and b/data/assets/wifi_signal_2.png differ diff --git a/data/assets/wifi_signal_2_locked.png b/data/assets/wifi_signal_2_locked.png new file mode 100644 index 00000000..d26417f4 Binary files /dev/null and b/data/assets/wifi_signal_2_locked.png differ diff --git a/data/assets/wifi_signal_3.png b/data/assets/wifi_signal_3.png new file mode 100644 index 00000000..89ff66b2 Binary files /dev/null and b/data/assets/wifi_signal_3.png differ diff --git a/data/assets/wifi_signal_3_locked.png b/data/assets/wifi_signal_3_locked.png new file mode 100644 index 00000000..40d4b10a Binary files /dev/null and b/data/assets/wifi_signal_3_locked.png differ diff --git a/data/assets/wifi_signal_4.png b/data/assets/wifi_signal_4.png new file mode 100644 index 00000000..e5b1b108 Binary files /dev/null and b/data/assets/wifi_signal_4.png differ diff --git a/data/assets/wifi_signal_4_locked.png b/data/assets/wifi_signal_4_locked.png new file mode 100644 index 00000000..c08dfc89 Binary files /dev/null and b/data/assets/wifi_signal_4_locked.png differ diff --git a/data/assets_sources/sdcard.svg b/data/assets_sources/sdcard.svg new file mode 100644 index 00000000..d250daab --- /dev/null +++ b/data/assets_sources/sdcard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/sdcard_alert.svg b/data/assets_sources/sdcard_alert.svg new file mode 100644 index 00000000..565c6856 --- /dev/null +++ b/data/assets_sources/sdcard_alert.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_connection_issue.svg b/data/assets_sources/wifi_connection_issue.svg new file mode 100644 index 00000000..0c527912 --- /dev/null +++ b/data/assets_sources/wifi_connection_issue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_find.svg b/data/assets_sources/wifi_find.svg new file mode 100644 index 00000000..97f271a4 --- /dev/null +++ b/data/assets_sources/wifi_find.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_off.svg b/data/assets_sources/wifi_off.svg new file mode 100644 index 00000000..bd0d4cc2 --- /dev/null +++ b/data/assets_sources/wifi_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_perm_scan.svg b/data/assets_sources/wifi_perm_scan.svg new file mode 100644 index 00000000..71708f75 --- /dev/null +++ b/data/assets_sources/wifi_perm_scan.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_0.svg b/data/assets_sources/wifi_signal_0.svg new file mode 100644 index 00000000..63c9ecfb --- /dev/null +++ b/data/assets_sources/wifi_signal_0.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_0_lock.svg b/data/assets_sources/wifi_signal_0_lock.svg new file mode 100644 index 00000000..50b38476 --- /dev/null +++ b/data/assets_sources/wifi_signal_0_lock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_1.svg b/data/assets_sources/wifi_signal_1.svg new file mode 100644 index 00000000..9cc573d1 --- /dev/null +++ b/data/assets_sources/wifi_signal_1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_1_locked.svg b/data/assets_sources/wifi_signal_1_locked.svg new file mode 100644 index 00000000..c8a7e5a9 --- /dev/null +++ b/data/assets_sources/wifi_signal_1_locked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_2.svg b/data/assets_sources/wifi_signal_2.svg new file mode 100644 index 00000000..dee8e30b --- /dev/null +++ b/data/assets_sources/wifi_signal_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_2_locked.svg b/data/assets_sources/wifi_signal_2_locked.svg new file mode 100644 index 00000000..075d61d5 --- /dev/null +++ b/data/assets_sources/wifi_signal_2_locked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_3.svg b/data/assets_sources/wifi_signal_3.svg new file mode 100644 index 00000000..f9709047 --- /dev/null +++ b/data/assets_sources/wifi_signal_3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_3_locked.svg b/data/assets_sources/wifi_signal_3_locked.svg new file mode 100644 index 00000000..82f7bf33 --- /dev/null +++ b/data/assets_sources/wifi_signal_3_locked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_4.svg b/data/assets_sources/wifi_signal_4.svg new file mode 100644 index 00000000..92d41ac4 --- /dev/null +++ b/data/assets_sources/wifi_signal_4.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_4_locked.svg b/data/assets_sources/wifi_signal_4_locked.svg new file mode 100644 index 00000000..9e22d11a --- /dev/null +++ b/data/assets_sources/wifi_signal_4_locked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/assets_sources/wifi_signal_5.svg b/data/assets_sources/wifi_signal_5.svg new file mode 100644 index 00000000..249ab46f --- /dev/null +++ b/data/assets_sources/wifi_signal_5.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tactility-esp/config/placeholder.txt b/data/config/placeholder.txt similarity index 100% rename from tactility-esp/config/placeholder.txt rename to data/config/placeholder.txt diff --git a/tactility-core/src/pubsub.c b/tactility-core/src/pubsub.c index 7bb65f7f..4fcfc227 100644 --- a/tactility-core/src/pubsub.c +++ b/tactility-core/src/pubsub.c @@ -13,7 +13,7 @@ LIST_DEF(PubSubSubscriptionList, PubSubSubscription, M_POD_OPLIST); struct PubSub { PubSubSubscriptionList_t items; - Mutex* mutex; + Mutex mutex; }; PubSub* tt_pubsub_alloc() { diff --git a/tactility-core/src/thread.c b/tactility-core/src/thread.c index 0ce968b5..21c732b2 100644 --- a/tactility-core/src/thread.c +++ b/tactility-core/src/thread.c @@ -80,7 +80,6 @@ static void tt_thread_body(void* context) { tt_thread_set_state(thread, ThreadStateRunning); thread->ret = thread->callback(thread->context); - TT_LOG_I(TAG, "thread returned: %s", thread->name ?: "[no name]"); tt_assert(thread->state == ThreadStateRunning); @@ -170,7 +169,7 @@ void tt_thread_mark_as_static(Thread* thread) { thread->is_static = true; } -bool tt_thread_mark_is_service(ThreadId thread_id) { +bool tt_thread_mark_is_static(ThreadId thread_id) { TaskHandle_t hTask = (TaskHandle_t)thread_id; assert(!TT_IS_IRQ_MODE() && (hTask != NULL)); Thread* thread = (Thread*)pvTaskGetThreadLocalStoragePointer(hTask, 0); diff --git a/tactility-core/src/thread.h b/tactility-core/src/thread.h index c04b5795..707c6fe2 100644 --- a/tactility-core/src/thread.h +++ b/tactility-core/src/thread.h @@ -275,7 +275,12 @@ void tt_thread_resume(ThreadId thread_id); */ bool tt_thread_is_suspended(ThreadId thread_id); -bool tt_thread_mark_is_service(ThreadId thread_id); +/** Check if the thread was created with static memory + * + * @param thread_id thread id + * @return true if thread memory is static + */ +bool tt_thread_mark_is_static(ThreadId thread_id); #ifdef __cplusplus } diff --git a/tactility-esp/CMakeLists.txt b/tactility-esp/CMakeLists.txt index 66214679..c759af9e 100644 --- a/tactility-esp/CMakeLists.txt +++ b/tactility-esp/CMakeLists.txt @@ -10,10 +10,10 @@ idf_component_register( REQUIRES esp_wifi nvs_flash spiffs ) -set(ASSETS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets") +set(ASSETS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../data/assets") spiffs_create_partition_image(assets ${ASSETS_SRC_DIR} FLASH_IN_PROJECT) -set(CONFIG_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/config") +set(CONFIG_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../data/config") spiffs_create_partition_image(config ${CONFIG_SRC_DIR} FLASH_IN_PROJECT) target_link_libraries(${COMPONENT_LIB} ${IDF_TARGET_NAME} tactility) diff --git a/tactility-esp/assets/ic_small_wifi_off.png b/tactility-esp/assets/ic_small_wifi_off.png deleted file mode 100644 index c27a2815..00000000 Binary files a/tactility-esp/assets/ic_small_wifi_off.png and /dev/null differ diff --git a/tactility-esp/assets/ic_small_wifi_on.png b/tactility-esp/assets/ic_small_wifi_on.png deleted file mode 100644 index 7e3141c8..00000000 Binary files a/tactility-esp/assets/ic_small_wifi_on.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi.png b/tactility-esp/assets/network_wifi.png deleted file mode 100644 index 00c107a1..00000000 Binary files a/tactility-esp/assets/network_wifi.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi_1_bar.png b/tactility-esp/assets/network_wifi_1_bar.png deleted file mode 100644 index a181c191..00000000 Binary files a/tactility-esp/assets/network_wifi_1_bar.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi_1_bar_locked.png b/tactility-esp/assets/network_wifi_1_bar_locked.png deleted file mode 100644 index 1b59d794..00000000 Binary files a/tactility-esp/assets/network_wifi_1_bar_locked.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi_2_bar.png b/tactility-esp/assets/network_wifi_2_bar.png deleted file mode 100644 index 82b45eb4..00000000 Binary files a/tactility-esp/assets/network_wifi_2_bar.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi_2_bar_locked.png b/tactility-esp/assets/network_wifi_2_bar_locked.png deleted file mode 100644 index ca2c8f67..00000000 Binary files a/tactility-esp/assets/network_wifi_2_bar_locked.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi_3_bar.png b/tactility-esp/assets/network_wifi_3_bar.png deleted file mode 100644 index c07627de..00000000 Binary files a/tactility-esp/assets/network_wifi_3_bar.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi_3_bar_locked.png b/tactility-esp/assets/network_wifi_3_bar_locked.png deleted file mode 100644 index b9596cfe..00000000 Binary files a/tactility-esp/assets/network_wifi_3_bar_locked.png and /dev/null differ diff --git a/tactility-esp/assets/network_wifi_locked.png b/tactility-esp/assets/network_wifi_locked.png deleted file mode 100644 index cfd4f35c..00000000 Binary files a/tactility-esp/assets/network_wifi_locked.png and /dev/null differ diff --git a/tactility-esp/assets/sdcard_mounted.png b/tactility-esp/assets/sdcard_mounted.png deleted file mode 100644 index 472f12f7..00000000 Binary files a/tactility-esp/assets/sdcard_mounted.png and /dev/null differ diff --git a/tactility-esp/assets/sdcard_unmounted.png b/tactility-esp/assets/sdcard_unmounted.png deleted file mode 100644 index 27e9a151..00000000 Binary files a/tactility-esp/assets/sdcard_unmounted.png and /dev/null differ diff --git a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.c b/tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.c index 1d5270e4..063b15e4 100644 --- a/tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.c +++ b/tactility-esp/src/apps/system/wifi_manage/wifi_manage_view.c @@ -26,30 +26,6 @@ static void on_disconnect_pressed(lv_event_t* event) { // region Secondary updates -static const char* get_network_icon(int8_t rssi, wifi_auth_mode_t auth_mode) { - if (rssi > -67) { - if (auth_mode == WIFI_AUTH_OPEN) - return "A:/assets/network_wifi.png"; - else - return "A:/assets/network_wifi_locked.png"; - } else if (rssi > -70) { - if (auth_mode == WIFI_AUTH_OPEN) - return "A:/assets/network_wifi_3_bar.png"; - else - return "A:/assets/network_wifi_3_bar_locked.png"; - } else if (rssi > -80) { - if (auth_mode == WIFI_AUTH_OPEN) - return "A:/assets/network_wifi_2_bar.png"; - else - return "A:/assets/network_wifi_2_bar_locked.png"; - } else { - if (auth_mode == WIFI_AUTH_OPEN) - return "A:/assets/network_wifi_1_bar.png"; - else - return "A:/assets/network_wifi_1_bar_locked.png"; - } -} - static void connect(lv_event_t* event) { lv_obj_t* button = event->current_target; // Assumes that the second child of the button is a label ... risky @@ -64,7 +40,7 @@ static void connect(lv_event_t* event) { static void create_network_button(WifiManageView* view, WifiManageBindings* bindings, WifiApRecord* record) { const char* ssid = (const char*)record->ssid; - const char* icon = get_network_icon(record->rssi, record->auth_mode); + const char* icon = wifi_get_status_icon_for_rssi(record->rssi, record->auth_mode != WIFI_AUTH_OPEN); lv_obj_t* ap_button = lv_list_add_btn( view->networks_list, icon, diff --git a/tactility-esp/src/services/wifi/wifi.c b/tactility-esp/src/services/wifi/wifi.c index 45d57a8d..7984b5c9 100644 --- a/tactility-esp/src/services/wifi/wifi.c +++ b/tactility-esp/src/services/wifi/wifi.c @@ -1,5 +1,6 @@ #include "wifi.h" +#include "assets.h" #include "check.h" #include "freertos/FreeRTOS.h" #include "freertos/event_groups.h" @@ -33,10 +34,12 @@ typedef struct { uint16_t scan_list_limit; int8_t statusbar_icon_id; bool scan_active; + bool secure_connection; esp_event_handler_instance_t event_handler_any_id; esp_event_handler_instance_t event_handler_got_ip; EventGroupHandle_t event_group; WifiRadioState radio_state; + const char* _Nullable last_statusbar_icon; } Wifi; typedef enum { @@ -86,7 +89,9 @@ static Wifi* wifi_alloc() { instance->event_handler_got_ip = NULL; instance->event_group = xEventGroupCreate(); instance->radio_state = WIFI_RADIO_OFF; - instance->statusbar_icon_id = tt_statusbar_icon_add("A:/assets/ic_small_wifi_off.png"); + instance->statusbar_icon_id = tt_statusbar_icon_add(TT_ASSETS_ICON_WIFI_OFF); + instance->last_statusbar_icon = NULL; + instance->secure_connection = false; return instance; } @@ -225,35 +230,6 @@ static void wifi_scan_list_free_safely(Wifi* wifi) { static void wifi_publish_event_simple(Wifi* wifi, WifiEventType type) { WifiEvent turning_on_event = {.type = type}; - switch (type) { - case WifiEventTypeRadioStateOn: - break; - case WifiEventTypeRadioStateOnPending: - break; - case WifiEventTypeRadioStateOff: - tt_statusbar_icon_set_image(wifi->statusbar_icon_id, "A:/assets/ic_small_wifi_off.png"); - break; - case WifiEventTypeRadioStateOffPending: - break; - case WifiEventTypeScanStarted: - break; - case WifiEventTypeScanFinished: - break; - case WifiEventTypeDisconnected: - tt_statusbar_icon_set_image(wifi->statusbar_icon_id, "A:/assets/ic_small_wifi_off.png"); - break; - case WifiEventTypeConnectionPending: - tt_statusbar_icon_set_image(wifi->statusbar_icon_id, "A:/assets/network_wifi_1_bar.png"); - break; - case WifiEventTypeConnectionSuccess: - // TODO: update with actual bars - tt_statusbar_icon_set_image(wifi->statusbar_icon_id, "A:/assets/network_wifi.png"); - break; - case WifiEventTypeConnectionFailed: - tt_statusbar_icon_set_image(wifi->statusbar_icon_id, "A:/assets/ic_small_wifi_off.png"); - break; - } - tt_pubsub_publish(wifi->pubsub, &turning_on_event); } @@ -266,6 +242,8 @@ static void event_handler(TT_UNUSED void* arg, esp_event_base_t event_base, int3 } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { xEventGroupSetBits(wifi_singleton->event_group, WIFI_FAIL_BIT); TT_LOG_I(TAG, "event_handler: disconnected"); + wifi_singleton->radio_state = WIFI_RADIO_ON; + wifi_publish_event_simple(wifi_singleton, WifiEventTypeDisconnected); } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { ip_event_got_ip_t* event = (ip_event_got_ip_t*)event_data; TT_LOG_I(TAG, "event_handler: got ip:" IPSTR, IP2STR(&event->ip_info.ip)); @@ -444,6 +422,47 @@ static void wifi_scan_internal(Wifi* wifi) { TT_LOG_I(TAG, "Finished scan"); } +const char* wifi_get_status_icon_for_rssi(int rssi, bool secured) { + if (rssi > -67) { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_4_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_4; + } else if (rssi > -70) { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_3_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_3; + } else if (rssi > -80) { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_2_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_2; + } else { + return secured ? TT_ASSETS_ICON_WIFI_SIGNAL_1_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_1; + } +} + +static const char* wifi_get_status_icon(WifiRadioState state, bool secure) { + static int rssi = 0; + switch (state) { + case WIFI_RADIO_ON_PENDING: + case WIFI_RADIO_ON: + case WIFI_RADIO_OFF_PENDING: + case WIFI_RADIO_OFF: + return TT_ASSETS_ICON_WIFI_OFF; + case WIFI_RADIO_CONNECTION_PENDING: + return TT_ASSETS_ICON_WIFI_FIND; + case WIFI_RADIO_CONNECTION_ACTIVE: + if (esp_wifi_sta_get_rssi(&rssi) == ESP_OK) { + return wifi_get_status_icon_for_rssi(rssi, secure); + } else { + return secure ? TT_ASSETS_ICON_WIFI_SIGNAL_0_LOCKED : TT_ASSETS_ICON_WIFI_SIGNAL_0; + } + default: + tt_crash_implementation("not implemented"); + } +} + +static void wifi_update_statusbar(Wifi* wifi) { + const char* icon = wifi_get_status_icon(wifi->radio_state, wifi->secure_connection); + if (icon != wifi->last_statusbar_icon) { + tt_statusbar_icon_set_image(wifi->statusbar_icon_id, icon); + wifi->last_statusbar_icon = icon; + } +} + static void wifi_connect_internal(Wifi* wifi, WifiConnectMessage* connect_message) { // TODO: only when connected! wifi_disconnect_internal(wifi); @@ -467,6 +486,8 @@ static void wifi_connect_internal(Wifi* wifi, WifiConnectMessage* connect_messag memcpy(wifi_config.sta.ssid, connect_message->ssid, 32); memcpy(wifi_config.sta.password, connect_message->password, 64); + wifi->secure_connection = (wifi_config.sta.password[0] != 0x00); + esp_err_t set_config_result = esp_wifi_set_config(WIFI_IF_STA, &wifi_config); if (set_config_result != ESP_OK) { wifi->radio_state = WIFI_RADIO_ON; @@ -589,6 +610,8 @@ _Noreturn int32_t wifi_main(TT_UNUSED void* parameter) { break; } } + + wifi_update_statusbar(wifi); } } diff --git a/tactility-esp/src/services/wifi/wifi.h b/tactility-esp/src/services/wifi/wifi.h index 76794445..4d543685 100644 --- a/tactility-esp/src/services/wifi/wifi.h +++ b/tactility-esp/src/services/wifi/wifi.h @@ -62,6 +62,9 @@ WifiRadioState wifi_get_radio_state(); */ void wifi_scan(); +/** + * @return true if wifi is actively scanning + */ bool wifi_is_scanning(); /** @@ -96,6 +99,14 @@ void wifi_connect(const char* ssid, const char _Nullable password[64]); */ void wifi_disconnect(); +/** + * Return the relevant icon asset from assets.h for the given inputs + * @param rssi the rssi value + * @param secured whether the access point is a secured one (as in: not an open one) + * @return + */ +const char* wifi_get_status_icon_for_rssi(int rssi, bool secured); + #ifdef __cplusplus } #endif diff --git a/tactility/src/app.c b/tactility/src/app.c index 25a3858b..b9370cbc 100644 --- a/tactility/src/app.c +++ b/tactility/src/app.c @@ -1,7 +1,10 @@ #include "app_i.h" +#include "log.h" #include +#define TAG "app" + static AppFlags tt_app_get_flags_default(AppType type); static const AppFlags DEFAULT_FLAGS = { @@ -11,6 +14,11 @@ static const AppFlags DEFAULT_FLAGS = { // region Alloc/free App tt_app_alloc(const AppManifest* manifest, Bundle* _Nullable parameters) { +#ifdef ESP_PLATFORM + size_t memory_before = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); +#else + size_t memory_before = 0; +#endif AppData* data = malloc(sizeof(AppData)); *data = (AppData) { .mutex = tt_mutex_alloc(MutexTypeNormal), @@ -18,6 +26,7 @@ App tt_app_alloc(const AppManifest* manifest, Bundle* _Nullable parameters) { .flags = tt_app_get_flags_default(manifest->type), .manifest = manifest, .parameters = parameters, + .memory = memory_before, .data = NULL }; return (App*)data; @@ -25,11 +34,25 @@ App tt_app_alloc(const AppManifest* manifest, Bundle* _Nullable parameters) { void tt_app_free(App app) { AppData* data = (AppData*)app; + + size_t memory_before = data->memory; + if (data->parameters) { tt_bundle_free(data->parameters); } tt_mutex_free(data->mutex); free(data); + +#ifdef ESP_PLATFORM + size_t memory_after = heap_caps_get_free_size(MALLOC_CAP_INTERNAL); +#else + size_t memory_after = 0; +#endif + + if (memory_after < memory_before) { + TT_LOG_W(TAG, "Potential memory leak: gained %u bytes after closing app", memory_before - memory_after); + TT_LOG_W(TAG, "Note that WiFi service frees up memory asynchronously and that the leak can be caused by an app that was launched by this app."); + } } // endregion diff --git a/tactility/src/app_i.h b/tactility/src/app_i.h index 97573586..d64a9e98 100644 --- a/tactility/src/app_i.h +++ b/tactility/src/app_i.h @@ -14,6 +14,8 @@ typedef struct { Mutex mutex; const AppManifest* manifest; AppState state; + /** @brief Memory marker at start of app, to detect memory leaks */ + size_t memory; AppFlags flags; /** @brief Optional parameters to start the app with * When these are stored in the app struct, the struct takes ownership. diff --git a/tactility/src/assets.h b/tactility/src/assets.h new file mode 100644 index 00000000..2d7c9605 --- /dev/null +++ b/tactility/src/assets.h @@ -0,0 +1,22 @@ +#pragma once + +#define TT_ASSET_FOLDER "A:/assets/" +#define TT_ASSET(file) TT_ASSET_FOLDER file + +#define TT_ASSETS_ICON_SDCARD TT_ASSET("sdcard.png") +#define TT_ASSETS_ICON_SDCARD_ALERT TT_ASSET("sdcard_alert.png") + +#define TT_ASSETS_ICON_WIFI_CONNECTION_ISSUE TT_ASSET("wifi_connection_issue.png") +#define TT_ASSETS_ICON_WIFI_FIND TT_ASSET("wifi_find.png") +#define TT_ASSETS_ICON_WIFI_OFF TT_ASSET("wifi_off.png") +#define TT_ASSETS_ICON_WIFI_PERM_SCAN TT_ASSET("wifi_perm_scan.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_0 TT_ASSET("wifi_signal_0.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_0_LOCKED TT_ASSET("wifi_signal_0_locked.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_1 TT_ASSET("wifi_signal_1.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_1_LOCKED TT_ASSET("wifi_signal_1_locked.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_2 TT_ASSET("wifi_signal_2.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_2_LOCKED TT_ASSET("wifi_signal_2_locked.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_3 TT_ASSET("wifi_signal_3.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_3_LOCKED TT_ASSET("wifi_signal_3_locked.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_4 TT_ASSET("wifi_signal_4.png") +#define TT_ASSETS_ICON_WIFI_SIGNAL_4_LOCKED TT_ASSET("wifi_signal_4_locked.png") diff --git a/tactility/src/hardware.c b/tactility/src/hardware.c index 15ff0931..7d1fa4e6 100644 --- a/tactility/src/hardware.c +++ b/tactility/src/hardware.c @@ -1,4 +1,5 @@ #include "hardware_i.h" +#include "sdcard_i.h" #define TAG "hardware" @@ -12,6 +13,7 @@ void tt_hardware_init(const HardwareConfig* config) { tt_check(config->bootstrap(), "bootstrap failed"); } + tt_sdcard_init(); if (config->sdcard != NULL) { TT_LOG_I(TAG, "Mounting sdcard"); tt_sdcard_mount(config->sdcard); diff --git a/tactility/src/sdcard.c b/tactility/src/sdcard.c index 3bf5eca4..b04a86e3 100644 --- a/tactility/src/sdcard.c +++ b/tactility/src/sdcard.c @@ -2,12 +2,10 @@ #include "mutex.h" #include "tactility_core.h" -#include "ui/statusbar.h" #define TAG "sdcard" -static Mutex* mutex = NULL; -static int8_t statusbar_icon = -1; +static Mutex mutex = NULL; typedef struct { const SdCard* sdcard; @@ -19,15 +17,13 @@ static MountData data = { .context = NULL }; -static void sdcard_ensure_initialized() { +void tt_sdcard_init() { if (mutex == NULL) { mutex = tt_mutex_alloc(MutexTypeRecursive); - statusbar_icon = tt_statusbar_icon_add("A:/assets/sdcard_unmounted.png"); } } static bool sdcard_lock(uint32_t timeout_ticks) { - sdcard_ensure_initialized(); return tt_mutex_acquire(mutex, timeout_ticks) == TtStatusOk; } @@ -51,7 +47,6 @@ bool tt_sdcard_mount(const SdCard* sdcard) { }; sdcard_unlock(); if (data.context != NULL) { - tt_statusbar_icon_set_image(statusbar_icon, "A:/assets/sdcard_mounted.png"); return true; } else { return false; @@ -62,8 +57,19 @@ bool tt_sdcard_mount(const SdCard* sdcard) { } } -bool tt_sdcard_is_mounted() { - return data.context != NULL; +SdcardState tt_sdcard_get_state() { + if (data.context == NULL) { + return SDCARD_STATE_UNMOUNTED; + } else { + // TODO: Side-effects are not great - consider refactoring this, so: + // Consider making tt_sdcard_get_status() that can return an error state + // The sdcard service can then auto-dismount + if (data.sdcard->is_mounted(data.context)) { + return SDCARD_STATE_MOUNTED; + } else { + return SDCARD_STATE_ERROR; + } + } } bool tt_sdcard_unmount(uint32_t timeout_ticks) { @@ -78,7 +84,6 @@ bool tt_sdcard_unmount(uint32_t timeout_ticks) { .sdcard = NULL }; result = true; - tt_statusbar_icon_set_image(statusbar_icon, "A:/assets/sdcard_unmounted.png"); } else { TT_LOG_E(TAG, "Can't unmount: nothing mounted"); } diff --git a/tactility/src/sdcard.h b/tactility/src/sdcard.h index 9a9de7f6..afd1a1bd 100644 --- a/tactility/src/sdcard.h +++ b/tactility/src/sdcard.h @@ -9,7 +9,14 @@ extern "C" { #endif typedef void* (*SdcardMount)(const char* mount_path); -typedef void (*SdcardUnmount)(void*); +typedef void (*SdcardUnmount)(void* context); +typedef bool (*SdcardIsMounted)(void* context); + +typedef enum { + SDCARD_STATE_MOUNTED, + SDCARD_STATE_UNMOUNTED, + SDCARD_STATE_ERROR, +} SdcardState; typedef enum { SDCARD_MOUNT_BEHAVIOUR_AT_BOOT, /** Only mount at boot */ @@ -19,11 +26,12 @@ typedef enum { typedef struct { SdcardMount mount; SdcardUnmount unmount; + SdcardIsMounted is_mounted; SdcardMountBehaviour mount_behaviour; } SdCard; bool tt_sdcard_mount(const SdCard* sdcard); -bool tt_sdcard_is_mounted(); +SdcardState tt_sdcard_get_state(); bool tt_sdcard_unmount(); #ifdef __cplusplus diff --git a/tactility/src/sdcard_i.h b/tactility/src/sdcard_i.h new file mode 100644 index 00000000..ce953c00 --- /dev/null +++ b/tactility/src/sdcard_i.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void tt_sdcard_init(); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/tactility/src/services/sdcard/sdcard.c b/tactility/src/services/sdcard/sdcard.c new file mode 100644 index 00000000..9aadf0dd --- /dev/null +++ b/tactility/src/services/sdcard/sdcard.c @@ -0,0 +1,117 @@ +#include + +#include "assets.h" +#include "mutex.h" +#include "service.h" +#include "tactility.h" +#include "tactility_core.h" +#include "ui/statusbar.h" + +#define TAG "sdcard_service" + +static int32_t sdcard_task(TT_UNUSED void* context); + +typedef struct { + Mutex mutex; + Thread* thread; + SdcardState last_state; + int8_t statusbar_icon_id; + bool interrupted; +} ServiceData; + +static ServiceData* service_data_alloc() { + ServiceData* data = malloc(sizeof(ServiceData)); + *data = (ServiceData) { + .mutex = tt_mutex_alloc(MutexTypeNormal), + .thread = tt_thread_alloc_ex( + "sdcard", + 3000, // Minimum is ~2800 @ ESP-IDF 5.1.2 when ejecting sdcard + &sdcard_task, + data + ), + .last_state = -1, + .statusbar_icon_id = tt_statusbar_icon_add(NULL), + .interrupted = false + }; + return data; +} + +static void service_data_free(ServiceData* data) { + tt_mutex_free(data->mutex); + tt_statusbar_icon_remove(data->statusbar_icon_id); + tt_thread_free(data->thread); +} + +static void service_data_lock(ServiceData* data) { + tt_check(tt_mutex_acquire(data->mutex, TtWaitForever) == TtStatusOk); +} + +static void service_data_unlock(ServiceData* data) { + tt_check(tt_mutex_release(data->mutex) == TtStatusOk); +} + +static int32_t sdcard_task(void* context) { + ServiceData* data = (ServiceData*)context; + + bool interrupted = false; + + // We set NULL as statusbar image by default, so it's hidden by default + tt_statusbar_icon_set_visibility(data->statusbar_icon_id, true); + + do { + service_data_lock(data); + + interrupted = data->interrupted; + + SdcardState new_state = tt_sdcard_get_state(); + + if (new_state == SDCARD_STATE_ERROR) { + TT_LOG_W(TAG, "Sdcard error - unmounting. Did you eject the card in an unsafe manner?"); + tt_sdcard_unmount(); + } + + if (new_state != data->last_state) { + TT_LOG_I(TAG, "State change %d -> %d", data->last_state, new_state); + if (new_state == SDCARD_STATE_MOUNTED) { + tt_statusbar_icon_set_image(data->statusbar_icon_id, TT_ASSETS_ICON_SDCARD); + } else { + tt_statusbar_icon_set_image(data->statusbar_icon_id, TT_ASSETS_ICON_SDCARD_ALERT); + } + data->last_state = new_state; + } + + service_data_unlock(data); + tt_delay_ms(2000); + } while (!interrupted); + + return 0; +} + +static void on_start(Service service) { + if (tt_get_config()->hardware->sdcard != NULL) { + ServiceData* data = service_data_alloc(); + tt_service_set_data(service, data); + tt_thread_start(data->thread); + } else { + TT_LOG_I(TAG, "task not started due to config"); + } +} + +static void on_stop(Service service) { + ServiceData* data = tt_service_get_data(service); + if (data != NULL) { + service_data_lock(data); + data->interrupted = true; + service_data_unlock(data); + + tt_thread_join(data->thread); + + service_data_free(data); + } +} + +const ServiceManifest sdcard_service = { + .id = "sdcard", + .on_start = &on_start, + .on_stop = &on_stop +}; diff --git a/tactility/src/tactility.c b/tactility/src/tactility.c index 4123ebb7..581b2924 100644 --- a/tactility/src/tactility.c +++ b/tactility/src/tactility.c @@ -14,10 +14,12 @@ static const Config* config_instance = NULL; extern const ServiceManifest gui_service; extern const ServiceManifest loader_service; +extern const ServiceManifest sdcard_service; static const ServiceManifest* const system_services[] = { &gui_service, - &loader_service // depends on gui service + &loader_service, // depends on gui service + &sdcard_service }; // endregion @@ -87,6 +89,9 @@ static void register_and_start_user_services(const ServiceManifest* const servic TT_UNUSED void tt_init(const Config* config) { TT_LOG_I(TAG, "tt_init started"); + // Assign early so starting services can use it + config_instance = config; + tt_service_registry_init(); tt_app_manifest_registry_init(); @@ -122,8 +127,6 @@ TT_UNUSED void tt_init(const Config* config) { } TT_LOG_I(TAG, "tt_init complete"); - - config_instance = config; } const Config* _Nullable tt_get_config() { diff --git a/tactility/src/ui/statusbar.c b/tactility/src/ui/statusbar.c index a84d2e08..1506dda8 100644 --- a/tactility/src/ui/statusbar.c +++ b/tactility/src/ui/statusbar.c @@ -18,7 +18,7 @@ typedef struct { } StatusbarIcon; typedef struct { - Mutex* mutex; + Mutex mutex; PubSub* pubsub; StatusbarIcon icons[STATUSBAR_ICON_LIMIT]; } StatusbarData; @@ -166,13 +166,13 @@ static void statusbar_event(TT_UNUSED const lv_obj_class_t* class_p, lv_event_t* } } -int8_t tt_statusbar_icon_add(const char* image) { +int8_t tt_statusbar_icon_add(const char* _Nullable image) { statusbar_lock(); int8_t result = -1; for (int8_t i = 0; i < STATUSBAR_ICON_LIMIT; ++i) { if (!statusbar_data.icons[i].claimed) { statusbar_data.icons[i].claimed = true; - statusbar_data.icons[i].visible = true; + statusbar_data.icons[i].visible = (image != NULL); statusbar_data.icons[i].image = image; result = i; TT_LOG_I(TAG, "id %d: added", i); diff --git a/tactility/src/ui/statusbar.h b/tactility/src/ui/statusbar.h index 73350a7e..4b4f9a67 100644 --- a/tactility/src/ui/statusbar.h +++ b/tactility/src/ui/statusbar.h @@ -12,7 +12,7 @@ extern "C" { #define STATUSBAR_HEIGHT (STATUSBAR_ICON_SIZE + 4) // 4 extra pixels for border and outline lv_obj_t* tt_statusbar_create(lv_obj_t* parent); -int8_t tt_statusbar_icon_add(const char* image); +int8_t tt_statusbar_icon_add(const char* _Nullable image); void tt_statusbar_icon_remove(int8_t id); void tt_statusbar_icon_set_image(int8_t id, const char* image); void tt_statusbar_icon_set_visibility(int8_t id, bool visible);