123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- /******************
- * event_loop.cpp *
- ******************/
-
- /****************************************************************************
- * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
- * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
- * *
- * This program is free software: you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation, either version 3 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * To view a copy of the GNU General Public License, go to the following *
- * location: <https://www.gnu.org/licenses/>. *
- ****************************************************************************/
-
- #include "ftdi_extended.h"
-
- #if ENABLED(FTDI_EXTENDED)
- using namespace FTDI;
-
- enum {
- UNPRESSED = 0x00
- };
-
- tiny_timer_t touch_timer;
- UIData::flags_t UIData::flags;
- uint8_t pressed_tag = UNPRESSED;
-
- uint8_t UIData::get_persistent_data_mask() {
- // A bit mask for flags that should be stored to the EEPROM.
- // Others are considered temporarily values that need not be
- // saved.
- constexpr flags_t persistent_flags = {
- bits: {
- touch_start_sound: true,
- touch_end_sound: true,
- touch_repeat_sound: true,
- show_animations: true
- }
- };
- return persistent_flags.value;
- }
-
- void UIData::reset_persistent_data() {
- // Default values for persistent data
- constexpr flags_t default_flags = {
- bits: {
- touch_start_sound: true,
- touch_end_sound: true,
- touch_repeat_sound: true,
- show_animations: true,
- touch_debouncing: false,
- ignore_unpress: false
- }
- };
- flags.value = default_flags.value;
- }
-
- uint8_t UIData::get_persistent_data() {
- return flags.value & get_persistent_data_mask();
- }
-
- void UIData::set_persistent_data(uint8_t value) {
- flags.value = value & get_persistent_data_mask();
- }
-
-
- void UIData::enable_touch_sounds(bool enabled) {
- UIData::flags.bits.touch_start_sound = enabled;
- UIData::flags.bits.touch_end_sound = enabled;
- UIData::flags.bits.touch_repeat_sound = enabled;
- }
-
- bool UIData::touch_sounds_enabled() {
- return UIData::flags.bits.touch_start_sound || UIData::flags.bits.touch_end_sound || UIData::flags.bits.touch_repeat_sound;
- }
-
- void UIData::enable_animations(bool enabled) {
- UIData::flags.bits.show_animations = enabled;
- }
-
- bool UIData::animations_enabled() {
- return UIData::flags.bits.show_animations;
- }
-
- namespace FTDI {
- uint8_t EventLoop::get_pressed_tag() {
- return pressed_tag;
- }
-
- bool EventLoop::is_touch_held() {
- return pressed_tag != 0;
- }
-
- /**
- * process_events(): Process events from the touch panel.
- *
- * This function consists of a state machine that accomplishes the following:
- *
- * - Reads the tag register from the touch panel
- * - Dispatches onTouchStart and onTouchEnd events to the active screen.
- * - Handles auto-repetition by sending onTouchHeld to the active screen periodically.
- * - Plays touch feedback "click" sounds when appropriate.
- * - Performs debouncing to supress spurious touch events.
- */
- void EventLoop::process_events() {
- // If the LCD is processing commands, don't check
- // for tags since they may be changing and could
- // cause spurious events.
- if (!touch_timer.elapsed(TOUCH_UPDATE_INTERVAL) || CLCD::CommandFifo::is_processing()) {
- return;
- }
-
- const uint8_t tag = CLCD::get_tag();
-
- switch (pressed_tag) {
- case UNPRESSED:
- if (tag != 0) {
- #if ENABLED(TOUCH_UI_DEBUG)
- SERIAL_ECHO_MSG("Touch start: ", tag);
- #endif
-
- pressed_tag = tag;
- current_screen.onRefresh();
-
- // When the user taps on a button, activate the onTouchStart handler
- const uint8_t lastScreen = current_screen.getScreen();
-
- if (current_screen.onTouchStart(tag)) {
- touch_timer.start();
- if (UIData::flags.bits.touch_start_sound) sound.play(press_sound);
- }
-
- // In the case in which a touch event triggered a new screen to be
- // drawn, we don't issue a touchEnd since it would be sent to the
- // wrong screen.
- UIData::flags.bits.ignore_unpress = (lastScreen != current_screen.getScreen());
- }
- else {
- touch_timer.start();
- }
- break;
- default: // PRESSED
- if (!UIData::flags.bits.touch_debouncing) {
- if (tag == pressed_tag) {
- // The user is holding down a button.
- if (touch_timer.elapsed(1000 / TOUCH_REPEATS_PER_SECOND)) {
- if (current_screen.onTouchHeld(tag)) {
- current_screen.onRefresh();
- if (UIData::flags.bits.touch_repeat_sound) sound.play(repeat_sound);
- }
- touch_timer.start();
- }
- }
- else if (tag == 0) {
- touch_timer.start();
- UIData::flags.bits.touch_debouncing = true;
- }
- }
-
- else {
- // Debouncing...
-
- if (tag == pressed_tag) {
- // If while debouncing, we detect a press, then cancel debouncing.
- UIData::flags.bits.touch_debouncing = false;
- }
-
- else if (touch_timer.elapsed(DEBOUNCE_PERIOD)) {
- UIData::flags.bits.touch_debouncing = false;
-
- if (UIData::flags.bits.ignore_unpress) {
- UIData::flags.bits.ignore_unpress = false;
- pressed_tag = UNPRESSED;
- break;
- }
-
- if (UIData::flags.bits.touch_end_sound) sound.play(unpress_sound);
-
- #if ENABLED(TOUCH_UI_DEBUG)
- SERIAL_ECHO_MSG("Touch end: ", pressed_tag);
- #endif
-
- const uint8_t saved_pressed_tag = pressed_tag;
- pressed_tag = UNPRESSED;
- current_screen.onTouchEnd(saved_pressed_tag);
- current_screen.onRefresh();
- }
- }
- break;
- } // switch (pressed_tag)
-
- } // processEvents()
-
- void EventLoop::setup() {
- CLCD::init();
- DLCache::init();
- UIData::reset_persistent_data();
- current_screen.start();
- }
-
- void EventLoop::loop() {
- sound.onIdle();
-
- /**
- * Guard against re-entry of UI methods, which can
- * crash. Re-entry can happen because some functions
- * (e.g. planner.synchronize) call idle().
- */
- if (!UIData::flags.bits.prevent_reentry) {
- UIData::flags.bits.prevent_reentry = true;
- current_screen.onIdle();
- process_events();
- UIData::flags.bits.prevent_reentry = false;
- }
- }
- } // namespace FTDI
-
- #endif // FTDI_EXTENDED
|