diff --git a/firmware/application/event_m0.cpp b/firmware/application/event_m0.cpp index 8e0ad5c2..964d17fb 100644 --- a/firmware/application/event_m0.cpp +++ b/firmware/application/event_m0.cpp @@ -150,6 +150,8 @@ void EventDispatcher::dispatch(const eventmask_t events) { *(uint32_t*)&shared_memory.bb_data.data[4]); } + handle_shell(); + if (events & EVT_MASK_APPLICATION) { handle_application_queue(); } @@ -223,6 +225,26 @@ void EventDispatcher::handle_usb() { portapack::usb_serial.dispatch(); } +void EventDispatcher::handle_shell() { + if (waiting_for_shellmode) { + waiting_for_shellmode = false; + shellmode_active = true; + while (shellmode_active) { + chThdSleepMilliseconds(5); + } + } + + if (injected_touch_event != nullptr) { + on_touch_event(*injected_touch_event); + injected_touch_event = nullptr; + } + + if (injected_keyboard_event != nullptr) { + on_keyboard_event(*injected_keyboard_event); + injected_keyboard_event = nullptr; + } +} + ui::Widget* EventDispatcher::touch_widget(ui::Widget* const w, ui::TouchEvent event) { if (!w->hidden()) { // To achieve reverse depth ordering (last object drawn is @@ -246,11 +268,17 @@ ui::Widget* EventDispatcher::touch_widget(ui::Widget* const w, ui::TouchEvent ev } void EventDispatcher::emulateTouch(ui::TouchEvent event) { - on_touch_event(event); + injected_touch_event = &event; + while (injected_touch_event != nullptr) { + chThdSleepMilliseconds(5); + } } void EventDispatcher::emulateKeyboard(ui::KeyboardEvent event) { - on_keyboard_event(event); + injected_keyboard_event = &event; + while (injected_keyboard_event != nullptr) { + chThdSleepMilliseconds(5); + } } void EventDispatcher::on_keyboard_event(ui::KeyboardEvent event) { @@ -290,6 +318,8 @@ ui::Widget* EventDispatcher::getFocusedWidget() { } void EventDispatcher::handle_lcd_frame_sync() { + bool waiting_for_frame = this->waiting_for_frame; + DisplayFrameSyncMessage message; message_map.send(&message); @@ -297,6 +327,28 @@ void EventDispatcher::handle_lcd_frame_sync() { painter.paint_widget_tree(top_widget); portapack::backlight()->on(); + + if (waiting_for_frame) + this->waiting_for_frame = false; +} + +void EventDispatcher::wait_finish_frame() { + waiting_for_frame = true; + while (waiting_for_frame) { + chThdSleepMilliseconds(5); + } +} + +void EventDispatcher::enter_shell_working_mode() { + waiting_for_shellmode = true; + + while (waiting_for_shellmode) { + chThdSleepMilliseconds(5); + } +} + +void EventDispatcher::exit_shell_working_mode() { + shellmode_active = false; } void EventDispatcher::handle_switches() { diff --git a/firmware/application/event_m0.hpp b/firmware/application/event_m0.hpp index efc09fce..a4a3cfe0 100644 --- a/firmware/application/event_m0.hpp +++ b/firmware/application/event_m0.hpp @@ -90,6 +90,10 @@ class EventDispatcher { void emulateTouch(ui::TouchEvent event); void emulateKeyboard(ui::KeyboardEvent event); + void wait_finish_frame(); + void enter_shell_working_mode(); + void exit_shell_working_mode(); + ui::Widget* getTopWidget(); ui::Widget* getFocusedWidget(); @@ -105,6 +109,11 @@ class EventDispatcher { bool sd_card_present = false; static bool display_sleep; bool in_key_event = false; + volatile bool waiting_for_frame = false; + volatile bool waiting_for_shellmode = false; + volatile bool shellmode_active = false; + ui::TouchEvent* volatile injected_touch_event = nullptr; + ui::KeyboardEvent* volatile injected_keyboard_event = nullptr; eventmask_t wait(); void dispatch(const eventmask_t events); @@ -113,6 +122,7 @@ class EventDispatcher { void handle_local_queue(); void handle_rtc_tick(); void handle_usb(); + void handle_shell(); static ui::Widget* touch_widget(ui::Widget* const w, ui::TouchEvent event); diff --git a/firmware/application/usb_serial_shell.cpp b/firmware/application/usb_serial_shell.cpp index cdff3036..10cab662 100644 --- a/firmware/application/usb_serial_shell.cpp +++ b/firmware/application/usb_serial_shell.cpp @@ -248,6 +248,9 @@ static void cmd_screenframe(BaseSequentialStream* chp, int argc, char* argv[]) { (void)argc; (void)argv; + auto evtd = getEventDispatcherInstance(); + evtd->enter_shell_working_mode(); + for (int i = 0; i < ui::screen_height; i++) { std::array row; portapack::display.read_pixels({0, i, ui::screen_width, 1}, row); @@ -258,6 +261,9 @@ static void cmd_screenframe(BaseSequentialStream* chp, int argc, char* argv[]) { } chprintf(chp, "\r\n"); } + + evtd->exit_shell_working_mode(); + chprintf(chp, "ok\r\n"); } @@ -275,6 +281,9 @@ static void cmd_screenframeshort(BaseSequentialStream* chp, int argc, char* argv (void)argc; (void)argv; + auto evtd = getEventDispatcherInstance(); + evtd->enter_shell_working_mode(); + for (int y = 0; y < ui::screen_height; y++) { std::array row; portapack::display.read_pixels({0, y, ui::screen_width, 1}, row); @@ -288,8 +297,10 @@ static void cmd_screenframeshort(BaseSequentialStream* chp, int argc, char* argv chprintf(chp, "\r\n"); } + evtd->exit_shell_working_mode(); chprintf(chp, "ok\r\n"); } + static void cmd_write_memory(BaseSequentialStream* chp, int argc, char* argv[]) { if (argc != 2) { chprintf(chp, "usage: write_memory
\r\n"); @@ -344,6 +355,11 @@ static void cmd_button(BaseSequentialStream* chp, int argc, char* argv[]) { control::debug::inject_switch(button); + // Wait two frame syncs to ensure action has painted + auto evtd = getEventDispatcherInstance(); + evtd->wait_finish_frame(); + evtd->wait_finish_frame(); + chprintf(chp, "ok\r\n"); } @@ -366,6 +382,11 @@ static void cmd_touch(BaseSequentialStream* chp, int argc, char* argv[]) { } evtd->emulateTouch({{x, y}, ui::TouchEvent::Type::Start}); evtd->emulateTouch({{x, y}, ui::TouchEvent::Type::End}); + + // Wait two frame syncs to ensure action has painted + evtd->wait_finish_frame(); + evtd->wait_finish_frame(); + chprintf(chp, "ok\r\n"); } @@ -404,6 +425,10 @@ static void cmd_keyboard(BaseSequentialStream* chp, int argc, char* argv[]) { evtd->emulateKeyboard(chr); } + // Wait two frame syncs to ensure action has painted + evtd->wait_finish_frame(); + evtd->wait_finish_frame(); + chprintf(chp, "ok\r\n"); }