mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-06-27 10:22:34 +00:00
feat(core): add event polling to button driver
[no changelog]
This commit is contained in:
parent
b9d15cb343
commit
8d7a25e5eb
86
core/embed/io/button/button_fsm.c
Normal file
86
core/embed/io/button/button_fsm.c
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef KERNEL_MODE
|
||||||
|
|
||||||
|
#include <trezor_rtl.h>
|
||||||
|
|
||||||
|
#include <sys/systick.h>
|
||||||
|
|
||||||
|
#include "button_fsm.h"
|
||||||
|
|
||||||
|
void button_fsm_init(button_fsm_t* fsm) {
|
||||||
|
memset(fsm, 0, sizeof(button_fsm_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool button_fsm_event_ready(button_fsm_t* fsm, uint32_t new_state) {
|
||||||
|
// Remember state changes
|
||||||
|
fsm->pressed |= new_state & ~fsm->state;
|
||||||
|
fsm->released |= ~new_state & fsm->state;
|
||||||
|
fsm->time = systick_us();
|
||||||
|
// Return true if there are any state changes
|
||||||
|
return (fsm->pressed | fsm->released) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool button_fsm_get_event(button_fsm_t* fsm, uint32_t new_state,
|
||||||
|
button_event_t* event) {
|
||||||
|
uint64_t now = systick_us();
|
||||||
|
|
||||||
|
if ((now - fsm->time) > 100000) {
|
||||||
|
// Reset the history if the button was not read for 100ms
|
||||||
|
fsm->pressed = 0;
|
||||||
|
fsm->released = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember state changes and the time of the last read
|
||||||
|
fsm->pressed |= new_state & ~fsm->state;
|
||||||
|
fsm->released |= ~new_state & fsm->state;
|
||||||
|
|
||||||
|
// Bring the automaton out of invalid states,
|
||||||
|
// in case it somehow ends up in one.
|
||||||
|
fsm->released &= fsm->pressed | fsm->state;
|
||||||
|
fsm->pressed &= fsm->released | ~fsm->state;
|
||||||
|
|
||||||
|
uint8_t button_idx = 0;
|
||||||
|
while (fsm->pressed | fsm->released) {
|
||||||
|
uint32_t mask = 1 << button_idx;
|
||||||
|
|
||||||
|
if ((fsm->pressed & mask) != 0 && (fsm->state & mask) == 0) {
|
||||||
|
// Button press was not signalled yet
|
||||||
|
fsm->pressed &= ~mask;
|
||||||
|
fsm->state |= mask;
|
||||||
|
event->button = (button_t)button_idx;
|
||||||
|
event->event_type = BTN_EVENT_DOWN;
|
||||||
|
return true;
|
||||||
|
} else if ((fsm->released & mask) != 0 && (fsm->state & mask) != 0) {
|
||||||
|
// Button release was not signalled yet
|
||||||
|
fsm->released &= ~mask;
|
||||||
|
fsm->state &= ~mask;
|
||||||
|
event->button = (button_t)button_idx;
|
||||||
|
event->event_type = BTN_EVENT_UP;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
++button_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // KERNEL_MODE
|
59
core/embed/io/button/button_fsm.h
Normal file
59
core/embed/io/button/button_fsm.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the Trezor project, https://trezor.io/
|
||||||
|
*
|
||||||
|
* Copyright (c) SatoshiLabs
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <io/button.h>
|
||||||
|
|
||||||
|
// This module is a simple finite state machine for buttons.
|
||||||
|
//
|
||||||
|
// It is designed to be used in a polling loop, where the state of the buttons
|
||||||
|
// is read periodically. The module keeps track of the state changes and
|
||||||
|
// provides a simple interface to get the events that happened since the last
|
||||||
|
// call to button_fsm_get_event().
|
||||||
|
//
|
||||||
|
// The structure is designed to be used in a multi-threaded environment, where
|
||||||
|
// each thread has its own state machine. The state machines are stored in an
|
||||||
|
// array indexed by the task ID.
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// Time of last update of pressed/released data
|
||||||
|
uint64_t time;
|
||||||
|
// Button presses that were detected since last get_event call
|
||||||
|
uint32_t pressed;
|
||||||
|
// Button releases that were detected since last get_event call
|
||||||
|
uint32_t released;
|
||||||
|
// State of buttons signalled to the poller
|
||||||
|
uint32_t state;
|
||||||
|
} button_fsm_t;
|
||||||
|
|
||||||
|
// Initializes button finite state machine
|
||||||
|
void button_fsm_init(button_fsm_t* fsm);
|
||||||
|
|
||||||
|
// Checks if button_fsm_get_event() would return `true` on the next call
|
||||||
|
bool button_fsm_event_ready(button_fsm_t* fsm, uint32_t new_state);
|
||||||
|
|
||||||
|
// Processes the new_state of the button and fills the event structure.
|
||||||
|
//
|
||||||
|
// `new_state` is the current state of the buttons - each bit represents
|
||||||
|
// the state of one button (up to 32 buttons can be handled simultaneously).
|
||||||
|
//
|
||||||
|
// Returns `true` if the event structure was filled.
|
||||||
|
bool button_fsm_get_event(button_fsm_t* fsm, uint32_t new_state,
|
||||||
|
button_event_t* event);
|
@ -68,8 +68,4 @@ void button_deinit(void);
|
|||||||
bool button_get_event(button_event_t* event);
|
bool button_get_event(button_event_t* event);
|
||||||
|
|
||||||
// Checks if the specified button is currently pressed
|
// Checks if the specified button is currently pressed
|
||||||
//
|
|
||||||
// The current implementation returns the state of the button at the time
|
|
||||||
// `button_get_event()` was called. In the future, we may fix this limitation.
|
|
||||||
// For now, `button_get_event()` must be called before `button_is_down()`.
|
|
||||||
bool button_is_down(button_t button);
|
bool button_is_down(button_t button);
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
#include <io/button.h>
|
#include <io/button.h>
|
||||||
#include <sys/irq.h>
|
#include <sys/irq.h>
|
||||||
#include <sys/mpu.h>
|
#include <sys/mpu.h>
|
||||||
|
#include <sys/sysevent_source.h>
|
||||||
|
|
||||||
|
#include "../button_fsm.h"
|
||||||
|
|
||||||
#ifdef USE_POWERCTL
|
#ifdef USE_POWERCTL
|
||||||
#include <sys/wakeup_flags.h>
|
#include <sys/wakeup_flags.h>
|
||||||
@ -34,15 +37,8 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
|
||||||
#ifdef BTN_LEFT_PIN
|
// Each task has its own state machine
|
||||||
bool left_down;
|
button_fsm_t tls[SYSTASK_MAX_TASKS];
|
||||||
#endif
|
|
||||||
#ifdef BTN_RIGHT_PIN
|
|
||||||
bool right_down;
|
|
||||||
#endif
|
|
||||||
#ifdef BTN_POWER_PIN
|
|
||||||
bool power_down;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} button_driver_t;
|
} button_driver_t;
|
||||||
|
|
||||||
@ -51,6 +47,9 @@ static button_driver_t g_button_driver = {
|
|||||||
.initialized = false,
|
.initialized = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
static const syshandle_vmt_t g_button_handle_vmt;
|
||||||
|
|
||||||
static void button_setup_pin(GPIO_TypeDef* port, uint16_t pin) {
|
static void button_setup_pin(GPIO_TypeDef* port, uint16_t pin) {
|
||||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||||
|
|
||||||
@ -99,81 +98,66 @@ bool button_init(void) {
|
|||||||
NVIC_EnableIRQ(BTN_EXTI_INTERRUPT_NUM);
|
NVIC_EnableIRQ(BTN_EXTI_INTERRUPT_NUM);
|
||||||
#endif // BTN_EXTI_INTERRUPT_HANDLER
|
#endif // BTN_EXTI_INTERRUPT_HANDLER
|
||||||
|
|
||||||
drv->initialized = true;
|
if (!syshandle_register(SYSHANDLE_BUTTON, &g_button_handle_vmt, drv)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv->initialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
button_deinit();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void button_deinit(void) {
|
void button_deinit(void) {
|
||||||
|
button_driver_t* drv = &g_button_driver;
|
||||||
|
|
||||||
|
syshandle_unregister(SYSHANDLE_BUTTON);
|
||||||
|
|
||||||
#ifdef BTN_EXIT_INTERRUPT_HANDLER
|
#ifdef BTN_EXIT_INTERRUPT_HANDLER
|
||||||
NVIC_DisableIRQ(BTN_EXTI_INTERRUPT_NUM);
|
NVIC_DisableIRQ(BTN_EXTI_INTERRUPT_NUM);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
memset(drv, 0, sizeof(button_driver_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t button_read_state(button_driver_t* drv) {
|
||||||
|
UNUSED(drv);
|
||||||
|
uint32_t state = 0;
|
||||||
|
|
||||||
|
#ifdef BTN_LEFT_PIN
|
||||||
|
if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(BTN_LEFT_PORT, BTN_LEFT_PIN)) {
|
||||||
|
state |= (1U << BTN_LEFT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BTN_RIGHT_PIN
|
||||||
|
if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(BTN_RIGHT_PORT, BTN_RIGHT_PIN)) {
|
||||||
|
state |= (1U << BTN_RIGHT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BTN_POWER_PIN
|
||||||
|
if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(BTN_POWER_PORT, BTN_POWER_PIN)) {
|
||||||
|
state |= (1U << BTN_POWER);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool button_get_event(button_event_t* event) {
|
bool button_get_event(button_event_t* event) {
|
||||||
button_driver_t* drv = &g_button_driver;
|
button_driver_t* drv = &g_button_driver;
|
||||||
|
|
||||||
memset(event, 0, sizeof(*event));
|
memset(event, 0, sizeof(*event));
|
||||||
|
|
||||||
if (!drv->initialized) {
|
if (!drv->initialized) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BTN_LEFT_PIN
|
uint32_t new_state = button_read_state(drv);
|
||||||
bool left_down =
|
|
||||||
(GPIO_PIN_RESET == HAL_GPIO_ReadPin(BTN_LEFT_PORT, BTN_LEFT_PIN));
|
|
||||||
|
|
||||||
if (drv->left_down != left_down) {
|
button_fsm_t* fsm = &drv->tls[systask_id(systask_active())];
|
||||||
drv->left_down = left_down;
|
return button_fsm_get_event(fsm, new_state, event);
|
||||||
if (left_down) {
|
|
||||||
event->button = BTN_LEFT;
|
|
||||||
event->event_type = BTN_EVENT_DOWN;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
event->button = BTN_LEFT;
|
|
||||||
event->event_type = BTN_EVENT_UP;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BTN_RIGHT_PIN
|
|
||||||
bool right_down =
|
|
||||||
(GPIO_PIN_RESET == HAL_GPIO_ReadPin(BTN_RIGHT_PORT, BTN_RIGHT_PIN));
|
|
||||||
|
|
||||||
if (drv->right_down != right_down) {
|
|
||||||
drv->right_down = right_down;
|
|
||||||
if (right_down) {
|
|
||||||
event->button = BTN_RIGHT;
|
|
||||||
event->event_type = BTN_EVENT_DOWN;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
event->button = BTN_RIGHT;
|
|
||||||
event->event_type = BTN_EVENT_UP;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef BTN_POWER_PIN
|
|
||||||
bool power_down =
|
|
||||||
(GPIO_PIN_RESET == HAL_GPIO_ReadPin(BTN_POWER_PORT, BTN_POWER_PIN));
|
|
||||||
|
|
||||||
if (drv->power_down != power_down) {
|
|
||||||
drv->power_down = power_down;
|
|
||||||
if (power_down) {
|
|
||||||
event->button = BTN_POWER;
|
|
||||||
event->event_type = BTN_EVENT_DOWN;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
event->button = BTN_POWER;
|
|
||||||
event->event_type = BTN_EVENT_UP;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool button_is_down(button_t button) {
|
bool button_is_down(button_t button) {
|
||||||
@ -183,22 +167,7 @@ bool button_is_down(button_t button) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (button) {
|
return (button_read_state(drv) & (1 << button)) != 0;
|
||||||
#ifdef BTN_LEFT_PIN
|
|
||||||
case BTN_LEFT:
|
|
||||||
return drv->left_down;
|
|
||||||
#endif
|
|
||||||
#ifdef BTN_RIGHT_PIN
|
|
||||||
case BTN_RIGHT:
|
|
||||||
return drv->right_down;
|
|
||||||
#endif
|
|
||||||
#ifdef BTN_POWER_PIN
|
|
||||||
case BTN_POWER:
|
|
||||||
return drv->power_down;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BTN_EXTI_INTERRUPT_HANDLER
|
#ifdef BTN_EXTI_INTERRUPT_HANDLER
|
||||||
@ -221,4 +190,40 @@ void BTN_EXTI_INTERRUPT_HANDLER(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void on_task_created(void* context, systask_id_t task_id) {
|
||||||
|
button_driver_t* drv = (button_driver_t*)context;
|
||||||
|
button_fsm_t* fsm = &drv->tls[task_id];
|
||||||
|
button_fsm_init(fsm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_event_poll(void* context, bool read_awaited,
|
||||||
|
bool write_awaited) {
|
||||||
|
button_driver_t* drv = (button_driver_t*)context;
|
||||||
|
|
||||||
|
UNUSED(write_awaited);
|
||||||
|
|
||||||
|
if (read_awaited) {
|
||||||
|
uint32_t state = button_read_state(drv);
|
||||||
|
syshandle_signal_read_ready(SYSHANDLE_BUTTON, &state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool on_check_read_ready(void* context, systask_id_t task_id,
|
||||||
|
void* param) {
|
||||||
|
button_driver_t* drv = (button_driver_t*)context;
|
||||||
|
button_fsm_t* fsm = &drv->tls[task_id];
|
||||||
|
|
||||||
|
uint32_t new_state = *(uint32_t*)param;
|
||||||
|
|
||||||
|
return button_fsm_event_ready(fsm, new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const syshandle_vmt_t g_button_handle_vmt = {
|
||||||
|
.task_created = on_task_created,
|
||||||
|
.task_killed = NULL,
|
||||||
|
.check_read_ready = on_check_read_ready,
|
||||||
|
.check_write_ready = NULL,
|
||||||
|
.poll = on_event_poll,
|
||||||
|
};
|
||||||
|
|
||||||
#endif // KERNEL_MODE
|
#endif // KERNEL_MODE
|
||||||
|
@ -20,23 +20,19 @@
|
|||||||
#include <trezor_bsp.h>
|
#include <trezor_bsp.h>
|
||||||
#include <trezor_rtl.h>
|
#include <trezor_rtl.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
|
||||||
|
|
||||||
#include <io/button.h>
|
#include <io/button.h>
|
||||||
|
#include <sys/sysevent_source.h>
|
||||||
|
#include <sys/unix/sdl_event.h>
|
||||||
|
|
||||||
|
#include "../button_fsm.h"
|
||||||
|
|
||||||
// Button driver state
|
// Button driver state
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
// Global state of buttons
|
||||||
#ifdef BTN_LEFT_KEY
|
uint32_t state;
|
||||||
bool left_down;
|
// Each task has its own state machine
|
||||||
#endif
|
button_fsm_t tls[SYSTASK_MAX_TASKS];
|
||||||
#ifdef BTN_RIGHT_KEY
|
|
||||||
bool right_down;
|
|
||||||
#endif
|
|
||||||
#ifdef BTN_POWER_KEY
|
|
||||||
bool power_down;
|
|
||||||
#endif
|
|
||||||
} button_driver_t;
|
} button_driver_t;
|
||||||
|
|
||||||
// Button driver instance
|
// Button driver instance
|
||||||
@ -44,6 +40,10 @@ static button_driver_t g_button_driver = {
|
|||||||
.initialized = false,
|
.initialized = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
static const syshandle_vmt_t g_button_handle_vmt;
|
||||||
|
static void button_sdl_event_filter(void* context, SDL_Event* sdl_event);
|
||||||
|
|
||||||
bool button_init(void) {
|
bool button_init(void) {
|
||||||
button_driver_t* drv = &g_button_driver;
|
button_driver_t* drv = &g_button_driver;
|
||||||
|
|
||||||
@ -53,58 +53,92 @@ bool button_init(void) {
|
|||||||
|
|
||||||
memset(drv, 0, sizeof(button_driver_t));
|
memset(drv, 0, sizeof(button_driver_t));
|
||||||
|
|
||||||
drv->initialized = true;
|
if (!syshandle_register(SYSHANDLE_BUTTON, &g_button_handle_vmt, drv)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sdl_events_register(button_sdl_event_filter, drv)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
drv->initialized = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
button_deinit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void button_deinit(void) {
|
||||||
|
button_driver_t* drv = &g_button_driver;
|
||||||
|
|
||||||
|
syshandle_unregister(SYSHANDLE_BUTTON);
|
||||||
|
|
||||||
|
sdl_events_unregister(button_sdl_event_filter, drv);
|
||||||
|
|
||||||
|
memset(drv, 0, sizeof(button_driver_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called from global event loop to filter and process SDL events
|
||||||
|
static void button_sdl_event_filter(void* context, SDL_Event* sdl_event) {
|
||||||
|
button_driver_t* drv = &g_button_driver;
|
||||||
|
|
||||||
|
if (sdl_event->type != SDL_KEYDOWN && sdl_event->type != SDL_KEYUP) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdl_event->key.repeat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
button_t button;
|
||||||
|
|
||||||
|
switch (sdl_event->key.keysym.sym) {
|
||||||
|
#ifdef BTN_LEFT_KEY
|
||||||
|
case BTN_LEFT_KEY:
|
||||||
|
button = BTN_LEFT;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef BTN_RIGHT_KEY
|
||||||
|
case BTN_RIGHT_KEY:
|
||||||
|
button = BTN_RIGHT;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef BTN_POWER_KEY
|
||||||
|
case BTN_POWER_KEY:
|
||||||
|
button = BTN_POWER;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdl_event->type == SDL_KEYDOWN) {
|
||||||
|
drv->state |= (1 << button);
|
||||||
|
} else {
|
||||||
|
drv->state &= ~(1 << button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t button_read_state(button_driver_t* drv) {
|
||||||
|
sdl_events_poll();
|
||||||
|
return drv->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool button_get_event(button_event_t* event) {
|
bool button_get_event(button_event_t* event) {
|
||||||
button_driver_t* drv = &g_button_driver;
|
button_driver_t* drv = &g_button_driver;
|
||||||
|
memset(event, 0, sizeof(*event));
|
||||||
memset(event, 0, sizeof(button_event_t));
|
|
||||||
|
|
||||||
if (!drv->initialized) {
|
if (!drv->initialized) {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Event sdl_event;
|
|
||||||
|
|
||||||
if (SDL_PollEvent(&sdl_event) > 0 &&
|
|
||||||
(sdl_event.type == SDL_KEYDOWN || sdl_event.type == SDL_KEYUP) &&
|
|
||||||
!sdl_event.key.repeat) {
|
|
||||||
bool down = (sdl_event.type == SDL_KEYDOWN);
|
|
||||||
uint32_t evt_type = down ? BTN_EVENT_DOWN : BTN_EVENT_UP;
|
|
||||||
|
|
||||||
switch (sdl_event.key.keysym.sym) {
|
|
||||||
#ifdef BTN_LEFT_KEY
|
|
||||||
case BTN_LEFT_KEY:
|
|
||||||
drv->left_down = down;
|
|
||||||
event->event_type = evt_type;
|
|
||||||
event->button = BTN_LEFT;
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
#ifdef BTN_RIGHT_KEY
|
|
||||||
case BTN_RIGHT_KEY:
|
|
||||||
drv->right_down = down;
|
|
||||||
event->event_type = evt_type;
|
|
||||||
event->button = BTN_RIGHT;
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
#ifdef BTN_POWER_KEY
|
|
||||||
case BTN_POWER_KEY:
|
|
||||||
drv->power_down = down;
|
|
||||||
event->event_type = evt_type;
|
|
||||||
event->button = BTN_POWER;
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t new_state = button_read_state(drv);
|
||||||
|
|
||||||
|
button_fsm_t* fsm = &drv->tls[systask_id(systask_active())];
|
||||||
|
return button_fsm_get_event(fsm, new_state, event);
|
||||||
|
}
|
||||||
|
|
||||||
bool button_is_down(button_t button) {
|
bool button_is_down(button_t button) {
|
||||||
button_driver_t* drv = &g_button_driver;
|
button_driver_t* drv = &g_button_driver;
|
||||||
|
|
||||||
@ -112,20 +146,35 @@ bool button_is_down(button_t button) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (button) {
|
return (button_read_state(drv) & (1 << button)) != 0;
|
||||||
#ifdef BTN_LEFT_KEY
|
}
|
||||||
case BTN_LEFT:
|
|
||||||
return drv->left_down;
|
static void on_event_poll(void* context, bool read_awaited,
|
||||||
#endif
|
bool write_awaited) {
|
||||||
#ifdef BTN_RIGHT_KEY
|
button_driver_t* drv = (button_driver_t*)context;
|
||||||
case BTN_RIGHT:
|
|
||||||
return drv->right_down;
|
UNUSED(write_awaited);
|
||||||
#endif
|
|
||||||
#ifdef BTN_POWER_KEY
|
if (read_awaited) {
|
||||||
case BTN_POWER:
|
uint32_t state = button_read_state(drv);
|
||||||
return drv->power_down;
|
syshandle_signal_read_ready(SYSHANDLE_BUTTON, &state);
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool on_check_read_ready(void* context, systask_id_t task_id,
|
||||||
|
void* param) {
|
||||||
|
button_driver_t* drv = (button_driver_t*)context;
|
||||||
|
button_fsm_t* fsm = &drv->tls[task_id];
|
||||||
|
|
||||||
|
uint32_t new_state = *(uint32_t*)param;
|
||||||
|
|
||||||
|
return button_fsm_event_ready(fsm, new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const syshandle_vmt_t g_button_handle_vmt = {
|
||||||
|
.task_created = NULL,
|
||||||
|
.task_killed = NULL,
|
||||||
|
.check_read_ready = on_check_read_ready,
|
||||||
|
.check_write_ready = NULL,
|
||||||
|
.poll = on_event_poll,
|
||||||
|
};
|
||||||
|
@ -70,15 +70,11 @@ void ui_click(void) {
|
|||||||
|
|
||||||
void ui_click(void) {
|
void ui_click(void) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
button_event_t event = {0};
|
|
||||||
button_get_event(&event);
|
|
||||||
if (button_is_down(BTN_LEFT) && button_is_down(BTN_RIGHT)) {
|
if (button_is_down(BTN_LEFT) && button_is_down(BTN_RIGHT)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (;;) {
|
for (;;) {
|
||||||
button_event_t event = {0};
|
|
||||||
button_get_event(&event);
|
|
||||||
if (!button_is_down(BTN_LEFT) && !button_is_down(BTN_RIGHT)) {
|
if (!button_is_down(BTN_LEFT) && !button_is_down(BTN_RIGHT)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -362,8 +362,6 @@ int bootloader_main(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined USE_BUTTON
|
#elif defined USE_BUTTON
|
||||||
button_event_t btn_evt = {0};
|
|
||||||
button_get_event(&btn_evt);
|
|
||||||
if (button_is_down(BTN_LEFT)) {
|
if (button_is_down(BTN_LEFT)) {
|
||||||
touched = 1;
|
touched = 1;
|
||||||
}
|
}
|
||||||
|
@ -67,10 +67,6 @@ static void test_button_combination(cli_t* cli, uint32_t timeout, button_t btn1,
|
|||||||
cli_trace(cli, "Waiting for button combination to be pressed...");
|
cli_trace(cli, "Waiting for button combination to be pressed...");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Event must be read before calling `button_is_down()`
|
|
||||||
button_event_t e = {0};
|
|
||||||
button_get_event(&e);
|
|
||||||
|
|
||||||
if (button_is_down(btn1) && button_is_down(btn2)) {
|
if (button_is_down(btn1) && button_is_down(btn2)) {
|
||||||
break;
|
break;
|
||||||
} else if (ticks_expired(expire_time)) {
|
} else if (ticks_expired(expire_time)) {
|
||||||
@ -84,10 +80,6 @@ static void test_button_combination(cli_t* cli, uint32_t timeout, button_t btn1,
|
|||||||
cli_trace(cli, "Waiting for buttons to be released...");
|
cli_trace(cli, "Waiting for buttons to be released...");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// Event must be read before calling `button_is_down()`
|
|
||||||
button_event_t e = {0};
|
|
||||||
button_get_event(&e);
|
|
||||||
|
|
||||||
if (!button_is_down(btn1) && !button_is_down(btn2)) {
|
if (!button_is_down(btn1) && !button_is_down(btn2)) {
|
||||||
break;
|
break;
|
||||||
} else if (ticks_expired(expire_time)) {
|
} else if (ticks_expired(expire_time)) {
|
||||||
|
@ -50,6 +50,7 @@ def configure(
|
|||||||
|
|
||||||
if "input" in features_wanted:
|
if "input" in features_wanted:
|
||||||
sources += ["embed/io/button/unix/button.c"]
|
sources += ["embed/io/button/unix/button.c"]
|
||||||
|
sources += ["embed/io/button/button_fsm.c"]
|
||||||
paths += ["embed/io/button/inc"]
|
paths += ["embed/io/button/inc"]
|
||||||
features_available.append("button")
|
features_available.append("button")
|
||||||
defines += [("USE_BUTTON", "1")]
|
defines += [("USE_BUTTON", "1")]
|
||||||
|
@ -50,6 +50,7 @@ def configure(
|
|||||||
|
|
||||||
if "input" in features_wanted:
|
if "input" in features_wanted:
|
||||||
sources += ["embed/io/button/stm32/button.c"]
|
sources += ["embed/io/button/stm32/button.c"]
|
||||||
|
sources += ["embed/io/button/button_fsm.c"]
|
||||||
paths += ["embed/io/button/inc"]
|
paths += ["embed/io/button/inc"]
|
||||||
features_available.append("button")
|
features_available.append("button")
|
||||||
defines += [("USE_BUTTON", "1")]
|
defines += [("USE_BUTTON", "1")]
|
||||||
|
@ -50,6 +50,7 @@ def configure(
|
|||||||
|
|
||||||
if "input" in features_wanted:
|
if "input" in features_wanted:
|
||||||
sources += ["embed/io/button/unix/button.c"]
|
sources += ["embed/io/button/unix/button.c"]
|
||||||
|
sources += ["embed/io/button/button_fsm.c"]
|
||||||
paths += ["embed/io/button/inc"]
|
paths += ["embed/io/button/inc"]
|
||||||
features_available.append("button")
|
features_available.append("button")
|
||||||
defines += [("USE_BUTTON", "1")]
|
defines += [("USE_BUTTON", "1")]
|
||||||
|
@ -49,6 +49,7 @@ def configure(
|
|||||||
|
|
||||||
if "input" in features_wanted:
|
if "input" in features_wanted:
|
||||||
sources += ["embed/io/button/stm32/button.c"]
|
sources += ["embed/io/button/stm32/button.c"]
|
||||||
|
sources += ["embed/io/button/button_fsm.c"]
|
||||||
paths += ["embed/io/button/inc"]
|
paths += ["embed/io/button/inc"]
|
||||||
features_available.append("button")
|
features_available.append("button")
|
||||||
defines += [("USE_BUTTON", "1")]
|
defines += [("USE_BUTTON", "1")]
|
||||||
|
@ -63,6 +63,7 @@ def configure(
|
|||||||
paths += ["embed/io/touch/inc"]
|
paths += ["embed/io/touch/inc"]
|
||||||
features_available.append("touch")
|
features_available.append("touch")
|
||||||
sources += ["embed/io/button/stm32/button.c"]
|
sources += ["embed/io/button/stm32/button.c"]
|
||||||
|
sources += ["embed/io/button/button_fsm.c"]
|
||||||
paths += ["embed/io/button/inc"]
|
paths += ["embed/io/button/inc"]
|
||||||
features_available.append("button")
|
features_available.append("button")
|
||||||
defines += [
|
defines += [
|
||||||
|
@ -63,6 +63,7 @@ def configure(
|
|||||||
paths += ["embed/io/touch/inc"]
|
paths += ["embed/io/touch/inc"]
|
||||||
features_available.append("touch")
|
features_available.append("touch")
|
||||||
sources += ["embed/io/button/stm32/button.c"]
|
sources += ["embed/io/button/stm32/button.c"]
|
||||||
|
sources += ["embed/io/button/button_fsm.c"]
|
||||||
paths += ["embed/io/button/inc"]
|
paths += ["embed/io/button/inc"]
|
||||||
features_available.append("button")
|
features_available.append("button")
|
||||||
defines += [
|
defines += [
|
||||||
|
@ -63,6 +63,7 @@ def configure(
|
|||||||
paths += ["embed/io/touch/inc"]
|
paths += ["embed/io/touch/inc"]
|
||||||
features_available.append("touch")
|
features_available.append("touch")
|
||||||
sources += ["embed/io/button/stm32/button.c"]
|
sources += ["embed/io/button/stm32/button.c"]
|
||||||
|
sources += ["embed/io/button/button_fsm.c"]
|
||||||
paths += ["embed/io/button/inc"]
|
paths += ["embed/io/button/inc"]
|
||||||
features_available.append("button")
|
features_available.append("button")
|
||||||
defines += [
|
defines += [
|
||||||
|
Loading…
Reference in New Issue
Block a user