diff --git a/mkapp/app/resource/OSD/GOGGLE/alert.png b/mkapp/app/resource/OSD/GOGGLE/alert.png new file mode 100644 index 00000000..d407171d Binary files /dev/null and b/mkapp/app/resource/OSD/GOGGLE/alert.png differ diff --git a/mkapp/app/script/online_downloader.sh b/mkapp/app/script/online_downloader.sh new file mode 100755 index 00000000..e4df678d --- /dev/null +++ b/mkapp/app/script/online_downloader.sh @@ -0,0 +1,101 @@ +#!/bin/sh + +version_gt() { test "$(echo "$@" | tr " " "\n" | sort -g | head -n 1)" != "$1"; } +version_le() { test "$(echo "$@" | tr " " "\n" | sort -g | head -n 1)" == "$1"; } +version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rg | head -n 1)" != "$1"; } +version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rg | head -n 1)" == "$1"; } + +download() { + dst_path="$1" + fw_links="$2" + fw_sizes="$3" + fw_notes="$4" + fw_total=1 + fw_counter=1 + + # Do we have a SD Card mounted? + if [ ! -z "$(mount | grep /mnt/extsd)" ]; then + dst_path="/mnt/extsd/FIRMWARE/$dst_path" + else + dst_path="/tmp/FIRMWARE/$dst_path" + fi + + # Check if we need to download? + if test -f $dst_path/release.notes; then + echo "Local storage contains latest release!" + return 0 + fi + + # Blindly create directory, errors checking handled below. + mkdir -p $dst_path 2> /dev/null + + # The real download work is performed here! + for link in $fw_links; do + file="$(basename "$link")" + target="$dst_path/$file" + if test -f "$target"; then + current_size=$(wc -c < "$target") + archive_size=$(echo $fw_sizes | cut -d" " -f$fw_counter) + if [ $current_size -ne $archive_size ]; then + echo "Resuming download: $target ...." + curl -s -k -C $current_size -L $link -o "$target" && \ + fw_total=$((fw_total + 1)) && \ + echo "Resuming download: $target DONE!" + else + fw_total=$((fw_total + 1)) + fi + else + echo "Downloading firmware: $target ...." + curl -s -k -L $link -o "$target" && \ + fw_total=$((fw_total + 1)) && \ + echo "Downloading firmware: $target DONE!" + fi + fw_counter=$((fw_counter + 1)) + done + + # Having release notes identify a successful download. + if [ $fw_total -eq $fw_counter ]; then + printf "$fw_notes" | tr -d '\r' > $dst_path/release.notes && \ + echo "Completed downloading latest release!" + fi +} + +app_version_check() { + if version_gt $1 $2; then + echo "Goggle running older firmware!" + return 0 + else + echo "Goggle running latest firmware!" + return 1 + fi +} + +online_goggle_fw_check() { + fw_info="/tmp/hdz_goggle_fw.latest" + echo "Checking Goggle Releases" && \ + curl -ks -o $fw_info https://api.github.com/repos/hd-zero/hdzero-goggle/releases/latest && \ + fw_link=$(cat $fw_info | grep 'browser_' | cut -d\" -f4) && \ + fw_note=$(cat $fw_info | grep 'body' | cut -d\" -f4) && \ + fw_size=$(cat $fw_info | grep 'size' | cut -d\" -f4) && \ + fw_file=$(basename $fw_link) && \ + rversion="$(echo ${fw_file%%.bin} | cut -d "-" -f4)" && \ + lversion="$(cat /mnt/app/version | cut -d "-" -f1)" && \ + app_version_check $rversion $lversion && \ + echo "Searching local storage for latest release..." && \ + download "GOGGLE/$rversion" "$fw_link" "$fw_size" "$fw_note" +} + +online_vtx_fw_check() { + fw_info="/tmp/hdz_vtx_fw.latest" + echo "Checking VTX Releases" && \ + curl -ks -o $fw_info https://api.github.com/repos/hd-zero/hdzero-vtx/releases/latest && \ + fw_links=$(cat $fw_info | grep 'browser_' | cut -d\" -f4) && \ + fw_notes=$(cat $fw_info | grep 'body' | cut -d\" -f4) && \ + fw_sizes=$(cat $fw_info | grep 'size' | cut -d: -f2 | cut -d, -f1) && \ + rversion=$(cat $fw_info | grep 'tag_name' | cut -d\" -f4) && \ + echo "Searching local storage for latest release..." && \ + download "VTX/$rversion" "$fw_links" "$fw_sizes" "$fw_notes" +} + +online_goggle_fw_check +online_vtx_fw_check diff --git a/mkapp/app/script/update_goggle.sh b/mkapp/app/script/update_goggle.sh index 006f4519..ee98c634 100755 --- a/mkapp/app/script/update_goggle.sh +++ b/mkapp/app/script/update_goggle.sh @@ -1,7 +1,9 @@ #!/bin/sh +GOGGLE_BIN="$1" +TMP_DIR=/tmp/goggle_update -function gpio_export() +gpio_export() { if [ ! -f /sys/class/gpio/gpio224/direction ] then @@ -9,55 +11,51 @@ function gpio_export() echo "out">/sys/class/gpio/gpio224/direction fi - if [ ! -f /sys/class/gpio/gpio228/direction ] then - echo "228">/sys/class/gpio/export - echo "out">/sys/class/gpio/gpio228/direction + echo "228">/sys/class/gpio/export + echo "out">/sys/class/gpio/gpio228/direction fi if [ ! -f /sys/class/gpio/gpio258/direction ] then - echo "258">/sys/class/gpio/export - echo "out">/sys/class/gpio/gpio258/direction - fi + echo "258">/sys/class/gpio/export + echo "out">/sys/class/gpio/gpio258/direction + fi } -function gpio_set_reset() +gpio_set_reset() { echo "0">/sys/class/gpio/gpio224/value echo "1">/sys/class/gpio/gpio228/value } -function gpio_clear_reset() +gpio_clear_reset() { echo "1">/sys/class/gpio/gpio224/value echo "0">/sys/class/gpio/gpio228/value } -function gpio_set_send() +gpio_set_send() { echo "1">/sys/class/gpio/gpio224/value echo "0">/sys/class/gpio/gpio228/value } - -function disconnect_fpga_flash() +disconnect_fpga_flash() { echo "1">/sys/class/gpio/gpio258/value } -function connect_fpga_flash() +connect_fpga_flash() { echo "0">/sys/class/gpio/gpio258/value } - -FILE_TARGET=/mnt/extsd/HDZERO_GOGGLE*.bin -TMP_DIR=/tmp/goggle_update - -function untar_fils() +untar_file() { + FILE_TARGET="$1" + if [ ! -e ${TMP_DIR} ] then mkdir ${TMP_DIR} @@ -71,10 +69,8 @@ function untar_fils() mv ${TMP_DIR}/HDZGOGGLE_VA*.bin ${TMP_DIR}/HDZGOGGLE_VA.bin } - -function update_rx() +update_rx() { - echo "find RX update file, start update" filesize=`ls -l ${TMP_DIR}/HDZGOGGLE_RX*.bin| awk '{print $5}'` gpio_export @@ -85,7 +81,6 @@ function update_rx() mtd_debug write /dev/mtd8 0 $filesize ${TMP_DIR}/HDZGOGGLE_RX.bin mtd_debug erase /dev/mtd9 0 65536 mtd_debug write /dev/mtd9 0 $filesize ${TMP_DIR}/HDZGOGGLE_RX.bin - echo "update finish RX, running" gpio_clear_reset @@ -93,7 +88,7 @@ function update_rx() rmmod /mnt/app/ko/w25q128.ko } -function update_fpga() +update_fpga() { echo "find VA update file, start update" filesize2=`ls -l ${TMP_DIR}/HDZGOGGLE_VA*.bin| awk '{print $5}'` @@ -110,12 +105,20 @@ function update_fpga() rmmod /mnt/app/ko/w25q128.ko } +# If firmware file was NOT supplied then default to primary location for emergency restore +if [ -z "$GOGGLE_BIN" ]; then + if [ `ls /mnt/extsd/HDZERO_GOGGLE*.bin | grep bin | wc -l` -eq 1 ] + then + GOGGLE_BIN="/mnt/extsd/HDZERO_GOGGLE*.bin" + fi +fi -if [ `ls /mnt/extsd/HDZERO_GOGGLE*.bin |grep bin |wc -l` == "1" ] +if [ ! -z "$GOGGLE_BIN" ] then + echo "Flashing $GOGGLE_BIN" echo "0" > /tmp/progress_goggle echo "0" - untar_fils + untar_file "$GOGGLE_BIN" mv ${TMP_DIR}/hdzgoggle_app_ota*.tar ${TMP_DIR}/hdzgoggle_app_ota.tar cp -f /mnt/app/setting.ini /mnt/UDISK/ #disable it66021 @@ -130,12 +133,12 @@ then echo "100" echo "100" > /tmp/progress_goggle echo "all done" - else - if [ `ls /mnt/extsd/HDZERO_GOGGLE*.bin |grep bin |wc -l` == "0" ] + if [ `ls /mnt/extsd/HDZERO_GOGGLE*.bin | grep bin | wc -l` -eq 0 ] then - echo "skip" + echo "skip" else echo "repeat" fi fi + diff --git a/mkapp/app/script/update_vtx.sh b/mkapp/app/script/update_vtx.sh index 55909d5b..e96120e2 100755 --- a/mkapp/app/script/update_vtx.sh +++ b/mkapp/app/script/update_vtx.sh @@ -1,6 +1,8 @@ #!/bin/sh -function gpio_export() +VTX_BIN="$1" + +gpio_export() { if [ ! -f /sys/class/gpio/gpio224/direction ] then @@ -8,7 +10,6 @@ function gpio_export() echo "out">/sys/class/gpio/gpio224/direction fi - if [ ! -f /sys/class/gpio/gpio228/direction ] then echo "228">/sys/class/gpio/export @@ -16,44 +17,56 @@ function gpio_export() fi } -function gpio_set_reset() +gpio_set_reset() { echo "0">/sys/class/gpio/gpio224/value echo "1">/sys/class/gpio/gpio228/value } -function gpio_clear_reset() +gpio_clear_reset() { echo "1">/sys/class/gpio/gpio224/value echo "0">/sys/class/gpio/gpio228/value } -function gpio_set_send() +gpio_set_send() { echo "1">/sys/class/gpio/gpio224/value echo "0">/sys/class/gpio/gpio228/value } -if [ -e /mnt/extsd/HDZERO_TX.bin ] -then - gpio_export - gpio_set_send +# If firmware file was NOT supplied then default to primary location for emergency restore +if [ -z "$VTX_BIN" ]; then + if [ `ls /mnt/extsd/HDZERO_TX.bin | grep bin | wc -l` -eq 1 ] + then + VTX_BIN="/mnt/extsd/HDZERO_TX.bin" + fi +fi + +if [ -e $VTX_BIN ] +then + echo "Flashing $VTX_BIN" + gpio_export + gpio_set_send insmod /mnt/app/ko/w25q128.ko - valude=`mtd_debug info /dev/mtd8 | grep mtd.size | grep 1M` - if [ "$valude" != "" ];then - filesize=`ls -l /mnt/extsd/HDZERO_TX.bin| awk '{print $5}'` + value=`mtd_debug info /dev/mtd8 | grep mtd.size | grep 1M` + + if [ ! -z "$value" ] + then + filesize=`ls -l $VTX_BIN | awk '{print $5}'` mtd_debug erase /dev/mtd8 0 65536 > /dev/null - cp /mnt/extsd/HDZERO_TX.bin /tmp/. - mtd_debug write /dev/mtd8 0 $filesize /mnt/extsd/HDZERO_TX.bin > /dev/null - mtd_debug read /dev/mtd8 0 $filesize /tmp/HDZERO_TX_RB.bin > /dev/null + cp $VTX_BIN /tmp/ + mtd_debug write /dev/mtd8 0 $filesize $VTX_BIN > /dev/null + mtd_debug read /dev/mtd8 0 $filesize /tmp/HDZERO_TX_RB.bin > /dev/null echo "all done" else echo "detect device failed" - fi - gpio_clear_reset + fi + + gpio_clear_reset sleep 1 - rmmod w25q128.ko + rmmod w25q128.ko else - echo "skip" -fi + echo "skip" +fi diff --git a/mkapp/app/services/bearssl/lib/libbearssl.so b/mkapp/app/services/bearssl/lib/libbearssl.so new file mode 100755 index 00000000..70a69a97 Binary files /dev/null and b/mkapp/app/services/bearssl/lib/libbearssl.so differ diff --git a/mkapp/app/services/scripts/busybox_startup.sh b/mkapp/app/services/scripts/10_busybox_startup.sh similarity index 100% rename from mkapp/app/services/scripts/busybox_startup.sh rename to mkapp/app/services/scripts/10_busybox_startup.sh diff --git a/mkapp/app/services/scripts/30_bearssl_startup.sh b/mkapp/app/services/scripts/30_bearssl_startup.sh new file mode 100755 index 00000000..c6f7ea2a --- /dev/null +++ b/mkapp/app/services/scripts/30_bearssl_startup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +ln -sfn /mnt/app/services/bearssl/lib/libbearssl.so /lib/libbearssl.so diff --git a/mkapp/app/services/scripts/dosfstools_startup.sh b/mkapp/app/services/scripts/30_dosfstools_startup.sh similarity index 100% rename from mkapp/app/services/scripts/dosfstools_startup.sh rename to mkapp/app/services/scripts/30_dosfstools_startup.sh diff --git a/mkapp/app/services/scripts/dropbear_start.sh b/mkapp/app/services/scripts/50_dropbear_startup.sh similarity index 100% rename from mkapp/app/services/scripts/dropbear_start.sh rename to mkapp/app/services/scripts/50_dropbear_startup.sh diff --git a/mkapp/app/services/scripts/50_tinycurl_startup.sh b/mkapp/app/services/scripts/50_tinycurl_startup.sh new file mode 100755 index 00000000..252255a7 --- /dev/null +++ b/mkapp/app/services/scripts/50_tinycurl_startup.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +ln -sfn /mnt/app/services/tinycurl/curl /bin/curl diff --git a/mkapp/app/services/tinycurl/curl b/mkapp/app/services/tinycurl/curl new file mode 100755 index 00000000..7a28becf Binary files /dev/null and b/mkapp/app/services/tinycurl/curl differ diff --git a/src/core/main.c b/src/core/main.c index cf1b8d55..0fbe40ce 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -23,6 +23,7 @@ #include "core/sleep_mode.h" #include "core/thread.h" #include "driver/TP2825.h" +#include "driver/beep.h" #include "driver/dm5680.h" #include "driver/esp32.h" #include "driver/fans.h" @@ -34,7 +35,6 @@ #include "driver/mcp3021.h" #include "driver/oled.h" #include "driver/rtc.h" -#include "driver/beep.h" #include "ui/page_power.h" #include "ui/page_scannow.h" #include "ui/page_source.h" @@ -44,7 +44,6 @@ #include "ui/ui_osd_element_pos.h" #include "ui/ui_porting.h" #include "ui/ui_statusbar.h" -#include "util/file.h" int gif_cnt = 0; @@ -188,14 +187,15 @@ int main(int argc, char *argv[]) { // 8. Synthetic counter for gif refresh gif_cnt = 0; - + // 8.1 set initial analog module power state Analog_Module_Power(0); - + // 10. Execute main loop g_init_done = 1; for (;;) { pthread_mutex_lock(&lvgl_mutex); + main_menu_update(); sleep_reminder(); statubar_update(); osd_hdzero_update(); diff --git a/src/core/settings.c b/src/core/settings.c index 4f719c14..edba7f10 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -9,7 +9,7 @@ #include "core/self_test.h" #include "ui/page_common.h" -#include "util/file.h" +#include "util/filesystem.h" #include "util/system.h" #define SETTINGS_INI_VERSION_UNKNOWN 0 @@ -288,7 +288,7 @@ void settings_reset(void) { void settings_init(void) { // check if backup of old settings file exists after goggle update - if (file_exists("/mnt/UDISK/setting.ini")) { + if (fs_file_exists("/mnt/UDISK/setting.ini")) { char buf[256]; sprintf(buf, "cp -f /mnt/UDISK/setting.ini %s", SETTING_INI); system_exec(buf); @@ -423,13 +423,13 @@ void settings_load(void) { g_setting.wifi.ssh = settings_get_bool("wifi", "ssh", g_setting_defaults.wifi.ssh); // no dial under video mode - g_setting.ease.no_dial = file_exists(NO_DIAL_FILE); + g_setting.ease.no_dial = fs_file_exists(NO_DIAL_FILE); // storage g_setting.storage.logging = settings_get_bool("storage", "logging", g_setting_defaults.storage.logging); // Check - if (file_exists(SELF_TEST_FILE)) { + if (fs_file_exists(SELF_TEST_FILE)) { unlink(SELF_TEST_FILE); if (log_file_open(SELF_TEST_FILE)) { g_setting.storage.logging = true; diff --git a/src/driver/gpio.c b/src/driver/gpio.c index f7589095..8f8a92e8 100644 --- a/src/driver/gpio.c +++ b/src/driver/gpio.c @@ -5,7 +5,7 @@ #include #include "core/defines.h" -#include "util/file.h" +#include "util/filesystem.h" void gpio_init() { gpio_open(GPIO_BEEP); @@ -31,14 +31,14 @@ void gpio_init() { } void gpio_open(int port_num) { - if (!file_printf("/sys/class/gpio/export", "%d", port_num)) { + if (!fs_printf("/sys/class/gpio/export", "%d", port_num)) { return; } char buf[64]; sprintf(buf, "/sys/class/gpio/gpio%d/direction", port_num); - if (!file_printf(buf, "out")) { + if (!fs_printf(buf, "out")) { return; } } @@ -46,5 +46,5 @@ void gpio_open(int port_num) { void gpio_set(int port_num, bool val) { char buf[64]; sprintf(buf, "/sys/class/gpio/gpio%d/value", port_num); - file_printf(buf, "%d", val ? 1 : 0); + fs_printf(buf, "%d", val ? 1 : 0); } diff --git a/src/ui/page_autoscan.c b/src/ui/page_autoscan.c index b0efc8f9..954faeff 100644 --- a/src/ui/page_autoscan.c +++ b/src/ui/page_autoscan.c @@ -77,6 +77,8 @@ page_pack_t pp_autoscan = { .create = page_autoscan_create, .enter = NULL, .exit = NULL, + .on_created = NULL, + .on_update = NULL, .on_roller = NULL, .on_click = page_autoscan_on_click, .on_right_button = NULL, diff --git a/src/ui/page_clock.c b/src/ui/page_clock.c index d9dbd78d..effb5892 100644 --- a/src/ui/page_clock.c +++ b/src/ui/page_clock.c @@ -573,6 +573,8 @@ page_pack_t pp_clock = { .create = page_clock_create, .enter = page_clock_enter, .exit = page_clock_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = page_clock_on_roller, .on_click = page_clock_on_click, .on_right_button = NULL, diff --git a/src/ui/page_common.h b/src/ui/page_common.h index 3751db94..1136602f 100644 --- a/src/ui/page_common.h +++ b/src/ui/page_common.h @@ -17,6 +17,7 @@ #define REC_STOP "/mnt/app/app/record/gogglecmd -rec stop" #define REC_STOP_LIVE "/mnt/app/app/record/gogglecmd -rec stopl" #define REC_CONF "/mnt/app/app/record/confs/record.conf" +#define WIFI_DOWNLOAD "/mnt/app/script/online_downloader.sh" #define WIFI_OFF "/mnt/app/script/wlan_stop.sh" #define WIFI_AP_ON "/tmp/wlan_start_ap.sh" #define WIFI_STA_ON "/tmp/wlan_start_sta.sh" @@ -68,6 +69,7 @@ #define DIAL_CLICK_IMG "dial_click.png" #define DIAL_SCROLL_IMG "dial_scroll.png" #define RIGHT_BUTTON_IMG "right_button.png" +#define ALERT_IMG "alert.png" #define MAX_PANELS 9 diff --git a/src/ui/page_elrs.c b/src/ui/page_elrs.c index 617335e8..00a19d25 100644 --- a/src/ui/page_elrs.c +++ b/src/ui/page_elrs.c @@ -113,8 +113,7 @@ static void elrs_status_timer(struct _lv_timer_t *timer) { } } -static void request_uid() -{ +static void request_uid() { msp_send_packet(MSP_GET_BP_STATUS, MSP_PACKET_COMMAND, 0, NULL); lv_timer_t *timer = lv_timer_create(elrs_status_timer, 250, NULL); lv_timer_set_repeat_count(timer, 20); @@ -170,25 +169,25 @@ static void page_elrs_on_click(uint8_t key, int sel) { pthread_mutex_unlock(&lvgl_mutex); mspAwaitResposne_e response = msp_await_resposne(MSP_SET_MODE, 1, (uint8_t *)"O", 120000); pthread_mutex_lock(&lvgl_mutex); - switch(response) { - case AWAIT_SUCCESS: - lv_label_set_text(label_bind_status, "#00FF00 Success#"); - request_uid(); - break; - case AWAIT_TIMEDOUT: - lv_label_set_text(label_bind_status, "#FEBE00 Timeout#"); - break; - case AWAIT_FAILED: - lv_label_set_text(label_bind_status, "#FF0000 FAILED#"); - break; - case AWAIT_CANCELLED: - lv_label_set_text(label_bind_status, "#FEBE00 Cancelled#"); - // repower the module and re-request binding info - disable_esp32(); - if (g_setting.elrs.enable) { - lv_timer_create(elrs_enable_timer, 100, NULL); - } - break; + switch (response) { + case AWAIT_SUCCESS: + lv_label_set_text(label_bind_status, "#00FF00 Success#"); + request_uid(); + break; + case AWAIT_TIMEDOUT: + lv_label_set_text(label_bind_status, "#FEBE00 Timeout#"); + break; + case AWAIT_FAILED: + lv_label_set_text(label_bind_status, "#FF0000 FAILED#"); + break; + case AWAIT_CANCELLED: + lv_label_set_text(label_bind_status, "#FEBE00 Cancelled#"); + // repower the module and re-request binding info + disable_esp32(); + if (g_setting.elrs.enable) { + lv_timer_create(elrs_enable_timer, 100, NULL); + } + break; } lv_obj_add_flag(cancel_label, LV_OBJ_FLAG_HIDDEN); binding = false; @@ -196,8 +195,7 @@ static void page_elrs_on_click(uint8_t key, int sel) { } } -static void page_elrs_on_rbtn(bool is_short) -{ +static void page_elrs_on_rbtn(bool is_short) { if (binding && is_short) { msp_cancel_await(); } @@ -212,6 +210,8 @@ page_pack_t pp_elrs = { .create = page_elrs_create, .enter = page_elrs_enter, .exit = NULL, + .on_created = NULL, + .on_update = NULL, .on_roller = page_elrs_on_roller, .on_click = page_elrs_on_click, .on_right_button = page_elrs_on_rbtn, diff --git a/src/ui/page_fans.c b/src/ui/page_fans.c index 3285458c..a8364997 100644 --- a/src/ui/page_fans.c +++ b/src/ui/page_fans.c @@ -398,6 +398,8 @@ page_pack_t pp_fans = { .create = page_fans_create, .enter = NULL, .exit = page_fans_mode_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = page_fans_mode_on_roller, .on_click = page_fans_mode_on_click, .on_right_button = NULL, diff --git a/src/ui/page_focus_chart.c b/src/ui/page_focus_chart.c index 122840de..798eaa82 100644 --- a/src/ui/page_focus_chart.c +++ b/src/ui/page_focus_chart.c @@ -64,6 +64,8 @@ page_pack_t pp_focus_chart = { .create = page_focus_chart_create, .enter = page_focus_chart_enter, .exit = page_focus_chart_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = NULL, .on_click = page_focus_chart_on_click, .on_right_button = NULL, diff --git a/src/ui/page_headtracker.c b/src/ui/page_headtracker.c index 67c8b11e..990685f1 100644 --- a/src/ui/page_headtracker.c +++ b/src/ui/page_headtracker.c @@ -213,6 +213,8 @@ page_pack_t pp_headtracker = { .create = page_headtracker_create, .enter = page_headtracker_enter, .exit = page_headtracker_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = page_headtracker_on_roller, .on_click = page_headtracker_on_click, .on_right_button = NULL, diff --git a/src/ui/page_imagesettings.c b/src/ui/page_imagesettings.c index 14e9854c..02efe1e5 100644 --- a/src/ui/page_imagesettings.c +++ b/src/ui/page_imagesettings.c @@ -138,6 +138,8 @@ page_pack_t pp_imagesettings = { .create = page_imagesettings_create, .enter = page_imagesettings_enter, .exit = NULL, + .on_created = NULL, + .on_update = NULL, .on_roller = NULL, .on_click = NULL, .on_right_button = NULL, diff --git a/src/ui/page_osd.c b/src/ui/page_osd.c index 5655ab2d..bfd8d4ed 100644 --- a/src/ui/page_osd.c +++ b/src/ui/page_osd.c @@ -159,6 +159,8 @@ page_pack_t pp_osd = { .create = page_osd_create, .enter = NULL, .exit = NULL, + .on_created = NULL, + .on_update = NULL, .on_roller = NULL, .on_click = on_click, .on_right_button = NULL, diff --git a/src/ui/page_playback.c b/src/ui/page_playback.c index bfc6f202..deae92f7 100644 --- a/src/ui/page_playback.c +++ b/src/ui/page_playback.c @@ -18,7 +18,7 @@ #include "ui/page_common.h" #include "ui/ui_player.h" #include "ui/ui_style.h" -#include "util/file.h" +#include "util/filesystem.h" #include "util/math.h" #include "util/system.h" @@ -106,7 +106,7 @@ static void show_pb_item(uint8_t pos, char *label) { lv_obj_clear_flag(pb_ui[pos]._label, LV_OBJ_FLAG_HIDDEN); sprintf(fname, "%s/%s." REC_packJPG, TMP_DIR, label); - if (file_exists(fname)) + if (fs_file_exists(fname)) sprintf(fname, "A:%s/%s." REC_packJPG, TMP_DIR, label); else osd_resource_path(fname, "%s", OSD_RESOURCE_720, DEF_VIDEOICON); @@ -188,7 +188,7 @@ static int walk_sdcard() { sprintf(fname, "%s%s", MEDIA_FILES_DIR, in_file->d_name); - long size = file_get_size(fname); + long size = fs_filesize(fname); size >>= 20; // in MB if (size < 5) { // skip small files @@ -464,6 +464,8 @@ page_pack_t pp_playback = { .create = page_playback_create, .enter = page_playback_enter, .exit = page_playback_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = page_playback_on_roller, .on_click = page_playback_on_click, .on_right_button = page_playback_on_right_button, diff --git a/src/ui/page_power.c b/src/ui/page_power.c index dded9be8..653eb9fb 100644 --- a/src/ui/page_power.c +++ b/src/ui/page_power.c @@ -353,6 +353,8 @@ page_pack_t pp_power = { .create = page_power_create, .enter = NULL, .exit = page_power_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = page_power_on_roller, .on_click = page_power_on_click, .on_right_button = NULL, diff --git a/src/ui/page_record.c b/src/ui/page_record.c index 1cc54685..4aeb6bac 100644 --- a/src/ui/page_record.c +++ b/src/ui/page_record.c @@ -106,6 +106,8 @@ page_pack_t pp_record = { .create = page_record_create, .enter = NULL, .exit = NULL, + .on_created = NULL, + .on_update = NULL, .on_roller = NULL, .on_click = page_record_on_click, .on_right_button = NULL, diff --git a/src/ui/page_scannow.c b/src/ui/page_scannow.c index 8f421893..3d08552a 100644 --- a/src/ui/page_scannow.c +++ b/src/ui/page_scannow.c @@ -430,6 +430,8 @@ page_pack_t pp_scannow = { .create = page_scannow_create, .enter = page_scannow_enter, .exit = page_scannow_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = page_scannow_on_roller, .on_click = page_scannow_on_click, .on_right_button = NULL, diff --git a/src/ui/page_sleep.c b/src/ui/page_sleep.c index 3996674b..afe6a9da 100644 --- a/src/ui/page_sleep.c +++ b/src/ui/page_sleep.c @@ -38,7 +38,6 @@ static fan_speed_t fan_speed_save; static void page_sleep_enter() { LOGI("page_sleep_enter"); - go_sleep(); } @@ -46,6 +45,8 @@ page_pack_t pp_sleep = { .create = page_sleep_create, .enter = page_sleep_enter, .exit = NULL, + .on_created = NULL, + .on_update = NULL, .on_roller = NULL, .on_click = NULL, .on_right_button = NULL, diff --git a/src/ui/page_source.c b/src/ui/page_source.c index 5c2a53f1..7e3bf5dc 100644 --- a/src/ui/page_source.c +++ b/src/ui/page_source.c @@ -213,6 +213,8 @@ page_pack_t pp_source = { .create = page_source_create, .enter = page_source_enter, .exit = page_source_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = NULL, .on_click = page_source_on_click, .on_right_button = NULL, diff --git a/src/ui/page_storage.c b/src/ui/page_storage.c index e35c0c05..cf3a3dd4 100644 --- a/src/ui/page_storage.c +++ b/src/ui/page_storage.c @@ -9,7 +9,7 @@ #include "core/common.hh" #include "core/settings.h" #include "ui/page_playback.h" -#include "util/file.h" +#include "util/filesystem.h" #include "util/sdcard.h" #include "util/system.h" @@ -125,7 +125,7 @@ static format_codes_t page_storage_format_sd() { system_exec(shell_command); int timeout_interval = 0; - while (!file_exists(log_file) && ++timeout_interval < 5) { + while (!fs_file_exists(log_file) && ++timeout_interval < 5) { sleep(1); } @@ -133,7 +133,7 @@ static format_codes_t page_storage_format_sd() { status = FMC_ERR_PROCESS_DID_NOT_START; } else { timeout_interval = 0; - while (!file_exists(results_file) && ++timeout_interval < 60) { + while (!fs_file_exists(results_file) && ++timeout_interval < 60) { sleep(1); } if (timeout_interval > 60) { @@ -197,7 +197,7 @@ static repair_codes_t page_storage_repair_sd() { system_exec(shell_command); int timeout_interval = 0; - while (!file_exists(log_file) && ++timeout_interval < 5) { + while (!fs_file_exists(log_file) && ++timeout_interval < 5) { sleep(1); } @@ -205,7 +205,7 @@ static repair_codes_t page_storage_repair_sd() { status = RPC_ERR_PROCESS_DID_NOT_START; } else { timeout_interval = 0; - while (!file_exists(results_file) && ++timeout_interval < 60) { + while (!fs_file_exists(results_file) && ++timeout_interval < 60) { sleep(1); } if (timeout_interval > 60) { @@ -373,7 +373,7 @@ static lv_obj_t *page_storage_create(lv_obj_t *parent, panel_arr_t *arr) { lv_label_set_text(page_storage.note, "Self-Test is enabled, All storage options are disabled."); page_storage.disable_controls = true; } else { - if (file_exists(DEVELOP_SCRIPT) || file_exists(APP_BIN_FILE)) { + if (fs_file_exists(DEVELOP_SCRIPT) || fs_file_exists(APP_BIN_FILE)) { char text[256]; snprintf(text, sizeof(text), "Detected files being accessed by SD Card, All storage options are disabled.\n" "Remove the following files from the SD Card and try again:\n" DEVELOP_SCRIPT "\n" APP_BIN_FILE); @@ -492,6 +492,8 @@ page_pack_t pp_storage = { .create = page_storage_create, .enter = page_storage_enter, .exit = page_storage_exit, + .on_created = NULL, + .on_update = NULL, .on_roller = page_storage_on_roller, .on_click = page_storage_on_click, .on_right_button = page_storage_on_right_button, diff --git a/src/ui/page_version.c b/src/ui/page_version.c index bf9a7f2d..ceb3d812 100644 --- a/src/ui/page_version.c +++ b/src/ui/page_version.c @@ -1,5 +1,6 @@ #include "page_version.h" +#include #include #include #include @@ -11,6 +12,7 @@ #include "core/app_state.h" #include "core/elrs.h" #include "core/esp32_flash.h" +#include "core/osd.h" #include "core/settings.h" #include "driver/beep.h" #include "driver/dm5680.h" @@ -21,7 +23,8 @@ #include "ui/page_common.h" #include "ui/ui_main_menu.h" #include "ui/ui_style.h" -#include "util/file.h" +#include "util/filesystem.h" +#include "util/strings.h" #include "util/system.h" enum { @@ -41,6 +44,26 @@ typedef enum { CONFIRMATION_TIMEOUT } ui_confirmation_t; +typedef struct { + void (*flash)(); + panel_arr_t page; + panel_arr_t this; + lv_obj_t *container; + lv_obj_t *msgbox; + lv_obj_t *dropdown; + lv_obj_t *update; + lv_obj_t *back; + char *alt_title; + char path[256]; + char **files; + bool dropdown_focused; + bool visible; + int which; + int count; + bool zipped; + bool ready; +} fw_select_t; + static lv_coord_t col_dsc[] = {160, 160, 160, 160, 160, 160, 160, LV_GRID_TEMPLATE_LAST}; static lv_coord_t row_dsc[] = {60, 60, 60, 60, 60, 60, 60, 60, 60, 60, LV_GRID_TEMPLATE_LAST}; @@ -54,6 +77,12 @@ static lv_obj_t *btn_esp = NULL; static lv_obj_t *label_esp = NULL; static lv_obj_t *msgbox_update_complete = NULL; static lv_obj_t *msgbox_settings_reset = NULL; +static lv_obj_t *msgbox_release_notes = NULL; +static lv_obj_t *label_note = NULL; +static lv_obj_t *alert_img = NULL; +static fw_select_t fw_select_goggle; +static fw_select_t fw_select_vtx; +static fw_select_t *fw_select_current = &fw_select_vtx; #define ADDR_AL 0x65 #define ADDR_FPGA 0x64 @@ -63,8 +92,8 @@ static lv_obj_t *msgbox_settings_reset = NULL; static bool is_need_update_progress = false; static bool reboot_flag = false; static lv_obj_t *cur_ver_label; - static int reset_all_settings_confirm = CONFIRMATION_UNCONFIRMED; +static atomic_bool autoscan_filesystem = ATOMIC_VAR_INIT(true); #undef RETURN_ON_ERROR #define RETURN_ON_ERROR(m, x) \ @@ -76,6 +105,15 @@ static int reset_all_settings_confirm = CONFIRMATION_UNCONFIRMED; } \ } while (0) +/** + * Declarations + */ +static void page_version_on_roller(uint8_t key); +static void page_version_on_click(uint8_t key, int sel); +static void page_version_on_right_button(bool is_short); +static void page_version_on_roller_fw_select(uint8_t key); +static void page_version_on_click_fw_select(uint8_t key, int sel); + static esp_loader_error_t flash_esp32_file(char *path, uint32_t offset) { char fpath[80]; strcpy(fpath, "/mnt/extsd/ELRS/"); @@ -144,6 +182,120 @@ static bool flash_elrs() { return ret; } +static int flash_hdzero(const char *dst_path, const char *dst_file, + const char *src_path, const char *src_file, + const char *update_script, bool is_zipped) { + uint8_t ret = 2; + char cmd_buff[1024] = {0}; + + // Flush working directory + snprintf(cmd_buff, + sizeof(cmd_buff), + "rm -rf %s && mkdir -p %s", + dst_path, dst_path); + + if (0 == system_exec(cmd_buff)) { + // Extract or copy files to working directory + if (is_zipped) { + snprintf(cmd_buff, sizeof(cmd_buff), + "unzip %s/%s -d %s", + src_path, src_file, dst_path); + } else { + snprintf(cmd_buff, sizeof(cmd_buff), + "cp -a %s/%s %s/%s", + src_path, src_file, + dst_path, dst_file); + } + // Now begin flashing + if (0 == system_exec(cmd_buff)) { + snprintf(cmd_buff, sizeof(cmd_buff), + "%s %s/%s", + update_script, dst_path, dst_file); + ret = command_monitor(cmd_buff); + } + } + + return ret; +} + +static void flash_vtx() { + uint8_t ret = 2; + char cmd_buff[1024] = {0}; + + lv_obj_clear_flag(bar_vtx, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(btn_vtx, "Flashing..."); + lv_timer_handler(); + + is_need_update_progress = true; + ret = flash_hdzero("/tmp/VTX", + "HDZERO_TX.bin", + fw_select_vtx.path, + fw_select_vtx.files[fw_select_vtx.which], + "/mnt/app/script/update_vtx.sh", + fw_select_vtx.zipped); + is_need_update_progress = false; + + if (ret == 1) { + if (fs_compare_files("/tmp/HDZERO_TX.bin", "/tmp/HDZERO_TX_RB.bin")) { + lv_label_set_text(btn_vtx, "#00FF00 SUCCESS#"); + } else + lv_label_set_text(btn_vtx, "#FF0000 Verification failed, try it again#"); + } else if (ret == 2) { + lv_label_set_text(btn_vtx, "#FFFF00 No firmware found.#"); + } else { + lv_label_set_text(btn_vtx, "#FF0000 Failed, check connection...#"); + } + lv_timer_handler(); + + system_exec("rm /tmp/HDZERO_TX.bin"); + system_exec("rm /tmp/HDZERO_TX_RB.bin"); + + sleep(2); + beep(); + sleep(2); + + lv_obj_add_flag(bar_vtx, LV_OBJ_FLAG_HIDDEN); +} + +static void flash_goggle() { + uint8_t ret = 0; + char cmd_buff[1024] = {0}; + + lv_obj_clear_flag(bar_goggle, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(btn_goggle, "WAIT... DO NOT POWER OFF... "); + lv_timer_handler(); + + is_need_update_progress = true; + ret = flash_hdzero("/tmp/GOGGLE", + fw_select_goggle.files[fw_select_goggle.which], + fw_select_goggle.path, + fw_select_goggle.files[fw_select_goggle.which], + "/mnt/app/script/update_goggle.sh", + fw_select_goggle.zipped); + is_need_update_progress = false; + + lv_obj_add_flag(bar_goggle, LV_OBJ_FLAG_HIDDEN); + if (ret == 1) { + lv_obj_clear_flag(msgbox_update_complete, LV_OBJ_FLAG_HIDDEN); + lv_timer_handler(); + app_state_push(APP_STATE_USER_INPUT_DISABLED); + beep(); + usleep(1000000); + beep(); + usleep(1000000); + beep(); + reboot_flag = true; + lv_timer_handler(); + } else if (ret == 2) { + lv_label_set_text(btn_goggle, "#FFFF00 No firmware found.#"); + } else if (ret == 3) { + lv_label_set_text(btn_goggle, "#FFFF00 Multiple versions been found. Keep only one.#"); + } else { + lv_label_set_text(btn_goggle, "#FF0000 FAILED#"); + } + lv_obj_add_flag(bar_goggle, LV_OBJ_FLAG_HIDDEN); +} + int generate_current_version(sys_version_t *sys_ver) { sys_ver->va = I2C_Read(ADDR_FPGA, 0xff); sys_ver->rx = rx_status[0].rx_ver; @@ -193,6 +345,413 @@ int generate_current_version(sys_version_t *sys_ver) { return 0; } +static const char *page_version_find_latest_fw(const char *path) { + char *dname = NULL; + DIR *dir = opendir(path); + if (dir) { + struct dirent *entry = readdir(dir); + while (entry != NULL) { + if (entry->d_type == DT_DIR) { + if (dname != NULL) { + if (str_compare_versions(entry->d_name, dname) > 0) { + dname = entry->d_name; + } + } else { + dname = entry->d_name; + } + } + entry = readdir(dir); + } + closedir(dir); + } + return dname; +} + +static int page_version_get_latest_fw_path(const char *device, char *path, size_t size) { + char tmp_path[256], sdc_path[256]; + snprintf(tmp_path, sizeof(tmp_path), "/tmp/FIRMWARE/%s", device); + snprintf(sdc_path, sizeof(sdc_path), "/mnt/extsd/FIRMWARE/%s", device); + + const char *tmp_latest = page_version_find_latest_fw(tmp_path); + const char *sdc_latest = page_version_find_latest_fw(sdc_path); + + if (tmp_latest && sdc_latest) { + if (str_compare_versions(tmp_latest, sdc_latest) > 0) { + sdc_latest = NULL; + } else { + tmp_latest = NULL; + } + } + + if (tmp_latest) { + return snprintf(path, size, "%s/%s", tmp_path, tmp_latest); + } else if (sdc_latest) { + return snprintf(path, size, "%s/%s", sdc_path, sdc_latest); + } else { + return 0; + } +} + +static void page_version_fw_select_reset(fw_select_t *fw_select) { + if (fw_select->count) { + for (int i = 0; i < fw_select->count; ++i) { + free(fw_select->files[i]); + fw_select->files[i] = NULL; + } + free(fw_select->files); + fw_select->ready = false; + fw_select->files = NULL; + fw_select->count = 0; + fw_select->zipped = false; + fw_select->alt_title = NULL; + } +} + +static int page_version_get_latest_fw_files(fw_select_t *fw_select, const char *pattern, bool has_release_notes) { + DIR *dir = opendir(fw_select->path); + if (dir) { + struct dirent *entry = readdir(dir); + while (entry != NULL) { + if (entry->d_type == DT_REG) { + if (strstr(entry->d_name, pattern)) { + bool match = false; + for (int j = 0; j < fw_select->count; ++j) { + if (0 == strcmp(fw_select->files[j], entry->d_name)) { + match = true; + break; + } + } + if (!match) { + if (fw_select->count == 0) { + fw_select->files = malloc(sizeof(char *) * 1); + } else { + fw_select->files = realloc(fw_select->files, sizeof(char *) * (fw_select->count + 1)); + } + fw_select->files[fw_select->count++] = strdup(entry->d_name); + if (strstr(entry->d_name, ".zip")) { + fw_select->zipped = true; + } + } + } else if (strstr(entry->d_name, "release.notes")) { + fw_select->ready = true; + } + } + + entry = readdir(dir); + } + closedir(dir); + + if (has_release_notes) { + if (!fw_select->ready) { + page_version_fw_select_reset(fw_select); + } else if (fw_select->count > 1) { + str_qsort(&fw_select->files[0], fw_select->count); + } + } else if (fw_select->count > 0) { + fw_select->ready = true; + } + } + + return fw_select->count; +} + +static void page_version_fw_scan_for_updates() { + bool has_online_goggle_update = false; + bool has_online_vtx_update = false; + + page_version_fw_select_reset(&fw_select_goggle); + snprintf(fw_select_goggle.path, sizeof(fw_select_goggle.path), "/mnt/extsd"); + page_version_get_latest_fw_files(&fw_select_goggle, "HDZERO_GOGGLE", false); + + if (fw_select_goggle.ready) { + fw_select_goggle.alt_title = "SD Card"; + } + + page_version_fw_select_reset(&fw_select_vtx); + snprintf(fw_select_vtx.path, sizeof(fw_select_vtx.path), "/mnt/extsd"); + page_version_get_latest_fw_files(&fw_select_vtx, "HDZERO_TX", false); + + if (fw_select_vtx.ready) { + fw_select_vtx.alt_title = "SD Card"; + } + + if (g_setting.wifi.enable) { + if (!fw_select_goggle.ready) { + has_online_goggle_update = + 0 < page_version_get_latest_fw_path("GOGGLE", fw_select_goggle.path, sizeof(fw_select_goggle.path)) && + 0 < page_version_get_latest_fw_files(&fw_select_goggle, ".bin", true); + } + + if (!fw_select_vtx.ready) { + has_online_vtx_update = + 0 < page_version_get_latest_fw_path("VTX", fw_select_vtx.path, sizeof(fw_select_vtx.path)) && + 0 < page_version_get_latest_fw_files(&fw_select_vtx, ".zip", true); + } + + if (has_online_goggle_update || has_online_vtx_update) { + lv_label_set_text(label_note, "To view release notes, select either Update VTX or Update Goggle\n" + "then press the Func button to display or hide the release notes."); + } else if (fw_select_goggle.alt_title || fw_select_vtx.alt_title) { + lv_label_set_text(label_note, "Remove HDZERO_TX or HDZERO_GOGGLE binary files from the root of\n" + "SD Card in order to install the latest online downloaded firmware files."); + } + } else { + lv_label_set_text(label_note, ""); + } +} + +static bool page_version_release_notes_active() { + return !lv_obj_has_flag(msgbox_release_notes, LV_OBJ_FLAG_HIDDEN); +} + +static void page_version_release_notes_show(fw_select_t *fw_select) { + static char buff[512]; + static char tbuff[128]; + static char mbuff[2048]; + + snprintf(buff, sizeof(buff), "%s/release.notes", fw_select->path); + FILE *notes = fopen(buff, "r"); + + if (notes) { + int max_msg_box_width = 1280; + int max_line_length = 1; + size_t written = 0; + size_t nbytes = 0; + size_t rbytes = 0; + char *line = NULL; + + while (-1 != (rbytes = getline(&line, &nbytes, notes)) && written < sizeof(mbuff)) { + max_line_length = rbytes > max_line_length ? rbytes : max_line_length; + // Read until buffer only contains 256 characters are left. + if (sizeof(mbuff) - written > 256) { + if (memcpy(&mbuff[written], line, rbytes)) { + written += rbytes; + } + } else { + strcpy(&mbuff[written], "\n\nVisit https://github.com/hdzero for the complete list of changes."); + break; + } + } + free(line); + fclose(notes); + + lv_obj_t *title = lv_msgbox_get_title(msgbox_release_notes); + lv_obj_t *message = lv_msgbox_get_text(msgbox_release_notes); + int msg_box_width = ((max_line_length / 10)) * 100; + if (msg_box_width > 1280) { + msg_box_width = 1280; + } else if (msg_box_width < 600) { + msg_box_width = 600; + } + + snprintf(tbuff, sizeof(tbuff), "Release Notes: %s", fs_basename(fw_select->path)); + lv_label_set_text_static(title, tbuff); + lv_label_set_text_static(message, mbuff); + lv_obj_set_style_text_font(message, &lv_font_montserrat_16, 0); + lv_obj_set_width(msgbox_release_notes, msg_box_width); + lv_obj_clear_flag(msgbox_release_notes, LV_OBJ_FLAG_HIDDEN); + + // Mark file as read and remove alert only if there are + // no binary files detected on the root of the sd card. + if (!fw_select->alt_title) { + snprintf(buff, sizeof(buff), "touch %s/release.notes.checked", fw_select->path); + if (!fs_file_exists(buff)) { + if (0 == system_exec(buff)) { + lv_obj_add_flag(alert_img, LV_OBJ_FLAG_HIDDEN); + } + } + } + + // Disable scrolling + pp_version.p_arr.max = 0; + } +} +static void page_version_release_notes_hide() { + // Restore scrolling + pp_version.p_arr.max = ROW_COUNT; + lv_obj_add_flag(msgbox_release_notes, LV_OBJ_FLAG_HIDDEN); +} + +static void page_version_fw_select_toggle_panel(fw_select_t *fw_select) { + fw_select_current = fw_select; + fw_select_current->visible = !fw_select_current->visible; + + if (fw_select_current->visible) { + fw_select_current->page = pp_version.p_arr; + pp_version.p_arr = fw_select_current->this; + pp_version.on_roller = page_version_on_roller_fw_select; + pp_version.on_click = page_version_on_click_fw_select; + pp_version.on_right_button = NULL; + } else { + for (int i = 0; i < pp_version.p_arr.max; ++i) { + lv_obj_add_flag(pp_version.p_arr.panel[i], LV_OBJ_FLAG_HIDDEN); + } + lv_obj_add_style(fw_select_current->dropdown, &style_dropdown, LV_PART_MAIN); + + pp_version.p_arr.cur = 0; + fw_select_current->this = pp_version.p_arr; + pp_version.p_arr = fw_select_current->page; + pp_version.on_roller = page_version_on_roller; + pp_version.on_click = page_version_on_click; + pp_version.on_right_button = page_version_on_right_button; + } +} + +static void page_version_fw_select_populate(fw_select_t *fw_select) { + int max_line_length = 1; + if (fw_select->count) { + char buffer[1024] = {0}; + int written = 0; + for (int i = 0; i < fw_select->count; ++i) { + int len = strlen(fw_select->files[i]); + max_line_length = len > max_line_length ? len : max_line_length; + written += snprintf(&buffer[written], sizeof(buffer) - written, "%s\n", fw_select->files[i]); + } + buffer[written - 1] = '\0'; + + lv_dropdown_set_options(fw_select->dropdown, buffer); + lv_dropdown_set_selected(fw_select->dropdown, fw_select->which); + lv_dropdown_set_text(fw_select->dropdown, fw_select->files[fw_select->which]); + } + + int text_width = ((max_line_length / 10)) * 175; + int msg_box_width = text_width + 200; + if (msg_box_width > 825) { + msg_box_width = 825; + } else if (msg_box_width < 600) { + msg_box_width = 600; + } + + lv_obj_set_size(fw_select->container, msg_box_width - 50, 200); + lv_obj_set_width(fw_select->msgbox, msg_box_width); + lv_obj_set_width(fw_select->dropdown, msg_box_width - 150); +} + +static void page_version_fw_select_show(const char *title, fw_select_t *fw_select) { + static char text[1024]; + if (fw_select->ready) { + snprintf(text, sizeof(text), + "%s %s", title, + fw_select->alt_title ? fw_select->alt_title : fs_basename(fw_select->path)); + } else { + snprintf(text, sizeof(text), "%s %s", title, "not found"); + } + + page_version_fw_select_populate(fw_select); + lv_label_set_text(lv_msgbox_get_title(fw_select->msgbox), text); + lv_obj_clear_flag(fw_select->msgbox, LV_OBJ_FLAG_HIDDEN); + page_version_fw_select_toggle_panel(fw_select); +} + +static void page_version_fw_select_hide(fw_select_t *fw_select) { + lv_obj_add_flag(fw_select->msgbox, LV_OBJ_FLAG_HIDDEN); +} + +static void page_version_on_roller_fw_select(uint8_t key) { + for (int i = 0; i < pp_version.p_arr.max; ++i) { + lv_obj_add_flag(pp_version.p_arr.panel[i], LV_OBJ_FLAG_HIDDEN); + } + lv_obj_remove_style(fw_select_current->dropdown, &style_dropdown, LV_PART_MAIN); + + if (fw_select_current->dropdown_focused) { + if (key == DIAL_KEY_UP) { + if (++fw_select_current->which >= fw_select_current->count) { + fw_select_current->which = fw_select_current->count - 1; + } + uint32_t evt = LV_KEY_DOWN; + lv_event_send(fw_select_current->dropdown, LV_EVENT_KEY, &evt); + } else if (key == DIAL_KEY_DOWN) { + if (--fw_select_current->which < 0) { + fw_select_current->which = 0; + } + uint32_t evt = LV_KEY_UP; + lv_event_send(fw_select_current->dropdown, LV_EVENT_KEY, &evt); + } + } + + switch (pp_version.p_arr.cur) { + case 0: + lv_obj_add_style(fw_select_current->dropdown, &style_dropdown, LV_PART_MAIN); + break; + default: + lv_obj_clear_flag(pp_version.p_arr.panel[pp_version.p_arr.cur], LV_OBJ_FLAG_HIDDEN); + break; + } +} + +static void page_version_on_click_fw_select(uint8_t key, int sel) { + switch (sel) { + case 0: + if (fw_select_current->count > 1) { + if (!fw_select_current->dropdown_focused) { + fw_select_current->dropdown_focused = true; + lv_dropdown_open(fw_select_current->dropdown); + pp_version.p_arr.max = 0; + } else { + fw_select_current->dropdown_focused = false; + lv_event_send(fw_select_current->dropdown, LV_EVENT_RELEASED, NULL); + lv_dropdown_set_text(fw_select_current->dropdown, fw_select_current->files[fw_select_current->which]); + pp_version.p_arr.max = 3; + } + } + break; + case 1: + if (fw_select_current->count) { + page_version_fw_select_hide(fw_select_current); + page_version_fw_select_toggle_panel(fw_select_current); + fw_select_current->flash(); + } + break; + case 2: + page_version_fw_select_hide(fw_select_current); + page_version_fw_select_toggle_panel(fw_select_current); + break; + } +} + +static void page_version_fw_select_create(const char *device, fw_select_t *fw_select, void (*flash)()) { + static lv_coord_t msgbox_col_dsc[] = {40, 160, 160, 160, 160, 160, 160, LV_GRID_TEMPLATE_LAST}; + static lv_coord_t mbsbox_row_dsc[] = {60, 60, 60, 60, 60, 60, 60, 60, 60, 60, LV_GRID_TEMPLATE_LAST}; + + char text[256]; + snprintf(text, sizeof(text), "Update %s", device); + + fw_select->flash = flash; + fw_select->msgbox = create_msgbox_item(device, "Target:"); + fw_select->container = lv_obj_create(fw_select->msgbox); + + lv_obj_set_pos(fw_select->container, 0, 0); + lv_obj_set_layout(fw_select->container, LV_LAYOUT_GRID); + lv_obj_clear_flag(fw_select->container, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_add_style(fw_select->container, &style_context, LV_PART_MAIN); + lv_obj_set_style_bg_color(fw_select->container, lv_color_make(19, 19, 19), 0); + lv_obj_set_style_grid_column_dsc_array(fw_select->container, msgbox_col_dsc, 0); + lv_obj_set_style_grid_row_dsc_array(fw_select->container, mbsbox_row_dsc, 0); + + fw_select->this.max = 3; + create_select_item(&fw_select->this, fw_select->container); + for (int i = 0; i < fw_select->this.max; ++i) { + lv_obj_set_style_bg_color(fw_select->this.panel[i], lv_color_make(0x44, 0x44, 0x44), 0); + } + fw_select->page = pp_version.p_arr; + fw_select->dropdown = create_dropdown_item(fw_select->container, "", 1, 0, 600, 40, 1, 4, LV_GRID_ALIGN_START, &lv_font_montserrat_26); + fw_select->update = create_label_item(fw_select->container, text, 1, 1, 4); + fw_select->back = create_label_item(fw_select->container, "< Back", 1, 2, 4); + + lv_obj_set_style_grid_column_dsc_array(fw_select->msgbox, col_dsc, 0); + lv_obj_set_style_grid_row_dsc_array(fw_select->msgbox, row_dsc, 0); + lv_obj_add_style(fw_select->dropdown, &style_dropdown, LV_PART_MAIN); + lv_obj_add_style(fw_select->update, &style_context, LV_PART_MAIN); + lv_obj_add_style(fw_select->back, &style_context, LV_PART_MAIN); + + lv_obj_t *list = lv_dropdown_get_list(fw_select->dropdown); + lv_obj_add_style(list, &style_dropdown, LV_PART_MAIN); + lv_obj_set_style_text_color(list, lv_color_make(0, 0, 0), LV_PART_SELECTED | LV_STATE_CHECKED); + + page_version_fw_select_populate(fw_select); + page_version_fw_select_hide(fw_select); +} + static lv_obj_t *page_version_create(lv_obj_t *parent, panel_arr_t *arr) { lv_obj_t *page = lv_menu_page_create(parent, NULL); lv_obj_clear_flag(page, LV_OBJ_FLAG_SCROLLABLE); @@ -250,9 +809,63 @@ static lv_obj_t *page_version_create(lv_obj_t *parent, panel_arr_t *arr) { msgbox_settings_reset = create_msgbox_item("Settings reset", "All settings have been reset.\nPlease repower goggle now."); lv_obj_add_flag(msgbox_settings_reset, LV_OBJ_FLAG_HIDDEN); + msgbox_release_notes = create_msgbox_item("Release Notes", "Empty"); + lv_obj_add_flag(msgbox_release_notes, LV_OBJ_FLAG_HIDDEN); + + label_note = lv_label_create(cont); + lv_label_set_text(label_note, ""); + lv_obj_set_style_text_font(label_note, &lv_font_montserrat_16, 0); + lv_obj_set_style_text_align(label_note, LV_TEXT_ALIGN_LEFT, 0); + lv_obj_set_style_text_color(label_note, lv_color_make(255, 255, 255), 0); + lv_obj_set_style_pad_top(label_note, 12, 0); + lv_label_set_long_mode(label_note, LV_LABEL_LONG_WRAP); + lv_obj_set_grid_cell(label_note, LV_GRID_ALIGN_START, 1, 4, LV_GRID_ALIGN_START, 6, 2); + + page_version_fw_scan_for_updates(); + page_version_fw_select_create("Goggle", &fw_select_goggle, flash_goggle); + page_version_fw_select_create("VTX", &fw_select_vtx, flash_vtx); + return page; } +static void page_version_on_created() { + alert_img = lv_img_create(pp_version.label); + char filename[256]; + osd_resource_path(filename, "%s", OSD_RESOURCE_720, ALERT_IMG); + lv_img_set_src(alert_img, filename); + + lv_obj_add_flag(alert_img, LV_OBJ_FLAG_FLOATING); + lv_obj_clear_flag(alert_img, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_add_flag(alert_img, LV_OBJ_FLAG_HIDDEN); + lv_obj_set_pos(alert_img, 125, 0); + + /** + * If user reads release notes, then we can remove the alert. + */ + static char checked[1024]; + snprintf(checked, sizeof(checked), "%s/release.notes.checked", fw_select_goggle.path); + if (fs_file_exists(checked)) { + lv_obj_add_flag(alert_img, LV_OBJ_FLAG_HIDDEN); + } else { + static char notes[1024]; + snprintf(notes, sizeof(notes), "%s/release.notes", fw_select_goggle.path); + if (fs_file_exists(notes)) { + lv_obj_clear_flag(alert_img, LV_OBJ_FLAG_HIDDEN); + } + } +} + +static void page_version_on_update(uint32_t delta_ms) { + static uint32_t elapsed_ms = 0; + + if ((elapsed_ms += delta_ms) > 5000) { + elapsed_ms = 0; + if (autoscan_filesystem) { + page_version_fw_scan_for_updates(); + } + } +} + uint8_t command_monitor(char *cmd) { FILE *stream; char buf[128]; @@ -298,7 +911,12 @@ static void elrs_version_timer(struct _lv_timer_t *timer) { lv_label_set_text(label_esp, label); } +static void reset_all_settings_reset_label_text() { + lv_label_set_text(btn_reset_all_settings, "Reset all settings"); +} + static void page_version_enter() { + autoscan_filesystem = false; version_update_title(); lv_label_set_text(label_esp, ""); @@ -307,8 +925,11 @@ static void page_version_enter() { lv_timer_set_repeat_count(timer, 20); } -static void reset_all_settings_reset_label_text() { - lv_label_set_text(btn_reset_all_settings, "Reset all settings"); +static void page_version_exit() { + lv_obj_add_flag(msgbox_release_notes, LV_OBJ_FLAG_HIDDEN); + page_version_fw_select_hide(&fw_select_vtx); + page_version_fw_select_hide(&fw_select_goggle); + autoscan_filesystem = true; } static void page_version_on_roller(uint8_t key) { @@ -321,124 +942,85 @@ static void page_version_on_roller(uint8_t key) { } static void page_version_on_click(uint8_t key, int sel) { - version_update_title(); - if (sel == ROW_CUR_VERSION) { - FILE *fp; - char buf[80]; - int dat[16]; - fp = fopen("/tmp/wr_reg", "r"); - if (fp) { + if (!page_version_release_notes_active()) { + version_update_title(); + if (sel == ROW_CUR_VERSION) { + FILE *fp; + char buf[80]; + int dat[16]; + fp = fopen("/tmp/wr_reg", "r"); + if (fp) { + while (fgets(buf, 80, fp)) { + sscanf(buf, "%x %x %x", &dat[0], &dat[1], &dat[2]); + DM5680_WriteReg(dat[0], dat[1], dat[2]); + LOGI("DM5680 REG[%02x,%02x]<-%02x", dat[0], dat[1], dat[2]); + usleep(100000); + } + fclose(fp); + // system_exec("rm /tmp/wr_reg"); + } + + fp = fopen("/tmp/rd_reg", "r"); + if (!fp) + return; while (fgets(buf, 80, fp)) { - sscanf(buf, "%x %x %x", &dat[0], &dat[1], &dat[2]); - DM5680_WriteReg(dat[0], dat[1], dat[2]); - LOGI("DM5680 REG[%02x,%02x]<-%02x", dat[0], dat[1], dat[2]); - usleep(100000); + sscanf(buf, "%x %x", &dat[0], &dat[1]); + DM5680_ReadReg(dat[0], dat[1]); + sleep(1); + LOGI("DM5680_0 REG[%02x,%02x]-> %02x", dat[0], dat[1], rx_status[0].rx_regval); + LOGI("DM5680_1 REG[%02x,%02x]-> %02x", dat[0], dat[1], rx_status[1].rx_regval); } fclose(fp); - // system_exec("rm /tmp/wr_reg"); - } - - fp = fopen("/tmp/rd_reg", "r"); - if (!fp) - return; - while (fgets(buf, 80, fp)) { - sscanf(buf, "%x %x", &dat[0], &dat[1]); - DM5680_ReadReg(dat[0], dat[1]); - sleep(1); - LOGI("DM5680_0 REG[%02x,%02x]-> %02x", dat[0], dat[1], rx_status[0].rx_regval); - LOGI("DM5680_1 REG[%02x,%02x]-> %02x", dat[0], dat[1], rx_status[1].rx_regval); - } - fclose(fp); - // system_exec("rm /tmp/rd_reg"); - } else if (sel == ROW_RESET_ALL_SETTINGS) { - if (reset_all_settings_confirm) { - settings_reset(); - reset_all_settings_reset_label_text(); - lv_obj_clear_flag(msgbox_settings_reset, LV_OBJ_FLAG_HIDDEN); - app_state_push(APP_STATE_USER_INPUT_DISABLED); - } else { - lv_label_set_text(btn_reset_all_settings, "#FFFF00 click to confirm/scroll to cancel#"); - reset_all_settings_confirm = CONFIRMATION_CONFIRMED; + // system_exec("rm /tmp/rd_reg"); + } else if (sel == ROW_RESET_ALL_SETTINGS) { + if (reset_all_settings_confirm) { + settings_reset(); + reset_all_settings_reset_label_text(); + lv_obj_clear_flag(msgbox_settings_reset, LV_OBJ_FLAG_HIDDEN); + app_state_push(APP_STATE_USER_INPUT_DISABLED); + } else { + lv_label_set_text(btn_reset_all_settings, "#FFFF00 click to confirm/scroll to cancel#"); + reset_all_settings_confirm = CONFIRMATION_CONFIRMED; + } + } else if (sel == ROW_UPDATE_VTX) { + page_version_fw_scan_for_updates(); + page_version_fw_select_show("VTX Firmware", &fw_select_vtx); + } else if ((sel == ROW_UPDATE_GOGGLE) && !reboot_flag) { + page_version_fw_scan_for_updates(); + page_version_fw_select_show("Goggle Firmware", &fw_select_goggle); + } else if (sel == ROW_UPDATE_ESP32) { // flash ESP via SD + lv_obj_clear_flag(bar_esp, LV_OBJ_FLAG_HIDDEN); + lv_obj_add_flag(label_esp, LV_OBJ_FLAG_HIDDEN); + lv_label_set_text(btn_esp, "Flashing..."); + lv_timer_handler(); + esp_loader_error_t ret = flash_elrs(); + lv_obj_add_flag(bar_esp, LV_OBJ_FLAG_HIDDEN); + lv_obj_clear_flag(label_esp, LV_OBJ_FLAG_HIDDEN); + if (ret == ESP_LOADER_SUCCESS) + lv_label_set_text(btn_esp, "#00FF00 Success#"); + else + lv_label_set_text(btn_esp, "#FF0000 FAILED#"); + page_version_enter(); } - } else if (sel == ROW_UPDATE_VTX) { - uint8_t ret; - lv_obj_clear_flag(bar_vtx, LV_OBJ_FLAG_HIDDEN); - lv_label_set_text(btn_vtx, "Flashing..."); - lv_timer_handler(); + } +} - is_need_update_progress = true; - ret = command_monitor("/mnt/app/script/update_vtx.sh"); - is_need_update_progress = false; - - if (ret == 1) { - if (file_compare("/tmp/HDZERO_TX.bin", "/tmp/HDZERO_TX_RB.bin")) { - lv_label_set_text(btn_vtx, "#00FF00 SUCCESS#"); - } else - lv_label_set_text(btn_vtx, "#FF0000 Verification failed, try it again#"); - } else if (ret == 2) { - lv_label_set_text(btn_vtx, "#FFFF00 No firmware found.#"); +void page_version_on_right_button(bool is_short) { + if (is_short) { + if (!page_version_release_notes_active()) { + switch (pp_version.p_arr.cur) { + case ROW_UPDATE_VTX: + page_version_release_notes_show(&fw_select_vtx); + break; + case ROW_UPDATE_GOGGLE: + page_version_release_notes_show(&fw_select_goggle); + break; + default: + break; + } } else { - lv_label_set_text(btn_vtx, "#FF0000 Failed, check connection...#"); + page_version_release_notes_hide(); } - lv_timer_handler(); - - system_exec("rm /tmp/HDZERO_TX.bin"); - system_exec("rm /tmp/HDZERO_TX_RB.bin"); - - sleep(2); - beep(); - sleep(2); - - lv_obj_add_flag(bar_vtx, LV_OBJ_FLAG_HIDDEN); - } else if ((sel == ROW_UPDATE_GOGGLE) && !reboot_flag) { - uint8_t ret = 0; - lv_obj_clear_flag(bar_goggle, LV_OBJ_FLAG_HIDDEN); - lv_label_set_text(btn_goggle, "WAIT... DO NOT POWER OFF... "); - lv_timer_handler(); - - is_need_update_progress = true; - ret = command_monitor("/mnt/app/script/update_goggle.sh"); - is_need_update_progress = false; - lv_obj_add_flag(bar_goggle, LV_OBJ_FLAG_HIDDEN); - if (ret == 1) { - // bool b1 = file_compare("/tmp//tmp/goggle_update/HDZERO_RX.bin","/tmp//tmp/goggle_update/HDZERO_RX_RBL.bin"); - // bool b2 = file_compare("/tmp//tmp/goggle_update/HDZERO_RX.bin","/tmp//tmp/goggle_update/HDZERO_RX_RBR.bin"); - // bool b3 = file_compare("/tmp//tmp/goggle_update/HDZERO_VA.bin","/tmp//tmp/goggle_update/HDZERO_VA_RB.bin"); - // LOGI("Verify result: %d %d %d", b1,b2,b3); - // if(b1 && b2 && b3) { - if (1) { - lv_obj_clear_flag(msgbox_update_complete, LV_OBJ_FLAG_HIDDEN); - lv_timer_handler(); - app_state_push(APP_STATE_USER_INPUT_DISABLED); - beep(); - usleep(1000000); - beep(); - usleep(1000000); - beep(); - } else - lv_label_set_text(btn_goggle, "#FF0000 FAILED#"); - reboot_flag = true; - lv_timer_handler(); - } else if (ret == 2) { - lv_label_set_text(btn_goggle, "#FFFF00 No firmware found.#"); - } else if (ret == 3) { - lv_label_set_text(btn_goggle, "#FFFF00 Multiple versions been found. Keep only one.#"); - } else - lv_label_set_text(btn_goggle, "#FF0000 FAILED#"); - lv_obj_add_flag(bar_goggle, LV_OBJ_FLAG_HIDDEN); - } else if (sel == ROW_UPDATE_ESP32) { // flash ESP via SD - lv_obj_clear_flag(bar_esp, LV_OBJ_FLAG_HIDDEN); - lv_obj_add_flag(label_esp, LV_OBJ_FLAG_HIDDEN); - lv_label_set_text(btn_esp, "Flashing..."); - lv_timer_handler(); - esp_loader_error_t ret = flash_elrs(); - lv_obj_add_flag(bar_esp, LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(label_esp, LV_OBJ_FLAG_HIDDEN); - if (ret == ESP_LOADER_SUCCESS) - lv_label_set_text(btn_esp, "#00FF00 Success#"); - else - lv_label_set_text(btn_esp, "#FF0000 FAILED#"); - page_version_enter(); } } @@ -504,8 +1086,6 @@ static int get_progress_info(int *v0, int *v1) { return 0; } -extern pthread_mutex_t lvgl_mutex; - void *thread_version(void *ptr) { int count = 0; int sec = 0; @@ -518,7 +1098,6 @@ void *thread_version(void *ptr) { int percentage = 0; for (;;) { if (is_need_update_progress) { - // pthread_mutex_lock(&lvgl_mutex); get_progress_info(&v0, &v1); if (v1 == 0) { percentage = 0; @@ -553,7 +1132,6 @@ void *thread_version(void *ptr) { sec_last = sec; process_bar_update(v0, percentage); lv_timer_handler(); - // pthread_mutex_unlock(&lvgl_mutex); } if (count >= 10) { @@ -575,11 +1153,13 @@ page_pack_t pp_version = { .cur = 0, .max = ROW_COUNT, }, - .name = "Firmware", + .name = "Firmware ", // Spaces are necessary to include alert icon. .create = page_version_create, .enter = page_version_enter, - .exit = NULL, + .exit = page_version_exit, + .on_created = page_version_on_created, + .on_update = page_version_on_update, .on_roller = page_version_on_roller, .on_click = page_version_on_click, - .on_right_button = NULL, + .on_right_button = page_version_on_right_button, }; diff --git a/src/ui/page_wifi.c b/src/ui/page_wifi.c index eac4607c..3cae0add 100644 --- a/src/ui/page_wifi.c +++ b/src/ui/page_wifi.c @@ -19,6 +19,7 @@ #include "ui/ui_attribute.h" #include "ui/ui_keyboard.h" #include "ui/ui_style.h" +#include "util/filesystem.h" #include "util/system.h" /** @@ -732,6 +733,29 @@ static void page_wifi_exit() { page_wifi.item_select = 0; } +/** + * Invoked periodically. + */ +static void page_wifi_on_update(uint32_t delta_ms) { + static uint32_t elapsed = -1; + + // Check immediately after running, then every 5 minutes. + if (g_setting.wifi.enable && (elapsed == -1 || (elapsed += delta_ms) > 300000)) { + switch (g_setting.wifi.mode) { + case WIFI_MODE_STA: + if (page_wifi_get_real_address()) { + if (!fs_file_exists("/tmp/hdz_goggle_fw.latest") && + !fs_file_exists("/tmp/hdz_vtx_fw.latest")) { + system_script(WIFI_DOWNLOAD); + } + } + break; + } + + elapsed = 0; + } +} + /** * Main navigation routine for this page. */ @@ -1052,6 +1076,8 @@ page_pack_t pp_wifi = { .create = page_wifi_create, .enter = page_wifi_enter, .exit = page_wifi_exit, + .on_created = NULL, + .on_update = page_wifi_on_update, .on_roller = page_wifi_on_roller, .on_click = page_wifi_on_click, .on_right_button = page_wifi_on_right_button, diff --git a/src/ui/ui_main_menu.c b/src/ui/ui_main_menu.c index 99009d64..de905558 100644 --- a/src/ui/ui_main_menu.c +++ b/src/ui/ui_main_menu.c @@ -125,11 +125,6 @@ void submenu_roller(uint8_t key) { return; } - if (pp->on_roller) { - // if your page as a roller event handler, call it - pp->on_roller(key); - } - if (pp->p_arr.max) { // if we have selectable entries, move selection if (key == DIAL_KEY_UP) { @@ -145,6 +140,12 @@ void submenu_roller(uint8_t key) { } set_select_item(&pp->p_arr, pp->p_arr.cur); } + + // Allow roller to have latest item selected + if (pp->on_roller) { + // if your page as a roller event handler, call it + pp->on_roller(key); + } } // the submenu pages called on_roller event handler has to update @@ -257,16 +258,20 @@ static void main_menu_create_entry(lv_obj_t *menu, lv_obj_t *section, page_pack_ lv_obj_t *cont = lv_menu_cont_create(section); - lv_obj_t *label = lv_label_create(cont); - lv_label_set_text(label, pp->name); - lv_obj_set_style_text_font(label, &lv_font_montserrat_26, 0); - lv_label_set_long_mode(label, LV_LABEL_LONG_SCROLL_CIRCULAR); + pp->label = lv_label_create(cont); + lv_label_set_text(pp->label, pp->name); + lv_obj_set_style_text_font(pp->label, &lv_font_montserrat_26, 0); + lv_label_set_long_mode(pp->label, LV_LABEL_LONG_SCROLL_CIRCULAR); pp->icon = lv_img_create(cont); lv_img_set_src(pp->icon, &img_arrow); lv_obj_set_style_text_font(cont, &lv_font_montserrat_26, 0); lv_menu_set_load_page_event(menu, cont, pp->page); + + if (pp->on_created) { + pp->on_created(); + } } void main_menu_init(void) { @@ -316,6 +321,18 @@ void main_menu_init(void) { keyboard_init(); } +void main_menu_update() { + static uint32_t delta_ms = 0; + uint32_t now_ms = time_ms(); + delta_ms = now_ms - delta_ms; + for (uint32_t i = 0; i < PAGE_COUNT; i++) { + if (page_packs[i]->on_update) { + page_packs[i]->on_update(delta_ms); + } + } + delta_ms = now_ms; +} + void progress_bar_update() { static uint8_t state = 0; // 0=idle, 1= in process diff --git a/src/ui/ui_main_menu.h b/src/ui/ui_main_menu.h index 8b376156..966edfd4 100644 --- a/src/ui/ui_main_menu.h +++ b/src/ui/ui_main_menu.h @@ -14,10 +14,13 @@ typedef struct { lv_obj_t *page; lv_obj_t *icon; + lv_obj_t *label; lv_obj_t *(*create)(lv_obj_t *parent, panel_arr_t *arr); void (*enter)(); void (*exit)(); + void (*on_created)(); + void (*on_update)(uint32_t delta_ms); void (*on_roller)(uint8_t key); void (*on_click)(uint8_t key, int sel); void (*on_right_button)(bool is_short); @@ -32,6 +35,7 @@ typedef struct { extern progress_bar_t progress_bar; void main_menu_init(); +void main_menu_update(); void main_menu_show(bool is_show); bool main_menu_is_shown(void); diff --git a/src/util/file.h b/src/util/file.h deleted file mode 100644 index 1fea5476..00000000 --- a/src/util/file.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include - -bool file_compare(char *f1, char *f2); -bool file_exists(const char *filename); -bool file_printf(const char *filename, const char *fmt, ...); -long file_get_size(const char *filename); -const char *file_get_name(const char *path); diff --git a/src/util/file.c b/src/util/filesystem.c similarity index 71% rename from src/util/file.c rename to src/util/filesystem.c index 49c1b6d5..69172e3b 100644 --- a/src/util/file.c +++ b/src/util/filesystem.c @@ -1,5 +1,6 @@ -#include "file.h" +#include "filesystem.h" +#include #include #include #include @@ -7,7 +8,7 @@ #include #include -bool file_compare(char *f1, char *f2) { +bool fs_compare_files(char *f1, char *f2) { FILE *fp1; FILE *fp2; char c1, c2; @@ -37,11 +38,20 @@ bool file_compare(char *f1, char *f2) { return ret; } -bool file_exists(const char *filename) { +bool fs_path_exists(const char *path) { + DIR *dir = opendir("path"); + if (dir) { + closedir(dir); + return true; + } + return false; +} + +bool fs_file_exists(const char *filename) { return access(filename, F_OK) == 0; } -bool file_printf(const char *filename, const char *fmt, ...) { +bool fs_printf(const char *filename, const char *fmt, ...) { FILE *fp = fopen(filename, "w"); if (!fp) { return false; @@ -57,7 +67,7 @@ bool file_printf(const char *filename, const char *fmt, ...) { return true; } -long file_get_size(const char *filename) { +long fs_filesize(const char *filename) { struct stat st; if (stat(filename, &st) != 0) { return 0; @@ -65,11 +75,11 @@ long file_get_size(const char *filename) { return st.st_size; } -const char *file_get_name(const char *path) { +const char *fs_basename(const char *path) { for (int i = strlen(path); i >= 0; --i) { if (path[i] == '/') { return &path[i + 1]; } } return path; -} \ No newline at end of file +} diff --git a/src/util/filesystem.h b/src/util/filesystem.h new file mode 100644 index 00000000..85f0c6f2 --- /dev/null +++ b/src/util/filesystem.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +bool fs_compare_files(char *f1, char *f2); +bool fs_path_exists(const char *path); +bool fs_file_exists(const char *filename); +bool fs_printf(const char *filename, const char *fmt, ...); +long fs_filesize(const char *filename); +const char *fs_basename(const char *path); diff --git a/src/util/strings.c b/src/util/strings.c new file mode 100644 index 00000000..ac0b6cfd --- /dev/null +++ b/src/util/strings.c @@ -0,0 +1,41 @@ +#include "strings.h" + +#include +#include + +int str_compare_versions(const char *a, const char *b) { + int result = 0; + while (result == 0) { + char *ta; + char *tb; + unsigned long va = strtoul(a, &ta, 10); + unsigned long vb = strtoul(b, &tb, 10); + if (va < vb) { + result = -1; + } else if (va > vb) { + result = +1; + } else { + a = ta; + b = tb; + if (*a == '\0' && *b == '\0') { + break; + } else if (*a == '\0') { + result = -1; + } else if (*b == '\0') { + result = +1; + } else { + a++; + b++; + } + } + } + return result; +} + +static int str_compare_ptr(const void *p1, const void *p2) { + return strcmp(*(char *const *)p1, *(char *const *)p2); +} + +void str_qsort(char **list, int count) { + qsort(list, count, sizeof(char *), str_compare_ptr); +} diff --git a/src/util/strings.h b/src/util/strings.h new file mode 100644 index 00000000..273d8ab1 --- /dev/null +++ b/src/util/strings.h @@ -0,0 +1,6 @@ +#pragma once + +#include + +int str_compare_versions(const char *a, const char *b); +void str_qsort(char **list, int count); diff --git a/src/util/system.c b/src/util/system.c index 865c0711..34948f09 100644 --- a/src/util/system.c +++ b/src/util/system.c @@ -6,7 +6,7 @@ #include #include "log/log.h" -#include "util/file.h" +#include "util/filesystem.h" int system_exec(const char *command) { LOGI("System Execute: %s", command); @@ -17,7 +17,7 @@ int system_script(const char *command) { LOGI("System Script: %s", command); // basename may edit argument - const char *script = file_get_name(command); + const char *script = fs_basename(command); // Modify command to log std out and error to a temporary file char buffer[256];