From 5558edccce2a9f432dce5e8e21cc2146160a9399 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Fri, 9 Feb 2024 23:53:29 +0100 Subject: [PATCH] Statusbar improvements (#36) - Added sdcard service: it updates a statusbar icon and it can auto-unmount sdcards that were physically ejected by the user. - Added `is_mounted` check for sdcard drivers - Refactored assets: moved them from `tactility-esp/` to `data/` - Made assets work with sim build - Refactored wifi statusbar icons - Refactored wifi_manage app access point icons - Support not having an initial image icon when registering a new icon in statusbars. When a statusbar icon is added, it is now visible/invisible depending on whether an image was specified. - Keep track of app memory on app start to find memory leaks (needs fine-tuning in the future) - `tt_init()` assigns `config_instance` earlier, so it can be used during service init --- app-sim/src/lv_conf.h | 4 +- boards/lilygo_tdeck/sdcard.c | 13 +- boards/yellow_board/sdcard.c | 6 + data/assets/sdcard.png | Bin 0 -> 287 bytes data/assets/sdcard_alert.png | Bin 0 -> 309 bytes data/assets/wifi_connection_issue.png | Bin 0 -> 376 bytes data/assets/wifi_find.png | Bin 0 -> 464 bytes data/assets/wifi_off.png | Bin 0 -> 411 bytes data/assets/wifi_perm_scan.png | Bin 0 -> 435 bytes data/assets/wifi_signal_0.png | Bin 0 -> 404 bytes data/assets/wifi_signal_0_lock.png | Bin 0 -> 451 bytes data/assets/wifi_signal_1.png | Bin 0 -> 415 bytes data/assets/wifi_signal_1_locked.png | Bin 0 -> 473 bytes data/assets/wifi_signal_2.png | Bin 0 -> 419 bytes data/assets/wifi_signal_2_locked.png | Bin 0 -> 473 bytes data/assets/wifi_signal_3.png | Bin 0 -> 415 bytes data/assets/wifi_signal_3_locked.png | Bin 0 -> 478 bytes data/assets/wifi_signal_4.png | Bin 0 -> 406 bytes data/assets/wifi_signal_4_locked.png | Bin 0 -> 466 bytes data/assets_sources/sdcard.svg | 1 + data/assets_sources/sdcard_alert.svg | 1 + data/assets_sources/wifi_connection_issue.svg | 1 + data/assets_sources/wifi_find.svg | 1 + data/assets_sources/wifi_off.svg | 1 + data/assets_sources/wifi_perm_scan.svg | 1 + data/assets_sources/wifi_signal_0.svg | 1 + data/assets_sources/wifi_signal_0_lock.svg | 1 + data/assets_sources/wifi_signal_1.svg | 1 + data/assets_sources/wifi_signal_1_locked.svg | 1 + data/assets_sources/wifi_signal_2.svg | 1 + data/assets_sources/wifi_signal_2_locked.svg | 1 + data/assets_sources/wifi_signal_3.svg | 1 + data/assets_sources/wifi_signal_3_locked.svg | 1 + data/assets_sources/wifi_signal_4.svg | 1 + data/assets_sources/wifi_signal_4_locked.svg | 1 + data/assets_sources/wifi_signal_5.svg | 1 + .../config/placeholder.txt | 0 tactility-core/src/pubsub.c | 2 +- tactility-core/src/thread.c | 3 +- tactility-core/src/thread.h | 7 +- tactility-esp/CMakeLists.txt | 4 +- tactility-esp/assets/ic_small_wifi_off.png | Bin 274 -> 0 bytes tactility-esp/assets/ic_small_wifi_on.png | Bin 224 -> 0 bytes tactility-esp/assets/network_wifi.png | Bin 312 -> 0 bytes tactility-esp/assets/network_wifi_1_bar.png | Bin 309 -> 0 bytes .../assets/network_wifi_1_bar_locked.png | Bin 336 -> 0 bytes tactility-esp/assets/network_wifi_2_bar.png | Bin 307 -> 0 bytes .../assets/network_wifi_2_bar_locked.png | Bin 344 -> 0 bytes tactility-esp/assets/network_wifi_3_bar.png | Bin 312 -> 0 bytes .../assets/network_wifi_3_bar_locked.png | Bin 353 -> 0 bytes tactility-esp/assets/network_wifi_locked.png | Bin 370 -> 0 bytes tactility-esp/assets/sdcard_mounted.png | Bin 220 -> 0 bytes tactility-esp/assets/sdcard_unmounted.png | Bin 224 -> 0 bytes .../system/wifi_manage/wifi_manage_view.c | 26 +--- tactility-esp/src/services/wifi/wifi.c | 83 ++++++++----- tactility-esp/src/services/wifi/wifi.h | 11 ++ tactility/src/app.c | 23 ++++ tactility/src/app_i.h | 2 + tactility/src/assets.h | 22 ++++ tactility/src/hardware.c | 2 + tactility/src/sdcard.c | 25 ++-- tactility/src/sdcard.h | 12 +- tactility/src/sdcard_i.h | 11 ++ tactility/src/services/sdcard/sdcard.c | 117 ++++++++++++++++++ tactility/src/tactility.c | 9 +- tactility/src/ui/statusbar.c | 6 +- tactility/src/ui/statusbar.h | 2 +- 67 files changed, 321 insertions(+), 86 deletions(-) create mode 100644 data/assets/sdcard.png create mode 100644 data/assets/sdcard_alert.png create mode 100644 data/assets/wifi_connection_issue.png create mode 100644 data/assets/wifi_find.png create mode 100644 data/assets/wifi_off.png create mode 100644 data/assets/wifi_perm_scan.png create mode 100644 data/assets/wifi_signal_0.png create mode 100644 data/assets/wifi_signal_0_lock.png create mode 100644 data/assets/wifi_signal_1.png create mode 100644 data/assets/wifi_signal_1_locked.png create mode 100644 data/assets/wifi_signal_2.png create mode 100644 data/assets/wifi_signal_2_locked.png create mode 100644 data/assets/wifi_signal_3.png create mode 100644 data/assets/wifi_signal_3_locked.png create mode 100644 data/assets/wifi_signal_4.png create mode 100644 data/assets/wifi_signal_4_locked.png create mode 100644 data/assets_sources/sdcard.svg create mode 100644 data/assets_sources/sdcard_alert.svg create mode 100644 data/assets_sources/wifi_connection_issue.svg create mode 100644 data/assets_sources/wifi_find.svg create mode 100644 data/assets_sources/wifi_off.svg create mode 100644 data/assets_sources/wifi_perm_scan.svg create mode 100644 data/assets_sources/wifi_signal_0.svg create mode 100644 data/assets_sources/wifi_signal_0_lock.svg create mode 100644 data/assets_sources/wifi_signal_1.svg create mode 100644 data/assets_sources/wifi_signal_1_locked.svg create mode 100644 data/assets_sources/wifi_signal_2.svg create mode 100644 data/assets_sources/wifi_signal_2_locked.svg create mode 100644 data/assets_sources/wifi_signal_3.svg create mode 100644 data/assets_sources/wifi_signal_3_locked.svg create mode 100644 data/assets_sources/wifi_signal_4.svg create mode 100644 data/assets_sources/wifi_signal_4_locked.svg create mode 100644 data/assets_sources/wifi_signal_5.svg rename {tactility-esp => data}/config/placeholder.txt (100%) delete mode 100644 tactility-esp/assets/ic_small_wifi_off.png delete mode 100644 tactility-esp/assets/ic_small_wifi_on.png delete mode 100644 tactility-esp/assets/network_wifi.png delete mode 100644 tactility-esp/assets/network_wifi_1_bar.png delete mode 100644 tactility-esp/assets/network_wifi_1_bar_locked.png delete mode 100644 tactility-esp/assets/network_wifi_2_bar.png delete mode 100644 tactility-esp/assets/network_wifi_2_bar_locked.png delete mode 100644 tactility-esp/assets/network_wifi_3_bar.png delete mode 100644 tactility-esp/assets/network_wifi_3_bar_locked.png delete mode 100644 tactility-esp/assets/network_wifi_locked.png delete mode 100644 tactility-esp/assets/sdcard_mounted.png delete mode 100644 tactility-esp/assets/sdcard_unmounted.png create mode 100644 tactility/src/assets.h create mode 100644 tactility/src/sdcard_i.h create mode 100644 tactility/src/services/sdcard/sdcard.c 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 0000000000000000000000000000000000000000..6c222e11070e5bc85e762cd17b34d898e06ce710 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmC@5Lt z8c`CQpH@mmtT}V`<;yxP|+Gs7sn8b-nUZ>`3@O~IM3Hs z@jDXo?x+Xb1BsZ0+~SE33{ns9gmhf`6BZ(2@K5c3#4XCJ}5q7Cu(w`gFk9&GMYhnRoZ>H|@#mnJ;`g@i=1pfp>G| g>*9-7?`SWdx8dXO8r}b|fbM4SboFyt=akR{0DV?)!vFvP literal 0 HcmV?d00001 diff --git a/data/assets/sdcard_alert.png b/data/assets/sdcard_alert.png new file mode 100644 index 0000000000000000000000000000000000000000..933c8465596b126cb37db8ca792e5281c22d8053 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmC@5Lt z8c`CQpH@mmtT}V`<;yxP|+bz7sn8b-m_B-`I;OAT<@!^ z%{$SQ@Yr-u^VX#zuMGDz_1Z4o+S-2bP<~@82e-E35zl2a|5RFA8}Ht9cE+?Guh-08 zr&KK;EM4NPtX`7pX}N(}@4#NyO)O&Do^M_8wvE{`;Q@@2q$jyK^88jHo(a7##? zI{WSO;`yyhloqVLxh4Cv_<_it6W_GNBtjQ12?>%~+`CF3B6#iPQjrC3eV-h>%=45n zWzsg=oj0SSw@*_qW${`yue6f$&Hm5L_pb*??`_xj&%K_t^QRym&^HX8u6{1-oD!M< D1;l#( literal 0 HcmV?d00001 diff --git a/data/assets/wifi_connection_issue.png b/data/assets/wifi_connection_issue.png new file mode 100644 index 0000000000000000000000000000000000000000..5c79dbdbe017d3b83b430affc3d835e01540c73c GIT binary patch literal 376 zcmV-;0f+vHP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10R>4! zK~y-6<)ST8n`B&p*Vr#Qh5w&V00UNOQg z9zqD;6F>+-%y9)>JRy{uQhuH;p@%alZt1t9wF{8BwS(h0NY-UGJ zEAD21HrCO>5a~F>is%5lxQkJZus3lj711^>aF2tyyX&c7NpvHwTaDjK+{^?^pq<>h zGrVJeF1P?4#`y#vIG^}$7B~k@vm>LAtM90000 literal 0 HcmV?d00001 diff --git a/data/assets/wifi_find.png b/data/assets/wifi_find.png new file mode 100644 index 0000000000000000000000000000000000000000..f20ab74fb3f8afadb74563fa19b7831d992a3f1b GIT binary patch literal 464 zcmV;>0WbcEP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10bNN% zK~y-6&D60=98nO*@y|QYJCM{NXz<^NNV+s3m5p^8u{LcQZEQ^8KM)Ctfe;9m7J`Wu zTKFd@Bvo>0?2Y6Y3*VEybJw%DKn4b8cW1u)o0-Q;5n-Ix8Y}Hz0NcYaQc7*i;{~4L zQFi!^9*(e!P+w-4QtDs{uQ7v5oZt-SNO*`@%%O{)SjSdGT!IXo#}5P!u!yOM zQ0I7n1$@gj-!WIjE#prHK5v5D0e^;5Twu9{X>{-vd-tAxwusorldSe}`O8|C{uZq} z)O7JCFQ%8{ZvNJa2-V~Qeb)rdfIhaf_pvdMGgMHZ?=evW?BPS@c^kcI&cHd0h_#dw ztYRXi^fDs)BgWVr9%@}{Md>HB8(RLD!7b38xE4P+XXO%^1T2Ms1D)G(bFfRN5FW4(CJc;8C=#*vv0000pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10VqjC zK~y-6t&_b<#Xt~+zlqnzr?C_SD+?dMClEvstSxWKaC@~d5g$bmYkO~Dp^qT`fHF2` zFYD%J6GH~3$mHyo*)tP!cczSDQd$6-S!rg~R8RvNz=2X0Yyk`40eA)8fj3|Y+yfP` z3v9SMaUwtg+$PW?9j*mf05__AN&5nv0Glar4|tMj1?@`R;1IZzehKV^0iOZiD(hE|H+^k%n3;J5`310K8gKaQ>SF)^002ovPDHLk FV1hwtqon`< literal 0 HcmV?d00001 diff --git a/data/assets/wifi_perm_scan.png b/data/assets/wifi_perm_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..c6b668d77fa8286edc720b75513e9f8a63b09aa8 GIT binary patch literal 435 zcmV;k0ZjghP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10YFJa zK~y-6&D76oQ&AAd@y|*B(X6|u#I3JT+P;8py6YxeARx`fG-j8>o0w^!<5nnp5i$k;wQdhj30S^2am9aP2Aum1`%-wGH@T)2#j!y zc0{O4wDZg;YsT2G%=IwAH#}|tyvA8W?@889&}*TCEqubqhFxFcqM>({wOi;^r<`Q# z@2b5PF1qN})Kk_3P9nl=^I2}ZN2?GHF|2{T$(k3_dNEW%`?Jsz*aVvcHbG~B8TPgg zRtsF>bRnz}SU?B<{Gtixi(m_Z#qIZVPH*#{fQ8eA&Z?Yy9Lk7@S1G0K{C&D?e)>49 dD(?RS`y03AsX}%_hSmT8002ovPDHLkV1kb`#Et*} literal 0 HcmV?d00001 diff --git a/data/assets/wifi_signal_0.png b/data/assets/wifi_signal_0.png new file mode 100644 index 0000000000000000000000000000000000000000..964d0ee225206c1f5e6f1f2c6e7ae1bc759d1655 GIT binary patch literal 404 zcmV;F0c-w=P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10U=35 zK~y-6&D6~*MNt$0;BQ}lT{C4s87Z$IyZ{q3V*@W>Xrf$Y;sG$hOBhk=PL#aDRVIpo zu|!%1_R;-4?yak=+O<1-t?#V%>8unHh8dNiYJUNawm(QIjbIt;SiuZt^YIg&af1uo zM#N`JeQ}2=r7>(_7jt;W9U6Ga`O{dyBF6EE1Dr?12gu+O?h&YC1CtS<+rnhdsppyo zmWt*!@rnnm_CiYVwOsp#?F!~m#Wk+_y7|_)%(WAkD&De_TR%l*fbJ5Ga_wG3Xg(YW z?S{30ZRlAU+6(Id`$02y+zsmrmZ864J;65g-1jepF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10Z>Uq zK~y-6<oc! z3I=QhEz~lE1Q`p@k=?7iZopI-817|ezWYXi`wPo0OkfDR_}bUxJ8cKwFo@@MmDSSvHd=qt zUEo8}Zf2(T=)|h+HK+8ZLCqyHx!dt!Bj{5p27;<>IKCi-nhAo-GPmne(DCr zUi-5ru+iyunN_R8aZz&BFRJd&r&ldAHzESo%V~m$Si(r7e576Y&`H+qC)P_WoBm*j tZ3}Kj#87#ETf&!(E-!C)@c;c_uK{~OlgIQlPgwu}002ovPDHLkV1kU{!j}L5 literal 0 HcmV?d00001 diff --git a/data/assets/wifi_signal_1.png b/data/assets/wifi_signal_1.png new file mode 100644 index 0000000000000000000000000000000000000000..7799eeda99bc02cc03483317a0d21b764e4fad1f GIT binary patch literal 415 zcmV;Q0bu@#P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10W3*G zK~y-6&D6gu#Zef?@z=S2Bgo%8v;&vTyPNfDu+QR^%1FMxxc2Pvfi%wrh~n80Mde#8?l zae}Le_-OMNJxnPLVGUcD!W*t}i|4E##|-8$j0f!EI3nIb1~zbqzy(%Nj|gRnde&TI z&n+57ajSU2Jr=7V-@uo$_Z1s8Ok))1IQvoO+v7BQM=(~rvYAUiMC}*VCG2N!Ga|HJ z7SN-gK+9llz~4YK?4T3Y1p5rh*?eA#w$e~Ow3+|_002ov JPDHLkV1hQ0wE6%5 literal 0 HcmV?d00001 diff --git a/data/assets/wifi_signal_1_locked.png b/data/assets/wifi_signal_1_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..7f3759d78a4729d9aed3409fe2808f8ce20d2ad9 GIT binary patch literal 473 zcmV;~0Ve*5P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10cJ@= zK~y-6&D6h3)lnG7@z=SQqD^5#f>To9+1^)#Xi>BxwsHGrq z2|}oUz@kOaLDz_+9tWSVeDCFZ{Q)=dzys%;&+~bIpYw3Or$mH)j#gi3{{wifd!v*x zfQOjFBizPV%6r(yXS~Cgi1^##uX>Js3O3Ta8WHMZJB7_lLT_N|bloLZ(3j^yo!sHYjMLnXdl(VzQVOi1lv18y z3Jf`Y2lP5pb^I#+VK}wrE-kPe5xxKA zh-hQ2wpD8L(FV&X=R6J#(8;s%Y3N}SG2>OZi@%PS_(>RBdG P00000NkvXXu0mjft?t#y literal 0 HcmV?d00001 diff --git a/data/assets/wifi_signal_2.png b/data/assets/wifi_signal_2.png new file mode 100644 index 0000000000000000000000000000000000000000..1da91111d304e89348f42ca28a00444c71ed439d GIT binary patch literal 419 zcmV;U0bKrxP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10We8K zK~y-6&D61K(@_-1@y|_dL$V1SDmV#!1xfn?x^#1Pa26b03W?Cg2XH8qzC59SX_DQnol9(J*X zM|pjY3w*{2zC^_JjDOn0Qp!4BVIPlig)@xtBlVlu##3zII}UIh5x+qKd-#gL5HHY; z2(?5vHN*6b(VG_c62I^b&lW)%;Lp>0i8n1gK?kS!^iQ3ijgRSV#WPEBAi!>GJGg-&v<<)j9y0_VQpl>Mr= zp+`;7Dy$LM09^=M3amgIVG;57aF~yXcwb8CpF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10cJ@= zK~y-6&D60=)ln1&@Xvi|4{Hi1hY%tMC%1BFa1o)i)KX^pRw*?nQC|`4m3j1kW0{mn*)(>&rC0%eJwDChk;K zo@eQ=(71xSgqQj3QbZ_&?HpLGF6)w{w=wZ&-xVxLn|O-1IK~n7Fj}a4j8-Y2u3|;{ zEq_aF6nU*&conV6f9}VQh;~W|mTE3wrC8s`dR|YJ1igAwDXs7e%^X{(QNIuoz29;~ zw6R>cQU+%)rrU=3$8e}29lt1_n&D7KntLiD-e-5GCbdH`9QtL~f583*e-tgH2;z5K P00000NkvXXu0mjf#!tx@ literal 0 HcmV?d00001 diff --git a/data/assets/wifi_signal_3.png b/data/assets/wifi_signal_3.png new file mode 100644 index 0000000000000000000000000000000000000000..89ff66b282c686f6736282852f0d91096c6ac37c GIT binary patch literal 415 zcmV;Q0bu@#P)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10W3*G zK~y-6&D1?g13?r3;BWlJbQ%izrt5q$92VdlMWXJ=tjL>OmGj8*#!aH>3!QkujDcCd*hEa&AHyy6a5 zxQ~eMuKwZ-Q%cj=$1zs$i3c?Cmg^U>hIP!~8E3eRh%b=A8Xgg7U>B8$&@WNRHI3ZU zM6KA|9zO7dtwG2Td^`8Ha4>;Y%;6R{Bb|JAT<6|d%olH|=dE89=bGoM`O^+_?xNbU zo^ns19uYdX-ia>cXDiQjW~)@w#=5`~`rZdB=X)9J0W*3u0#@WnPyc{FHwxN=4FpF( z`(i`EA?QHtSFjH{6pM)7%b^?*ah_6|%j47E>f4vYxZ?j`us_9ql8t;m`$zx)002ov JPDHLkV1j_$uppF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10c%M_ zK~y-6&D6hZltB>2@z2H|Ap`;%3jz6$%1%L2#m>VbeH6q}@DkDumUrLTdA>V4@4iza!ZdAWs7q#ix=a|6_m+f{bg zF&H{kqsZL^*yAd0kf+$jp!ffAu_K}@rNF($2Y67;m+>g)mukSc>oA(>56tJpF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10V7F7 zK~y-6&D1?g15p&k@!#_clyo*C*t!GJ!UYJ{Za~mdOACucuyGN=6rj(jo0l+rlXv5Psp;R2U<%>C1t#{wpBhkYDI#5>5qC0rwLf;CJfM^Ub0%*+e9t*u4Ml;vo!K4O^jk2&)MszCv4?RGkcBV6$ z0HCspOd}$Eoy*QIV1?>!PHEV`fz~@16<_ct(0W(C$8RwRvi;j;PyYFcuJ6ndlmGw#07*qoM6N<$f@CDC AG5`Po literal 0 HcmV?d00001 diff --git a/data/assets/wifi_signal_4_locked.png b/data/assets/wifi_signal_4_locked.png new file mode 100644 index 0000000000000000000000000000000000000000..c08dfc89f7337b2553afe7ab2709c2d4b835e4db GIT binary patch literal 466 zcmV;@0WJQCP)pF8FWQhbW?9;ba!ELWdL_~cP?peYja~^aAhuUa%Y?FJQ@H10bfZ( zK~y-6&D60@6j2n$@!thB5!Y%f3p;%Q3ZWpuP7+IE>f(deN$W7c87HCYmF@?~zmd(MCEoSZo&B8+oQjFom3z^SHDN}0qQ zo?sq#Q}6{R*vA_jM8vPZ^6MIwQf^=w&v6ewaESL9WPBG7@DMlg8JpOSh@T*VbNGP3 z9-d-4BD4v&u#~ZZBh1#9Tfr%gv6yBDt9Xr%_?|jWZxx-4T}=NpS*mr(v( \ 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 c27a2815ee93a650d7aa4cbbd755583cc611a3a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 274 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+0wn(&ce?|mZhE>nhG>ZHJ-AWNIZ=Y)!sPj{ zE_IpQeRGeo`N#?$pI3}W@;070sysvG((NUkM;{1gUBCE%lc(ixn3O!P;6pW2%j5B( zZ#>l^jIK=d*^szGdFEuxtECB-_r&|P^rggeDDK&@<&F2nwP5f_Yw*s|`)R&GhkIlVgO(3Xv%{(QAr32x8gICiGEFKcScPvdR*@Fq%e z`kUQ>pATaP?q@dDT#V@(qC8|q}6jL%ZLG(=i>~$f3_nU|3 WxlOcWOWp+ZB!j1`pUXO@geCy5esQV* 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 7e3141c8f4a83084ca92935904a0b312feaaad8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+0wn(&ce?|mmV3H5hG>W$J-EA*DUpHgfTKaw z9fvI}vjq;?@tg~)+s4P-o8xpr%w$6+>qf?p*5ZB6?wEN5Y;iEE6%87Cx_LmiK7Mw}36rtZI$Dy^U+`iHY%;Ge}Baj#`P X@7vEZE8Kn)=wt>@S3j3^P6kD4gwW*Y=(TLjSib5;DGm14v^$k`q=kVkutZ^PGYmrU@WBUyY!GKKeEkNipMH2B_W+8$_DCd zz!K?VK+ZgKCCBRE5(myr53d|{YdFWadMOS%6jYs8z(};+GET>|64nMJH^ylV)&(32 z{e$^{eb81|AFvDB2^#`zLcOq|KnIQ7)9^ik*?wPR-eGO-!49-00000NkvXX Hu0mjfJv4!f 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 1b59d794e9b2079caeea8cb94feae27a09a57bf6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336 zcmV-W0k8gvP)6k3QHO0S7!Xod7bqHC^N%-cd@{GHu>AI}L$UHT@Fi;pB4Wxwq_9{sMi#=rH^# zRiLz8997w0<~%>Glp=1l>b;j;?6^{Hz)%S!p5+tQk;DyZ*aKKwp3y{f+=%vs16eWrFv)V%!+njRWxPzf#IS&?cXdfFi!t18LU@0KE z6f_9?1&l$Xura_PGzl9EG-%~^Gj_PM{k~G&P3E#Y`~a{=H5Go_vEcv!002ovPDHLk FV1i;VfdT*k 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 ca2c8f679149ae8bd1fa433d2f67146fd5d4c118..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 344 zcmV-e0jK_nP)U`lI?%lYWJBnO%z_&AN!sRSYqXMmo=2Dgs`Z0jcDq z$v_UO(&}Eo;s`k4sptxj!M*6F-&q}{VlLLj`{EN9NL9&~FiYoO_WWoqTa|5~FBl!V zhw=-Qwu`N*I%W3LDrJ#{h(p7;He(T22V?$0s~T5cY^#)?xPz{pC73v{NWXI};_XW@ zsK*P2S|#JDDAR;koRY`4iBf q>=SUTb<18?&EY34H&dL9&Vf&|>pd0PQetob0000Kvr-9WdtYC4R8Zx0$0!t7(q911p7#v9LL>pCWIzU;acDQw#2fS z*~*!D#bUs%C_ji3R~l)i6aQ*#H4d8e6&@vf7T;*qOX6FdBhK-i=E+^ef%j%WlsvQ; z$X$JKyZ6H7IB>vw@eUw|H}Q`?KU0)IuF}ib5^EQTs`^iumGfI>-dfA1(ucATT4E#^ zOJO7|W(1={cPTFPB*{ic5E9MB)Lc!O)rPjrJW+tUlvxcMMoe#^58ISZ@cQ%s76Wpg z10BIqz$s`DHU*49qp%#H4^6^yfd;MIZN@gX*xy&qCljohUEvSVG&L1FH(d$<0000< KMNUMnLSTXtjeb)A 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 b9596cfe0712dc5cc5c5ec10c5912c3971dac3be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 353 zcmV-n0iOPeP)MXI2_cc#$DGvN*21LnD zHv>u4?`{t!T#f?=JQgnivbYsL={SEyiR1=)d0S%Qfv8G8gxPk^((}wpHkBci2caZd zg7GM{gok;6QK5en51mVLtu2U&reAxPpzNG^?3L*!3Q!j_+LCGl5f|}?SM~=@X$*Fd z#gT(`bX?jc&wk1?XipB(M{Fsc>v*8^mtQXiH32gL&|`1(eN*+9L#XXX9Y4z33YAqr z4tVHL%lrvwQ2GQM`?}Owe=!V1uwh*Z?+Q1NhJShukQQD~Pc4b%}j` z_s?TSH1T_aReOjO6mYIxs^Wr+$z%Mm9&&7wlIv1wEZl-NVI?9;-`u?Ij~_u zx|L`f=-2>OOOFO}=DTRQ(hDwe5N-;*pXJ!YIac{c3FtAPH+K?Wowi#x4t-^uj*aBR z3B)g2jSWK=d(0`$aKrhL7so@}&5*+=bO^duLhU4C>t~9j`LSPb2zqGX8-^I diff --git a/tactility-esp/assets/sdcard_mounted.png b/tactility-esp/assets/sdcard_mounted.png deleted file mode 100644 index 472f12f7cd5b9ace7c0d805c3613462032962eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 220 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE5DWk0lm$i!OEy*VwD9;a zL|Mr9FYR^M$(B-C!*+=0Hpi6$#_olD4u;hVZidX$8x0PNF_|{pxWRBD_3IG{kDf#Y z?hdmL_5p?`W;3!V^{6mkWd6-?r66F(!2>HACrmgnEyrPE)5L_0E&{HJ9NiyzuXKsb za6IAJsU#jWB{)N -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);