227 lines
7.1 KiB
C++
227 lines
7.1 KiB
C++
/******************
|
|
* 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
|