UX improvements (#6)

* UX: factory reset on long press on boot button
* Portal: reboot button
* Renamed "reset service" to "factory reset service"
This commit is contained in:
SG 2022-02-25 00:03:17 +10:00 committed by GitHub
parent f7e4e686fa
commit d845ae3d72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 148 additions and 4 deletions

View File

@ -1 +1 @@
main.svelte-wdqzrw.svelte-wdqzrw{border:4px dashed #000;margin:10px auto;padding:10px;max-width:800px}.svelte-wdqzrw.svelte-wdqzrw{-moz-user-select:none;-o-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}tabs.svelte-wdqzrw.svelte-wdqzrw{border-bottom:4px dashed #000;width:100%;display:block}tab.svelte-wdqzrw.svelte-wdqzrw{margin-right:10px;padding:5px 10px;margin-bottom:5px;display:inline-block}tab.svelte-wdqzrw.svelte-wdqzrw:hover,tab.selected.svelte-wdqzrw.svelte-wdqzrw:hover{background:rgb(255, 255, 255);color:#000000}tab.selected.svelte-wdqzrw.svelte-wdqzrw{background-color:black;color:white}tabs-content.svelte-wdqzrw.svelte-wdqzrw{display:block;margin-top:10px}error.svelte-wdqzrw.svelte-wdqzrw{padding:5px 10px;background-color:rgb(255, 0, 0);color:black}@font-face{font-family:"DOS";src:url("../assets/ega8.otf") format("opentype");font-weight:normal;font-style:normal;-webkit-font-kerning:none;font-kerning:none;font-synthesis:none;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-variant-numeric:tabular-nums}body{padding:0;margin:0;background-color:#ffa21c;color:#000;font-size:28px;font-family:"DOS", monospace;line-height:1;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0, 0, 0, 0)}.grid.svelte-wdqzrw.svelte-wdqzrw{display:inline-grid;grid-template-columns:auto auto}.grid.svelte-wdqzrw>div.svelte-wdqzrw{margin-top:10px}.value-name.svelte-wdqzrw.svelte-wdqzrw{text-align:right}task-list.svelte-wdqzrw.svelte-wdqzrw{display:inline-grid;grid-template-columns:auto auto auto auto auto;width:100%}.button-css.svelte-yar6m3{background-color:black;color:white;font-size:28px;font-family:"DOS", monospace;line-height:1;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0, 0, 0, 0);border:0;padding:5px 10px;display:inline-block;max-width:100%}.button-css.svelte-yar6m3:hover{background:rgb(255, 255, 255);color:#000000}.input-text-css.svelte-4h7oz2{display:inline-block;color:#000;font-size:28px;font-family:"DOS", monospace;line-height:1;box-sizing:border-box;margin:0;border:0;border-bottom:4px solid #000;padding:0 5px 0 5px;box-shadow:none;border-radius:0;-moz-appearance:none;-webkit-appearance:none;appearance:none;background-color:#ffa21c;height:32px}.input-text-css.svelte-4h7oz2:focus-visible,.input-text-css.svelte-4h7oz2:hover{outline:0;background-color:white}popup-wrapper.svelte-1ufadaz{background-color:rgba(0, 0, 0, 0.863);width:100%;height:100%;display:table;table-layout:fixed;z-index:999;overflow:auto;position:fixed;top:0;left:0;right:0;bottom:0}popup-body.svelte-1ufadaz{margin:auto;display:table-cell;text-align:center;vertical-align:middle;width:100%}popup-content.svelte-1ufadaz{background-color:#ffa21c;display:inline-block;outline:none;position:relative;text-align:initial;max-width:100vw}popup-border.svelte-1ufadaz{display:block;border:4px dashed #000;margin:10px;padding:10px}popup-close.svelte-1ufadaz{background-color:#000;display:inline-block;color:#ffa21c;position:absolute;width:24px;right:0px;top:0px;text-align:center}popup-close.svelte-1ufadaz:hover{background-color:#fff;color:#000}@keyframes svelte-1471rey-spinner-animation{0%{content:"|"}25%{content:"/"}50%{content:"-"}75%{content:"\\"}100%{content:"|"}}spinner.svelte-1471rey::after{display:inline-block;animation:svelte-1471rey-spinner-animation 0.6s linear infinite alternate;content:"|"}select.svelte-1rf61qb.svelte-1rf61qb{display:inline-block;color:#000;font-size:28px;font-family:"DOS", monospace;line-height:1;box-sizing:border-box;margin:0;border:0;border-bottom:4px solid #000;padding:0 5px 0 5px;box-shadow:none;border-radius:0;-moz-appearance:none;-webkit-appearance:none;appearance:none;background-color:#ffa21c}select.svelte-1rf61qb.svelte-1rf61qb::-ms-expand{display:none}select.svelte-1rf61qb.svelte-1rf61qb:hover{background:rgb(255, 255, 255);color:#000000}select.svelte-1rf61qb.svelte-1rf61qb:focus{box-shadow:none;outline:none;background:rgb(255, 255, 255);color:#000000}select.svelte-1rf61qb option.svelte-1rf61qb{font-weight:normal}.button.svelte-1rqr1h4{box-sizing:border-box;display:inline-block;font-size:28px;font-family:"DOS", monospace;line-height:1;border:0;padding:0 5px 0 5px;box-shadow:none;border-radius:0;display:inline-block;max-width:100%}.black.svelte-1rqr1h4{color:white;background-color:black;border-bottom:4px solid #000}.black.svelte-1rqr1h4:hover{background:#fff;color:#000}.normal.svelte-1rqr1h4{color:#000;background-color:#ffa21c;border-bottom:4px solid #ffa21c}.normal.svelte-1rqr1h4:hover{background:#000;color:#fff}
main.svelte-wdqzrw.svelte-wdqzrw{border:4px dashed #000;margin:10px auto;padding:10px;max-width:800px}.svelte-wdqzrw.svelte-wdqzrw{-moz-user-select:none;-o-user-select:none;-khtml-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none}tabs.svelte-wdqzrw.svelte-wdqzrw{border-bottom:4px dashed #000;width:100%;display:block}tab.svelte-wdqzrw.svelte-wdqzrw{margin-right:10px;padding:5px 10px;margin-bottom:5px;display:inline-block}tab.svelte-wdqzrw.svelte-wdqzrw:hover,tab.selected.svelte-wdqzrw.svelte-wdqzrw:hover{background:rgb(255, 255, 255);color:#000000}tab.selected.svelte-wdqzrw.svelte-wdqzrw{background-color:black;color:white}tabs-content.svelte-wdqzrw.svelte-wdqzrw{display:block;margin-top:10px}error.svelte-wdqzrw.svelte-wdqzrw{padding:5px 10px;background-color:rgb(255, 0, 0);color:black}@font-face{font-family:"DOS";src:url("../assets/ega8.otf") format("opentype");font-weight:normal;font-style:normal;-webkit-font-kerning:none;font-kerning:none;font-synthesis:none;-webkit-font-variant-ligatures:none;font-variant-ligatures:none;font-variant-numeric:tabular-nums}body{padding:0;margin:0;background-color:#ffa21c;color:#000;font-size:28px;font-family:"DOS", monospace;line-height:1;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0, 0, 0, 0)}.grid.svelte-wdqzrw.svelte-wdqzrw{display:inline-grid;grid-template-columns:auto auto}.grid.svelte-wdqzrw>div.svelte-wdqzrw{margin-top:10px}.value-name.svelte-wdqzrw.svelte-wdqzrw{text-align:right}task-list.svelte-wdqzrw.svelte-wdqzrw{display:inline-grid;grid-template-columns:auto auto auto auto auto;width:100%}.input-text-css.svelte-4h7oz2{display:inline-block;color:#000;font-size:28px;font-family:"DOS", monospace;line-height:1;box-sizing:border-box;margin:0;border:0;border-bottom:4px solid #000;padding:0 5px 0 5px;box-shadow:none;border-radius:0;-moz-appearance:none;-webkit-appearance:none;appearance:none;background-color:#ffa21c;height:32px}.input-text-css.svelte-4h7oz2:focus-visible,.input-text-css.svelte-4h7oz2:hover{outline:0;background-color:white}popup-wrapper.svelte-1ufadaz{background-color:rgba(0, 0, 0, 0.863);width:100%;height:100%;display:table;table-layout:fixed;z-index:999;overflow:auto;position:fixed;top:0;left:0;right:0;bottom:0}popup-body.svelte-1ufadaz{margin:auto;display:table-cell;text-align:center;vertical-align:middle;width:100%}popup-content.svelte-1ufadaz{background-color:#ffa21c;display:inline-block;outline:none;position:relative;text-align:initial;max-width:100vw}popup-border.svelte-1ufadaz{display:block;border:4px dashed #000;margin:10px;padding:10px}popup-close.svelte-1ufadaz{background-color:#000;display:inline-block;color:#ffa21c;position:absolute;width:24px;right:0px;top:0px;text-align:center}popup-close.svelte-1ufadaz:hover{background-color:#fff;color:#000}@keyframes svelte-1471rey-spinner-animation{0%{content:"|"}25%{content:"/"}50%{content:"-"}75%{content:"\\"}100%{content:"|"}}spinner.svelte-1471rey::after{display:inline-block;animation:svelte-1471rey-spinner-animation 0.6s linear infinite alternate;content:"|"}select.svelte-1rf61qb.svelte-1rf61qb{display:inline-block;color:#000;font-size:28px;font-family:"DOS", monospace;line-height:1;box-sizing:border-box;margin:0;border:0;border-bottom:4px solid #000;padding:0 5px 0 5px;box-shadow:none;border-radius:0;-moz-appearance:none;-webkit-appearance:none;appearance:none;background-color:#ffa21c}select.svelte-1rf61qb.svelte-1rf61qb::-ms-expand{display:none}select.svelte-1rf61qb.svelte-1rf61qb:hover{background:rgb(255, 255, 255);color:#000000}select.svelte-1rf61qb.svelte-1rf61qb:focus{box-shadow:none;outline:none;background:rgb(255, 255, 255);color:#000000}select.svelte-1rf61qb option.svelte-1rf61qb{font-weight:normal}.button-css.svelte-yar6m3{background-color:black;color:white;font-size:28px;font-family:"DOS", monospace;line-height:1;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0, 0, 0, 0);border:0;padding:5px 10px;display:inline-block;max-width:100%}.button-css.svelte-yar6m3:hover{background:rgb(255, 255, 255);color:#000000}.button.svelte-1rqr1h4{box-sizing:border-box;display:inline-block;font-size:28px;font-family:"DOS", monospace;line-height:1;border:0;padding:0 5px 0 5px;box-shadow:none;border-radius:0;display:inline-block;max-width:100%}.black.svelte-1rqr1h4{color:white;background-color:black;border-bottom:4px solid #000}.black.svelte-1rqr1h4:hover{background:#fff;color:#000}.normal.svelte-1rqr1h4{color:#000;background-color:#ffa21c;border-bottom:4px solid #ffa21c}.normal.svelte-1rqr1h4:hover{background:#000;color:#fff}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -65,6 +65,12 @@
});
}
async function reboot_board() {
api_post(server + "/api/v1/system/reboot", {});
popup_message_text = "Rebooted";
popup_message.show();
}
function change_tab(tab) {
current_tab = tab;
localStorage.setItem("current_tab", current_tab);
@ -184,6 +190,7 @@
</div>
<div style="margin-top: 10px;">
<Button value="SAVE" on:click={save_settings} />
<Button value="REBOOT" on:click={reboot_board} />
</div>
</tab-content>
{/if}

View File

@ -20,6 +20,7 @@ set(SOURCES
"cli/cli-commands-device-info.c"
"cli/cli-args.c"
"soft-uart-log.c"
"factory-reset-service.c"
)
set(INCLUDES

View File

@ -0,0 +1,119 @@
#include "driver/gpio.h"
#include <string.h>
#include <esp_log.h>
#include "freertos/FreeRTOS.h"
#include "freertos/timers.h"
#include "led.h"
#include "nvs.h"
#define BOOT_PIN (0)
#define ESP_INTR_FLAG_DEFAULT 0
#define RESET_TIMER_TICK 250
#define RESET_TIMER_TICKS_TO_RESET 40
// static timer
static StaticTimer_t reset_timer_data;
static TimerHandle_t reset_timer;
static size_t reset_counter = 0;
static void start_reset_timer() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if(xPortInIsrContext()) {
xTimerStartFromISR(reset_timer, &xHigherPriorityTaskWoken);
} else {
xTimerStart(reset_timer, portMAX_DELAY);
}
if(xHigherPriorityTaskWoken != pdFALSE) {
portYIELD_FROM_ISR(pdTRUE);
}
}
static void stop_reset_timer() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if(xPortInIsrContext()) {
xTimerStopFromISR(reset_timer, &xHigherPriorityTaskWoken);
} else {
xTimerStop(reset_timer, portMAX_DELAY);
}
reset_counter = 0;
led_set(0, 0, 0);
if(xHigherPriorityTaskWoken != pdFALSE) {
portYIELD_FROM_ISR(pdTRUE);
}
}
static void IRAM_ATTR boot_button_isr_handler(void* arg) {
if(gpio_get_level(BOOT_PIN) == 0) {
start_reset_timer();
} else {
stop_reset_timer();
}
}
static void reset_timer_cb(TimerHandle_t xTimer) {
(void)xTimer;
if(gpio_get_level(BOOT_PIN) == 1) {
stop_reset_timer();
} else {
reset_counter++;
uint8_t led_color = 0;
if(reset_counter < (RESET_TIMER_TICKS_TO_RESET / 2)) {
// slow blink
if(reset_counter % 4 < 2) {
led_color = 0xFF;
}
} else {
// fast blink
if(reset_counter % 2 != 0) {
led_color = 0xFF;
}
}
if(reset_counter > RESET_TIMER_TICKS_TO_RESET) {
stop_reset_timer();
led_set(255, 0, 0);
// waiting for button release
while(gpio_get_level(BOOT_PIN) == 0) {
}
led_set(0, 255, 0);
nvs_erase();
led_set(0, 0, 255);
esp_restart();
} else {
led_set(led_color, led_color, led_color);
}
}
}
void factory_reset_service_init(void) {
gpio_config_t io_conf;
memset(&io_conf, 0, sizeof(gpio_config_t));
io_conf.intr_type = GPIO_INTR_ANYEDGE;
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = ((1 << BOOT_PIN));
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
gpio_config(&io_conf);
// install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
// attach interrupt
gpio_isr_handler_add(BOOT_PIN, boot_button_isr_handler, (void*)BOOT_PIN);
// soft timers
reset_timer = xTimerCreateStatic(
NULL, pdMS_TO_TICKS(RESET_TIMER_TICK), true, NULL, reset_timer_cb, &reset_timer_data);
}

