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.
This commit is contained in:
parent
c4c15206e7
commit
d6344812e8
4
main.c
4
main.c
@ -57,6 +57,7 @@
|
|||||||
#include "supervisor/shared/stack.h"
|
#include "supervisor/shared/stack.h"
|
||||||
#include "supervisor/shared/status_leds.h"
|
#include "supervisor/shared/status_leds.h"
|
||||||
#include "supervisor/shared/tick.h"
|
#include "supervisor/shared/tick.h"
|
||||||
|
#include "supervisor/shared/title_bar.h"
|
||||||
#include "supervisor/shared/traceback.h"
|
#include "supervisor/shared/traceback.h"
|
||||||
#include "supervisor/shared/translate/translate.h"
|
#include "supervisor/shared/translate/translate.h"
|
||||||
#include "supervisor/shared/workflow.h"
|
#include "supervisor/shared/workflow.h"
|
||||||
@ -822,7 +823,9 @@ STATIC int run_repl(bool first_run) {
|
|||||||
status_led_deinit();
|
status_led_deinit();
|
||||||
#endif
|
#endif
|
||||||
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
|
||||||
|
supervisor_title_bar_suspend();
|
||||||
exit_code = pyexec_raw_repl();
|
exit_code = pyexec_raw_repl();
|
||||||
|
supervisor_title_bar_resume();
|
||||||
} else {
|
} else {
|
||||||
exit_code = pyexec_friendly_repl();
|
exit_code = pyexec_friendly_repl();
|
||||||
}
|
}
|
||||||
@ -914,6 +917,7 @@ int __attribute__((used)) main(void) {
|
|||||||
run_boot_py(safe_mode);
|
run_boot_py(safe_mode);
|
||||||
|
|
||||||
supervisor_workflow_start();
|
supervisor_workflow_start();
|
||||||
|
supervisor_title_bar_start();
|
||||||
|
|
||||||
// Boot script is finished, so now go into REPL or run code.py.
|
// Boot script is finished, so now go into REPL or run code.py.
|
||||||
int exit_code = PYEXEC_FORCED_EXIT;
|
int exit_code = PYEXEC_FORCED_EXIT;
|
||||||
|
@ -30,6 +30,14 @@ CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-4MB-no-uf2.csv"
|
|||||||
#
|
#
|
||||||
# Component config
|
# Component config
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# PHY
|
||||||
|
#
|
||||||
|
CONFIG_ESP_PHY_ENABLE_USB=y
|
||||||
|
# end of PHY
|
||||||
|
|
||||||
#
|
#
|
||||||
# ESP System Settings
|
# ESP System Settings
|
||||||
#
|
#
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# PHY
|
||||||
|
#
|
||||||
|
CONFIG_ESP_PHY_ENABLE_USB=y
|
||||||
|
# end of PHY
|
||||||
|
|
||||||
#
|
#
|
||||||
# LWIP
|
# LWIP
|
||||||
#
|
#
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
#
|
||||||
|
# PHY
|
||||||
|
#
|
||||||
|
CONFIG_ESP_PHY_ENABLE_USB=y
|
||||||
|
# end of PHY
|
||||||
|
|
||||||
#
|
#
|
||||||
# LWIP
|
# LWIP
|
||||||
#
|
#
|
||||||
|
@ -44,6 +44,7 @@ wifi_radio_obj_t common_hal_wifi_radio_obj;
|
|||||||
#include "components/log/include/esp_log.h"
|
#include "components/log/include/esp_log.h"
|
||||||
|
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
|
#include "supervisor/shared/title_bar.h"
|
||||||
#include "supervisor/workflow.h"
|
#include "supervisor/workflow.h"
|
||||||
|
|
||||||
#include "esp_ipc.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 const char *TAG = "CP wifi";
|
||||||
|
|
||||||
STATIC void schedule_background_on_cp_core(void *arg) {
|
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
|
// 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.
|
// notify the main task every time in case it's waiting for us.
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 0180c0cb80f052919badc15df164e8edde6344ad
|
Subproject commit ddb7ddbcb613a582e0a91eda8b1d2510dd0a2d83
|
@ -30,7 +30,6 @@
|
|||||||
#include "supervisor/board.h"
|
#include "supervisor/board.h"
|
||||||
#include "supervisor/port.h"
|
#include "supervisor/port.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "supervisor/esp_port.h"
|
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
@ -390,6 +389,14 @@ void port_wake_main_task() {
|
|||||||
xTaskNotifyGive(circuitpython_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) {
|
void sleep_timer_cb(void *arg) {
|
||||||
port_wake_main_task();
|
port_wake_main_task();
|
||||||
}
|
}
|
||||||
|
@ -28,19 +28,23 @@
|
|||||||
#include "py/ringbuf.h"
|
#include "py/ringbuf.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/mphal.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 "hal/usb_serial_jtag_ll.h"
|
||||||
#include "esp_intr_alloc.h"
|
#include "esp_intr_alloc.h"
|
||||||
#include "soc/periph_defs.h"
|
#include "soc/periph_defs.h"
|
||||||
|
|
||||||
#include "supervisor/esp_port.h"
|
|
||||||
|
|
||||||
#define USB_SERIAL_JTAG_BUF_SIZE (64)
|
#define USB_SERIAL_JTAG_BUF_SIZE (64)
|
||||||
|
|
||||||
STATIC ringbuf_t ringbuf;
|
STATIC ringbuf_t ringbuf;
|
||||||
STATIC uint8_t buf[128];
|
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) {
|
static void usb_serial_jtag_isr_handler(void *arg) {
|
||||||
uint32_t flags = usb_serial_jtag_ll_get_intsts_mask();
|
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);
|
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) {
|
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);
|
usb_serial_jtag_ll_clr_intsts_mask(USB_SERIAL_JTAG_INTR_SERIAL_OUT_RECV_PKT);
|
||||||
size_t req_len = ringbuf_num_empty(&ringbuf);
|
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]);
|
ringbuf_put(&ringbuf, rx_buf[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vTaskNotifyGiveFromISR(circuitpython_task, NULL);
|
port_wake_main_task_from_isr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_serial_jtag_init(void) {
|
void usb_serial_jtag_init(void) {
|
||||||
ringbuf_init(&ringbuf, buf, sizeof(buf));
|
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_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_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,
|
ESP_ERROR_CHECK(esp_intr_alloc(ETS_USB_SERIAL_JTAG_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1,
|
||||||
usb_serial_jtag_isr_handler, NULL, NULL));
|
usb_serial_jtag_isr_handler, NULL, NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool usb_serial_jtag_connected(void) {
|
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;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +99,14 @@ void port_background_task(void);
|
|||||||
void port_start_background_task(void);
|
void port_start_background_task(void);
|
||||||
void port_finish_background_task(void);
|
void port_finish_background_task(void);
|
||||||
|
|
||||||
// Some ports need special handling to wake the main task from an interrupt
|
// Some ports need special handling to wake the main task from another task. The
|
||||||
// context or other task. The port must implement the necessary code in this
|
// port must implement the necessary code in this function. A default weak
|
||||||
// function. A default weak implementation is provided that does nothing.
|
// implementation is provided that does nothing.
|
||||||
void port_wake_main_task(void);
|
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
|
#endif // MICROPY_INCLUDED_SUPERVISOR_PORT_H
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* 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
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
@ -24,12 +24,10 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef MICROPY_INCLUDED_ESPRESSIF_SUPERVISOR_PORT_H
|
#include "supervisor/port.h"
|
||||||
#define MICROPY_INCLUDED_ESPRESSIF_SUPERVISOR_PORT_H
|
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
MP_WEAK void port_wake_main_task(void) {
|
||||||
#include "freertos/task.h"
|
}
|
||||||
|
|
||||||
extern TaskHandle_t circuitpython_task;
|
MP_WEAK void port_wake_main_task_from_isr(void) {
|
||||||
|
}
|
||||||
#endif // MICROPY_INCLUDED_ESPRESSIF_SUPERVISOR_PORT_H
|
|
@ -207,10 +207,17 @@ char serial_read(void) {
|
|||||||
|
|
||||||
#if CIRCUITPY_WEB_WORKFLOW
|
#if CIRCUITPY_WEB_WORKFLOW
|
||||||
if (websocket_available()) {
|
if (websocket_available()) {
|
||||||
return websocket_read_char();
|
char c = websocket_read_char();
|
||||||
|
if (c != -1) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (port_serial_bytes_available() > 0) {
|
||||||
|
return port_serial_read();
|
||||||
|
}
|
||||||
|
|
||||||
#if CIRCUITPY_USB_CDC
|
#if CIRCUITPY_USB_CDC
|
||||||
if (!usb_cdc_console_enabled()) {
|
if (!usb_cdc_console_enabled()) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -220,9 +227,6 @@ char serial_read(void) {
|
|||||||
return (char)tud_cdc_read_char();
|
return (char)tud_cdc_read_char();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (port_serial_bytes_available() > 0) {
|
|
||||||
return port_serial_read();
|
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
93
supervisor/shared/title_bar.c
Normal file
93
supervisor/shared/title_bar.c
Normal file
@ -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 <stdbool.h>
|
||||||
|
#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);
|
||||||
|
}
|
34
supervisor/shared/title_bar.h
Normal file
34
supervisor/shared/title_bar.h
Normal file
@ -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 <stdbool.h>
|
||||||
|
|
||||||
|
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);
|
@ -63,10 +63,12 @@ input.addEventListener("beforeinput", function(e) {
|
|||||||
input.value = "";
|
input.value = "";
|
||||||
input.focus();
|
input.focus();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
} else if (e.inputType == "insertText") {
|
} else if (e.inputType == "insertText" || e.inputType == "insertFromPaste") {
|
||||||
ws.send(e.data);
|
ws.send(e.data);
|
||||||
} else if (e.inputType == "deleteContentBackward") {
|
} else if (e.inputType == "deleteContentBackward") {
|
||||||
ws.send("\b");
|
ws.send("\b");
|
||||||
|
} else {
|
||||||
|
console.log(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -95,7 +95,12 @@ typedef struct {
|
|||||||
char websocket_key[24 + 1];
|
char websocket_key[24 + 1];
|
||||||
} _request;
|
} _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 mdns_server_obj_t mdns;
|
||||||
static uint32_t web_api_port = 80;
|
static uint32_t web_api_port = 80;
|
||||||
@ -108,6 +113,7 @@ static _request active_request;
|
|||||||
|
|
||||||
static char _api_password[64];
|
static char _api_password[64];
|
||||||
|
|
||||||
|
// Store the encoded IP so we don't duplicate work.
|
||||||
static uint32_t _encoded_ip = 0;
|
static uint32_t _encoded_ip = 0;
|
||||||
static char _our_ip_encoded[4 * 4];
|
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;
|
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) {
|
void supervisor_web_workflow_status(void) {
|
||||||
serial_write_compressed(translate("Wi-Fi: "));
|
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);
|
uint32_t ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj);
|
||||||
if (wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE ||
|
_last_wifi_status = _wifi_status;
|
||||||
wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) {
|
if (_wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE ||
|
||||||
|
_wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) {
|
||||||
serial_write_compressed(translate("Authentication failure"));
|
serial_write_compressed(translate("Authentication failure"));
|
||||||
} else if (wifi_status != WIFI_RADIO_ERROR_NONE) {
|
} else if (_wifi_status != WIFI_RADIO_ERROR_NONE) {
|
||||||
mp_printf(&mp_plat_print, "%d", wifi_status);
|
mp_printf(&mp_plat_print, "%d", _wifi_status);
|
||||||
} else if (ipv4_address == 0) {
|
} else if (ipv4_address == 0) {
|
||||||
|
_last_ip = 0;
|
||||||
serial_write_compressed(translate("No IP"));
|
serial_write_compressed(translate("No IP"));
|
||||||
} else {
|
} else {
|
||||||
if (_encoded_ip != ipv4_address) {
|
_update_encoded_ip();
|
||||||
uint8_t *octets = (uint8_t *)&ipv4_address;
|
_last_ip = _encoded_ip;
|
||||||
snprintf(_our_ip_encoded, sizeof(_our_ip_encoded), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]);
|
|
||||||
_encoded_ip = ipv4_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
mp_printf(&mp_plat_print, "%s", _our_ip_encoded);
|
mp_printf(&mp_plat_print, "%s", _our_ip_encoded);
|
||||||
if (web_api_port != 80) {
|
if (web_api_port != 80) {
|
||||||
mp_printf(&mp_plat_print, ":%d", web_api_port);
|
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
|
// 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
|
// network. If we are connected to a different network, then it will disconnect before
|
||||||
// attempting to connect to the given network.
|
// 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,
|
&common_hal_wifi_radio_obj, (uint8_t *)ssid, ssid_len, (uint8_t *)password, password_len,
|
||||||
0, 0.1, NULL, 0);
|
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);
|
common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -290,8 +312,6 @@ void supervisor_start_web_workflow(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// GET /cp/serial.txt
|
|
||||||
// - Most recent 1k of serial output.
|
|
||||||
// GET /edit/
|
// GET /edit/
|
||||||
// - Super basic editor
|
// - Super basic editor
|
||||||
#endif
|
#endif
|
||||||
@ -406,6 +426,7 @@ static bool _origin_ok(const char *origin) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_update_encoded_ip();
|
||||||
end = origin + strlen(http) + strlen(_our_ip_encoded);
|
end = origin + strlen(http) + strlen(_our_ip_encoded);
|
||||||
if (strncmp(origin + strlen(http), _our_ip_encoded, strlen(_our_ip_encoded)) == 0 &&
|
if (strncmp(origin + strlen(http), _our_ip_encoded, strlen(_our_ip_encoded)) == 0 &&
|
||||||
(end[0] == '\0' || end[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};
|
mp_print_t _socket_print = {socket, _print_chunk};
|
||||||
|
|
||||||
const char *hostname = common_hal_mdns_server_get_hostname(&mdns);
|
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.
|
// Note: this leverages the fact that C concats consecutive string literals together.
|
||||||
mp_printf(&_socket_print,
|
mp_printf(&_socket_print,
|
||||||
"{\"web_api_version\": 1, "
|
"{\"web_api_version\": 1, "
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
// This background function should be called repeatedly. It cannot be done based
|
// This background function should be called repeatedly. It cannot be done based
|
||||||
// on events.
|
// on events.
|
||||||
void supervisor_web_workflow_background(void);
|
void supervisor_web_workflow_background(void);
|
||||||
|
bool supervisor_web_workflow_status_dirty(void);
|
||||||
void supervisor_web_workflow_status(void);
|
void supervisor_web_workflow_status(void);
|
||||||
void supervisor_start_web_workflow(void);
|
void supervisor_start_web_workflow(void);
|
||||||
void supervisor_stop_web_workflow(void);
|
void supervisor_stop_web_workflow(void);
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
|
|
||||||
#include "supervisor/shared/web_workflow/websocket.h"
|
#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.
|
// TODO: Remove ESP specific stuff. For now, it is useful as we refine the server.
|
||||||
#include "esp_log.h"
|
#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.
|
// Mark the original socket object as closed without telling the lower level.
|
||||||
socket->connected = false;
|
socket->connected = false;
|
||||||
socket->num = -1;
|
socket->num = -1;
|
||||||
|
|
||||||
|
// Send the title bar for the new client.
|
||||||
|
supervisor_title_bar_request_update(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool websocket_connected(void) {
|
bool websocket_connected(void) {
|
||||||
@ -94,7 +99,7 @@ static void _read_next_frame_header(void) {
|
|||||||
}
|
}
|
||||||
if (cp_serial.frame_index == 1 && _read_byte(&h)) {
|
if (cp_serial.frame_index == 1 && _read_byte(&h)) {
|
||||||
cp_serial.frame_index++;
|
cp_serial.frame_index++;
|
||||||
uint8_t len = h & 0xf;
|
uint8_t len = h & 0x7f;
|
||||||
cp_serial.masked = (h >> 7) == 1;
|
cp_serial.masked = (h >> 7) == 1;
|
||||||
if (len <= 125) {
|
if (len <= 125) {
|
||||||
cp_serial.payload_remaining = len;
|
cp_serial.payload_remaining = len;
|
||||||
@ -194,7 +199,9 @@ bool websocket_available(void) {
|
|||||||
|
|
||||||
char websocket_read_char(void) {
|
char websocket_read_char(void) {
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
_read_next_payload_byte(&c);
|
if (!_read_next_payload_byte(&c)) {
|
||||||
|
c = -1;
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,13 +222,20 @@ static void _websocket_send(_websocket *ws, const char *text, size_t len) {
|
|||||||
}
|
}
|
||||||
frame_header[1] = payload_len;
|
frame_header[1] = payload_len;
|
||||||
_send_raw(&ws->socket, (const uint8_t *)frame_header, 2);
|
_send_raw(&ws->socket, (const uint8_t *)frame_header, 2);
|
||||||
|
uint8_t extended_len[4];
|
||||||
if (payload_len == 126) {
|
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) {
|
} else if (payload_len == 127) {
|
||||||
uint32_t zero = 0;
|
uint32_t zero = 0;
|
||||||
// 64 bits where top four bytes are zero.
|
// 64 bits where top four bytes are zero.
|
||||||
_send_raw(&ws->socket, (const uint8_t *)&zero, 4);
|
_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);
|
_send_raw(&ws->socket, (const uint8_t *)text, len);
|
||||||
char copy[len];
|
char copy[len];
|
||||||
|
@ -46,27 +46,7 @@
|
|||||||
#endif
|
#endif
|
||||||
static background_callback_t workflow_background_cb;
|
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) {
|
static void workflow_background(void *data) {
|
||||||
#if CIRCUITPY_STATUS_BAR
|
|
||||||
supervisor_workflow_update_status_bar();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CIRCUITPY_WEB_WORKFLOW
|
#if CIRCUITPY_WEB_WORKFLOW
|
||||||
supervisor_web_workflow_background();
|
supervisor_web_workflow_background();
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,12 +8,14 @@ SRC_SUPERVISOR = \
|
|||||||
supervisor/shared/lock.c \
|
supervisor/shared/lock.c \
|
||||||
supervisor/shared/memory.c \
|
supervisor/shared/memory.c \
|
||||||
supervisor/shared/micropython.c \
|
supervisor/shared/micropython.c \
|
||||||
|
supervisor/shared/port.c \
|
||||||
supervisor/shared/reload.c \
|
supervisor/shared/reload.c \
|
||||||
supervisor/shared/safe_mode.c \
|
supervisor/shared/safe_mode.c \
|
||||||
supervisor/shared/serial.c \
|
supervisor/shared/serial.c \
|
||||||
supervisor/shared/stack.c \
|
supervisor/shared/stack.c \
|
||||||
supervisor/shared/status_leds.c \
|
supervisor/shared/status_leds.c \
|
||||||
supervisor/shared/tick.c \
|
supervisor/shared/tick.c \
|
||||||
|
supervisor/shared/title_bar.c \
|
||||||
supervisor/shared/traceback.c \
|
supervisor/shared/traceback.c \
|
||||||
supervisor/shared/translate/translate.c \
|
supervisor/shared/translate/translate.c \
|
||||||
supervisor/shared/workflow.c
|
supervisor/shared/workflow.c
|
||||||
|
Loading…
Reference in New Issue
Block a user