From d6344812e8ca7032b50f4c0f0aedb88448183f02 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 27 Jul 2022 17:00:38 -0700 Subject: [PATCH] Lots of web workflow, C3 and title bar fixes * Fixes #6221 - C3 hang on `import wifi`. Enabling the WiFi PHY was disabling USB. Now boards that use it set CONFIG_ESP_PHY_ENABLE_USB explicitly. * Fixes #6655 - Allows pasting into the web serial page. Fixes reading more than 0xf bytes at a time. * Fixes #6653 - Fixes web socket encoding of payloads >125 bytes. Can happen when printing a long string. * Fixes C3 responsiveness when waiting for key to enter REPL. (It now correctly stops sleeping.) * Disables title bar updates when in raw REPL. Related to #6548. * Adds version to title bar. --- main.c | 4 + .../boards/adafruit_qtpy_esp32c3/sdkconfig | 8 ++ .../boards/beetle-esp32-c3/sdkconfig | 6 ++ .../espressif/boards/lolin_c3_mini/sdkconfig | 6 ++ ports/espressif/common-hal/wifi/__init__.c | 3 +- ports/espressif/esp-idf | 2 +- ports/espressif/supervisor/port.c | 9 +- ports/espressif/supervisor/usb_serial_jtag.c | 27 +++--- supervisor/port.h | 12 ++- .../esp_port.h => supervisor/shared/port.c | 14 ++- supervisor/shared/serial.c | 12 ++- supervisor/shared/title_bar.c | 93 +++++++++++++++++++ supervisor/shared/title_bar.h | 34 +++++++ .../shared/web_workflow/static/serial.js | 4 +- supervisor/shared/web_workflow/web_workflow.c | 54 +++++++---- supervisor/shared/web_workflow/web_workflow.h | 1 + supervisor/shared/web_workflow/websocket.c | 22 ++++- supervisor/shared/workflow.c | 20 ---- supervisor/supervisor.mk | 2 + 19 files changed, 262 insertions(+), 71 deletions(-) rename ports/espressif/supervisor/esp_port.h => supervisor/shared/port.c (78%) create mode 100644 supervisor/shared/title_bar.c create mode 100644 supervisor/shared/title_bar.h diff --git a/main.c b/main.c index 5fcb2d61a6..d310f571a6 100644 --- a/main.c +++ b/main.c @@ -57,6 +57,7 @@ #include "supervisor/shared/stack.h" #include "supervisor/shared/status_leds.h" #include "supervisor/shared/tick.h" +#include "supervisor/shared/title_bar.h" #include "supervisor/shared/traceback.h" #include "supervisor/shared/translate/translate.h" #include "supervisor/shared/workflow.h" @@ -822,7 +823,9 @@ STATIC int run_repl(bool first_run) { status_led_deinit(); #endif if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + supervisor_title_bar_suspend(); exit_code = pyexec_raw_repl(); + supervisor_title_bar_resume(); } else { exit_code = pyexec_friendly_repl(); } @@ -914,6 +917,7 @@ int __attribute__((used)) main(void) { run_boot_py(safe_mode); supervisor_workflow_start(); + supervisor_title_bar_start(); // Boot script is finished, so now go into REPL or run code.py. int exit_code = PYEXEC_FORCED_EXIT; diff --git a/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig b/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig index f9b0292400..5111900c7e 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig +++ b/ports/espressif/boards/adafruit_qtpy_esp32c3/sdkconfig @@ -30,6 +30,14 @@ CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-4MB-no-uf2.csv" # # Component config # +# + +# +# PHY +# +CONFIG_ESP_PHY_ENABLE_USB=y +# end of PHY + # # ESP System Settings # diff --git a/ports/espressif/boards/beetle-esp32-c3/sdkconfig b/ports/espressif/boards/beetle-esp32-c3/sdkconfig index 129c537108..331a5d14dc 100644 --- a/ports/espressif/boards/beetle-esp32-c3/sdkconfig +++ b/ports/espressif/boards/beetle-esp32-c3/sdkconfig @@ -1,3 +1,9 @@ +# +# PHY +# +CONFIG_ESP_PHY_ENABLE_USB=y +# end of PHY + # # LWIP # diff --git a/ports/espressif/boards/lolin_c3_mini/sdkconfig b/ports/espressif/boards/lolin_c3_mini/sdkconfig index 2cb6b06589..c548ee3c69 100644 --- a/ports/espressif/boards/lolin_c3_mini/sdkconfig +++ b/ports/espressif/boards/lolin_c3_mini/sdkconfig @@ -1,3 +1,9 @@ +# +# PHY +# +CONFIG_ESP_PHY_ENABLE_USB=y +# end of PHY + # # LWIP # diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index 885cc98f96..ca0533525d 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -44,6 +44,7 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "components/log/include/esp_log.h" #include "supervisor/port.h" +#include "supervisor/shared/title_bar.h" #include "supervisor/workflow.h" #include "esp_ipc.h" @@ -55,7 +56,7 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; static const char *TAG = "CP wifi"; STATIC void schedule_background_on_cp_core(void *arg) { - supervisor_workflow_request_background(); + supervisor_title_bar_request_update(false); // CircuitPython's VM is run in a separate FreeRTOS task from wifi callbacks. So, we have to // notify the main task every time in case it's waiting for us. diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index 0180c0cb80..ddb7ddbcb6 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit 0180c0cb80f052919badc15df164e8edde6344ad +Subproject commit ddb7ddbcb613a582e0a91eda8b1d2510dd0a2d83 diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index adefff3f71..5245c9f025 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -30,7 +30,6 @@ #include "supervisor/board.h" #include "supervisor/port.h" #include "py/runtime.h" -#include "supervisor/esp_port.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -390,6 +389,14 @@ void port_wake_main_task() { xTaskNotifyGive(circuitpython_task); } +void port_wake_main_task_from_isr() { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + vTaskNotifyGiveFromISR(circuitpython_task, &xHigherPriorityTaskWoken); + if (xHigherPriorityTaskWoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + void sleep_timer_cb(void *arg) { port_wake_main_task(); } diff --git a/ports/espressif/supervisor/usb_serial_jtag.c b/ports/espressif/supervisor/usb_serial_jtag.c index 33f0ec3a8e..c666c9bb3c 100644 --- a/ports/espressif/supervisor/usb_serial_jtag.c +++ b/ports/espressif/supervisor/usb_serial_jtag.c @@ -28,19 +28,23 @@ #include "py/ringbuf.h" #include "py/runtime.h" #include "py/mphal.h" -#include "usb_serial_jtag.h" +#include "supervisor/port.h" +#include "supervisor/usb_serial_jtag.h" #include "hal/usb_serial_jtag_ll.h" #include "esp_intr_alloc.h" #include "soc/periph_defs.h" -#include "supervisor/esp_port.h" #define USB_SERIAL_JTAG_BUF_SIZE (64) STATIC ringbuf_t ringbuf; STATIC uint8_t buf[128]; -STATIC bool connected; +STATIC volatile bool connected; + +#if CIRCUITPY_ESP_USB_SERIAL_JTAG && !CONFIG_ESP_PHY_ENABLE_USB +#error "CONFIG_ESP_PHY_ENABLE_USB must be enabled in sdkconfig" +#endif static void usb_serial_jtag_isr_handler(void *arg) { uint32_t flags = usb_serial_jtag_ll_get_intsts_mask(); @@ -49,6 +53,11 @@ static void usb_serial_jtag_isr_handler(void *arg) { usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF); } + if (flags & USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1) { + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1); + connected = true; + } + if (flags & USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT) { usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); size_t req_len = ringbuf_num_empty(&ringbuf); @@ -64,25 +73,19 @@ static void usb_serial_jtag_isr_handler(void *arg) { ringbuf_put(&ringbuf, rx_buf[i]); } } - vTaskNotifyGiveFromISR(circuitpython_task, NULL); + port_wake_main_task_from_isr(); } } void usb_serial_jtag_init(void) { ringbuf_init(&ringbuf, buf, sizeof(buf)); - usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); - usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT); + usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1); + usb_serial_jtag_ll_ena_intr_mask(USB_SERIAL_JTAG_INTR_SOF | USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT | USB_SERIAL_JTAG_INTR_TOKEN_REC_IN_EP1); ESP_ERROR_CHECK(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1, usb_serial_jtag_isr_handler, NULL, NULL)); } bool usb_serial_jtag_connected(void) { - // Make connected sticky. Otherwise we'll be disconnected every time the SOF - // index is 0. (It's only ~15 bits so it wraps around frequently.) - if (connected) { - return true; - } - connected = USB_SERIAL_JTAG.fram_num.sof_frame_index > 0; return connected; } diff --git a/supervisor/port.h b/supervisor/port.h index 0a8cdfd342..d693d49440 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -99,8 +99,14 @@ void port_background_task(void); void port_start_background_task(void); void port_finish_background_task(void); -// Some ports need special handling to wake the main task from an interrupt -// context or other task. The port must implement the necessary code in this -// function. A default weak implementation is provided that does nothing. +// Some ports need special handling to wake the main task from another task. The +// port must implement the necessary code in this function. A default weak +// implementation is provided that does nothing. void port_wake_main_task(void); + +// Some ports need special handling to wake the main task from an interrupt +// context. The port must implement the necessary code in this function. A +// default weak implementation is provided that does nothing. +void port_wake_main_task_from_isr(void); + #endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H diff --git a/ports/espressif/supervisor/esp_port.h b/supervisor/shared/port.c similarity index 78% rename from ports/espressif/supervisor/esp_port.h rename to supervisor/shared/port.c index 90ba3f65f1..5d4eeea093 100644 --- a/ports/espressif/supervisor/esp_port.h +++ b/supervisor/shared/port.c @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019 Lucian Copeland for Adafruit Industries + * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,12 +24,10 @@ * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_ESPRESSIF_SUPERVISOR_PORT_H -#define MICROPY_INCLUDED_ESPRESSIF_SUPERVISOR_PORT_H +#include "supervisor/port.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" +MP_WEAK void port_wake_main_task(void) { +} -extern TaskHandle_t circuitpython_task; - -#endif // MICROPY_INCLUDED_ESPRESSIF_SUPERVISOR_PORT_H +MP_WEAK void port_wake_main_task_from_isr(void) { +} diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c index 710046e62e..974dd12b32 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -207,10 +207,17 @@ char serial_read(void) { #if CIRCUITPY_WEB_WORKFLOW if (websocket_available()) { - return websocket_read_char(); + char c = websocket_read_char(); + if (c != -1) { + return c; + } } #endif + if (port_serial_bytes_available() > 0) { + return port_serial_read(); + } + #if CIRCUITPY_USB_CDC if (!usb_cdc_console_enabled()) { return -1; @@ -220,9 +227,6 @@ char serial_read(void) { return (char)tud_cdc_read_char(); #endif - if (port_serial_bytes_available() > 0) { - return port_serial_read(); - } return -1; } diff --git a/supervisor/shared/title_bar.c b/supervisor/shared/title_bar.c new file mode 100644 index 0000000000..b836765ba3 --- /dev/null +++ b/supervisor/shared/title_bar.c @@ -0,0 +1,93 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "genhdr/mpversion.h" +#include "py/mpconfig.h" +#include "supervisor/background_callback.h" +#include "supervisor/serial.h" +#include "supervisor/shared/title_bar.h" + +#if CIRCUITPY_WEB_WORKFLOW +#include "supervisor/shared/web_workflow/web_workflow.h" +#endif +static background_callback_t title_bar_background_cb; + +static bool _forced_dirty = false; +static bool _suspended = false; + +static void title_bar_background(void *data) { + if (_suspended) { + return; + } + bool dirty = _forced_dirty; + + #if CIRCUITPY_WEB_WORKFLOW + dirty = dirty || supervisor_web_workflow_status_dirty(); + #endif + + if (!dirty) { + return; + } + _forced_dirty = false; + #if CIRCUITPY_STATUS_BAR + // Neighboring "" "" are concatenated by the compiler. Without this separation, the hex code + // doesn't get terminated after two following characters and the value is invalid. + // This is the OSC command to set the title and the icon text. It can be up to 255 characters + // but some may be cut off. + serial_write("\x1b" "]0;"); + serial_write("🐍 "); + #if CIRCUITPY_WEB_WORKFLOW + supervisor_web_workflow_status(); + #endif + serial_write("|"); + serial_write(MICROPY_GIT_TAG); + // Send string terminator + serial_write("\x1b" "\\"); + #endif +} + +void supervisor_title_bar_start(void) { + title_bar_background_cb.fun = title_bar_background; + title_bar_background_cb.data = NULL; + supervisor_title_bar_request_update(true); +} + +void supervisor_title_bar_request_update(bool force_dirty) { + if (force_dirty) { + _forced_dirty = true; + } + background_callback_add_core(&title_bar_background_cb); +} + +void supervisor_title_bar_suspend(void) { + _suspended = true; +} + +void supervisor_title_bar_resume(void) { + _suspended = false; + supervisor_title_bar_request_update(false); +} diff --git a/supervisor/shared/title_bar.h b/supervisor/shared/title_bar.h new file mode 100644 index 0000000000..778d768086 --- /dev/null +++ b/supervisor/shared/title_bar.h @@ -0,0 +1,34 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Scott Shawcroft for Adafruit Industries + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include + +void supervisor_title_bar_start(void); +void supervisor_title_bar_suspend(void); +void supervisor_title_bar_resume(void); +void supervisor_title_bar_request_update(bool force_dirty); diff --git a/supervisor/shared/web_workflow/static/serial.js b/supervisor/shared/web_workflow/static/serial.js index 86ec077e92..5c644795a0 100644 --- a/supervisor/shared/web_workflow/static/serial.js +++ b/supervisor/shared/web_workflow/static/serial.js @@ -63,10 +63,12 @@ input.addEventListener("beforeinput", function(e) { input.value = ""; input.focus(); e.preventDefault(); - } else if (e.inputType == "insertText") { + } else if (e.inputType == "insertText" || e.inputType == "insertFromPaste") { ws.send(e.data); } else if (e.inputType == "deleteContentBackward") { ws.send("\b"); + } else { + console.log(e); } }); diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index bd7b150765..ca68155e36 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -95,7 +95,12 @@ typedef struct { char websocket_key[24 + 1]; } _request; -static wifi_radio_error_t wifi_status = WIFI_RADIO_ERROR_NONE; +static wifi_radio_error_t _wifi_status = WIFI_RADIO_ERROR_NONE; + +// Store last status state to compute dirty. +static bool _last_enabled = false; +static uint32_t _last_ip = 0; +static wifi_radio_error_t _last_wifi_status = WIFI_RADIO_ERROR_NONE; static mdns_server_obj_t mdns; static uint32_t web_api_port = 80; @@ -108,6 +113,7 @@ static _request active_request; static char _api_password[64]; +// Store the encoded IP so we don't duplicate work. static uint32_t _encoded_ip = 0; static char _our_ip_encoded[4 * 4]; @@ -170,25 +176,41 @@ static bool _base64_in_place(char *buf, size_t in_len, size_t out_len) { return true; } +STATIC void _update_encoded_ip(void) { + uint32_t ipv4_address = 0; + if (common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); + } + if (_encoded_ip != ipv4_address) { + uint8_t *octets = (uint8_t *)&ipv4_address; + snprintf(_our_ip_encoded, sizeof(_our_ip_encoded), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); + _encoded_ip = ipv4_address; + } +} + +bool supervisor_web_workflow_status_dirty(void) { + return common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) != _last_enabled || + _encoded_ip != _last_ip || + _last_wifi_status != _wifi_status; +} void supervisor_web_workflow_status(void) { serial_write_compressed(translate("Wi-Fi: ")); - if (common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + _last_enabled = common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj); + if (_last_enabled) { uint32_t ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); - if (wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE || - wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) { + _last_wifi_status = _wifi_status; + if (_wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE || + _wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) { serial_write_compressed(translate("Authentication failure")); - } else if (wifi_status != WIFI_RADIO_ERROR_NONE) { - mp_printf(&mp_plat_print, "%d", wifi_status); + } else if (_wifi_status != WIFI_RADIO_ERROR_NONE) { + mp_printf(&mp_plat_print, "%d", _wifi_status); } else if (ipv4_address == 0) { + _last_ip = 0; serial_write_compressed(translate("No IP")); } else { - if (_encoded_ip != ipv4_address) { - uint8_t *octets = (uint8_t *)&ipv4_address; - snprintf(_our_ip_encoded, sizeof(_our_ip_encoded), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); - _encoded_ip = ipv4_address; - } - + _update_encoded_ip(); + _last_ip = _encoded_ip; mp_printf(&mp_plat_print, "%s", _our_ip_encoded); if (web_api_port != 80) { mp_printf(&mp_plat_print, ":%d", web_api_port); @@ -231,11 +253,11 @@ void supervisor_start_web_workflow(void) { // We can all connect again because it will return early if we're already connected to the // network. If we are connected to a different network, then it will disconnect before // attempting to connect to the given network. - wifi_status = common_hal_wifi_radio_connect( + _wifi_status = common_hal_wifi_radio_connect( &common_hal_wifi_radio_obj, (uint8_t *)ssid, ssid_len, (uint8_t *)password, password_len, 0, 0.1, NULL, 0); - if (wifi_status != WIFI_RADIO_ERROR_NONE) { + if (_wifi_status != WIFI_RADIO_ERROR_NONE) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, false); return; } @@ -290,8 +312,6 @@ void supervisor_start_web_workflow(void) { } // TODO: - // GET /cp/serial.txt - // - Most recent 1k of serial output. // GET /edit/ // - Super basic editor #endif @@ -406,6 +426,7 @@ static bool _origin_ok(const char *origin) { return true; } + _update_encoded_ip(); end = origin + strlen(http) + strlen(_our_ip_encoded); if (strncmp(origin + strlen(http), _our_ip_encoded, strlen(_our_ip_encoded)) == 0 && (end[0] == '\0' || end[0] == ':')) { @@ -710,6 +731,7 @@ static void _reply_with_version_json(socketpool_socket_obj_t *socket, _request * mp_print_t _socket_print = {socket, _print_chunk}; const char *hostname = common_hal_mdns_server_get_hostname(&mdns); + _update_encoded_ip(); // Note: this leverages the fact that C concats consecutive string literals together. mp_printf(&_socket_print, "{\"web_api_version\": 1, " diff --git a/supervisor/shared/web_workflow/web_workflow.h b/supervisor/shared/web_workflow/web_workflow.h index f233c06e48..a325b0667e 100644 --- a/supervisor/shared/web_workflow/web_workflow.h +++ b/supervisor/shared/web_workflow/web_workflow.h @@ -31,6 +31,7 @@ // This background function should be called repeatedly. It cannot be done based // on events. void supervisor_web_workflow_background(void); +bool supervisor_web_workflow_status_dirty(void); void supervisor_web_workflow_status(void); void supervisor_start_web_workflow(void); void supervisor_stop_web_workflow(void); diff --git a/supervisor/shared/web_workflow/websocket.c b/supervisor/shared/web_workflow/websocket.c index 313e18a86d..5a42eefb35 100644 --- a/supervisor/shared/web_workflow/websocket.c +++ b/supervisor/shared/web_workflow/websocket.c @@ -26,6 +26,8 @@ #include "supervisor/shared/web_workflow/websocket.h" +#include "supervisor/shared/title_bar.h" + // TODO: Remove ESP specific stuff. For now, it is useful as we refine the server. #include "esp_log.h" @@ -59,6 +61,9 @@ void websocket_handoff(socketpool_socket_obj_t *socket) { // Mark the original socket object as closed without telling the lower level. socket->connected = false; socket->num = -1; + + // Send the title bar for the new client. + supervisor_title_bar_request_update(true); } bool websocket_connected(void) { @@ -94,7 +99,7 @@ static void _read_next_frame_header(void) { } if (cp_serial.frame_index == 1 && _read_byte(&h)) { cp_serial.frame_index++; - uint8_t len = h & 0xf; + uint8_t len = h & 0x7f; cp_serial.masked = (h >> 7) == 1; if (len <= 125) { cp_serial.payload_remaining = len; @@ -194,7 +199,9 @@ bool websocket_available(void) { char websocket_read_char(void) { uint8_t c; - _read_next_payload_byte(&c); + if (!_read_next_payload_byte(&c)) { + c = -1; + } return c; } @@ -215,13 +222,20 @@ static void _websocket_send(_websocket *ws, const char *text, size_t len) { } frame_header[1] = payload_len; _send_raw(&ws->socket, (const uint8_t *)frame_header, 2); + uint8_t extended_len[4]; if (payload_len == 126) { - _send_raw(&ws->socket, (const uint8_t *)&len, 2); + extended_len[0] = (len >> 8) & 0xff; + extended_len[1] = len & 0xff; + _send_raw(&ws->socket, extended_len, 2); } else if (payload_len == 127) { uint32_t zero = 0; // 64 bits where top four bytes are zero. _send_raw(&ws->socket, (const uint8_t *)&zero, 4); - _send_raw(&ws->socket, (const uint8_t *)&len, 4); + extended_len[0] = (len >> 24) & 0xff; + extended_len[1] = (len >> 16) & 0xff; + extended_len[2] = (len >> 8) & 0xff; + extended_len[3] = len & 0xff; + _send_raw(&ws->socket, extended_len, 4); } _send_raw(&ws->socket, (const uint8_t *)text, len); char copy[len]; diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index 23532181c6..7b14c663c4 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -46,27 +46,7 @@ #endif static background_callback_t workflow_background_cb; -#if CIRCUITPY_STATUS_BAR -static void supervisor_workflow_update_status_bar(void) { - // Neighboring "" "" are concatenated by the compiler. Without this separation, the hex code - // doesn't get terminated after two following characters and the value is invalid. - // This is the OSC command to set the title and the icon text. It can be up to 255 characters - // but some may be cut off. - serial_write("\x1b" "]0;"); - serial_write("🐍 "); - #if CIRCUITPY_WEB_WORKFLOW - supervisor_web_workflow_status(); - #endif - // Send string terminator - serial_write("\x1b" "\\"); -} -#endif - static void workflow_background(void *data) { - #if CIRCUITPY_STATUS_BAR - supervisor_workflow_update_status_bar(); - #endif - #if CIRCUITPY_WEB_WORKFLOW supervisor_web_workflow_background(); #endif diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 5b8cb513a7..912b5c5f37 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -8,12 +8,14 @@ SRC_SUPERVISOR = \ supervisor/shared/lock.c \ supervisor/shared/memory.c \ supervisor/shared/micropython.c \ + supervisor/shared/port.c \ supervisor/shared/reload.c \ supervisor/shared/safe_mode.c \ supervisor/shared/serial.c \ supervisor/shared/stack.c \ supervisor/shared/status_leds.c \ supervisor/shared/tick.c \ + supervisor/shared/title_bar.c \ supervisor/shared/traceback.c \ supervisor/shared/translate/translate.c \ supervisor/shared/workflow.c