View File

@ -0,0 +1,3 @@
#pragma once
void factory_reset_service_init(void);

View File

@ -14,6 +14,7 @@
#include "network-http.h"
#include "network-uart.h"
#include "network-gdb.h"
#include "factory-reset-service.h"
#include <gdb-glue.h>
#include <soft-uart-log.h>
@ -48,11 +49,13 @@ void pins_init() {
}
void app_main(void) {
// Software UART logging at pin 7, 57600 baud
// Software UART logging at pin 7, 57600 baud
soft_uart_log_init(7, 57600);
ESP_LOGI(TAG, "start");
factory_reset_service_init();
gdb_glue_init();
led_init();

View File

@ -229,6 +229,12 @@ static esp_err_t system_tasks_handler(httpd_req_t* req) {
return ESP_OK;
}
static esp_err_t system_reboot(httpd_req_t* req) {
httpd_resp_sendstr(req, JSON_RESULT("OK"));
esp_restart();
return ESP_OK;
}
static esp_err_t system_info_get_handler(httpd_req_t* req) {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_set_type(req, "application/json");
@ -580,6 +586,11 @@ const httpd_uri_t uri_handlers[] = {
.handler = system_info_get_handler,
.user_ctx = NULL},
{.uri = "/api/v1/system/reboot",
.method = HTTP_POST,
.handler = system_reboot,
.user_ctx = NULL},
/*************** GPIO ***************/
{.uri = "/api/v1/gpio/led",