Input: refactoring, platform agnostic key configuration.

Update input usage across project. Minor queue usage fixes and tick timings. (#330)
This commit is contained in:
あく 2021-02-10 11:56:05 +03:00 committed by GitHub
parent 5dbe2983aa
commit 8b94eff7f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 347 additions and 334 deletions

View File

@ -36,7 +36,7 @@ static void render_callback(Canvas* canvas, void* _ctx) {
static void input_callback(InputEvent* input_event, void* _ctx) {
AppLoaderState* ctx = (AppLoaderState*)_ctx;
if(input_event->state && input_event->input == InputBack) {
if(input_event->type == InputTypeShort && input_event->key == InputKeyBack) {
osThreadTerminate(ctx->app_thread_id);
view_port_enabled_set(ctx->view_port, false);
api_hal_timebase_insomnia_exit();

View File

@ -237,8 +237,11 @@ const FreqConfig FREQ_LIST[] = {
{&bands[10], 0},
};
extern "C" void cc1101_isr() {
gpio_write((GpioPin*)&debug_0, gpio_read(&cc1101_g0_gpio));
extern "C" void cc1101_isr(void* _pin, void* _ctx) {
uint32_t pin = (uint32_t)_pin;
if(pin == CC1101_G0_Pin) {
gpio_write((GpioPin*)&debug_0, gpio_read(&cc1101_g0_gpio));
}
}
typedef enum {
@ -343,7 +346,7 @@ static void input_callback(InputEvent* input_event, void* ctx) {
}
extern "C" void cc1101_workaround(void* p) {
osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL);
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
furi_check(event_queue);
State _state;
@ -383,7 +386,7 @@ extern "C" void cc1101_workaround(void* p) {
GpioPin cs_pin = {CC1101_CS_GPIO_Port, CC1101_CS_Pin};
gpio_init(&cc1101_g0_gpio, GpioModeInput);
api_interrupt_add(cc1101_isr, InterruptTypeExternalInterrupt, NULL);
// TODO open record
GpioPin* cs_pin_record = &cs_pin;
CC1101 cc1101(cs_pin_record);
@ -425,7 +428,8 @@ extern "C" void cc1101_workaround(void* p) {
if(event_status == osOK) {
if(event.type == EventTypeKey) {
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyBack) {
printf("[cc1101] bye!\r\n");
cc1101.SpiStrobe(CC1101_SIDLE);
@ -438,7 +442,8 @@ extern "C" void cc1101_workaround(void* p) {
furiac_exit(NULL);
}
if(event.value.input.state && event.value.input.input == InputDown) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyDown) {
if(state->active_freq_idx > 0) {
state->active_freq_idx--;
}
@ -448,7 +453,8 @@ extern "C" void cc1101_workaround(void* p) {
state->need_cc1101_conf = true;
}
if(event.value.input.state && event.value.input.input == InputUp) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyUp) {
if(state->active_freq_idx < (sizeof(FREQ_LIST) / sizeof(FREQ_LIST[0]) - 1)) {
state->active_freq_idx++;
}
@ -458,7 +464,8 @@ extern "C" void cc1101_workaround(void* p) {
state->need_cc1101_conf = true;
}
if(event.value.input.state && event.value.input.input == InputRight) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyRight) {
/*
if(state->tx_level < (sizeof(TX_LEVELS) / sizeof(TX_LEVELS[0]) - 1)) {
state->tx_level++;
@ -471,7 +478,8 @@ extern "C" void cc1101_workaround(void* p) {
state->need_cc1101_conf = true;
}
if(event.value.input.state && event.value.input.input == InputLeft) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyLeft) {
/*
if(state->tx_level < (sizeof(TX_LEVELS) / sizeof(TX_LEVELS[0]) - 1)) {
state->tx_level++;
@ -484,9 +492,14 @@ extern "C" void cc1101_workaround(void* p) {
state->need_cc1101_conf = true;
}
if(event.value.input.input == InputOk) {
state->mode = event.value.input.state ? ModeTx : ModeRx;
state->need_cc1101_conf = true;
if(event.value.input.key == InputKeyOk) {
if(event.value.input.type == InputTypePress) {
state->mode = ModeTx;
state->need_cc1101_conf = true;
} else if(event.value.input.type == InputTypeRelease) {
state->mode = ModeRx;
state->need_cc1101_conf = true;
}
}
}
} else {

View File

@ -4,13 +4,13 @@ bool dolphin_view_first_start_input(InputEvent* event, void* context) {
furi_assert(event);
furi_assert(context);
Dolphin* dolphin = context;
if(event->state) {
if(event->input == InputLeft) {
if(event->type == InputTypeShort) {
if(event->key == InputKeyLeft) {
with_view_model(
dolphin->idle_view_first_start, (DolphinViewFirstStartModel * model) {
if(model->page > 0) model->page--;
});
} else if(event->input == InputRight) {
} else if(event->key == InputKeyRight) {
uint32_t page;
with_view_model(
dolphin->idle_view_first_start,
@ -30,13 +30,13 @@ bool dolphin_view_idle_main_input(InputEvent* event, void* context) {
furi_assert(context);
Dolphin* dolphin = context;
if(event->state) {
if(event->input == InputOk) {
if(event->type == InputTypeShort) {
if(event->key == InputKeyOk) {
with_value_mutex(
dolphin->menu_vm, (Menu * menu) { menu_ok(menu); });
} else if(event->input == InputUp) {
} else if(event->key == InputKeyUp) {
view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleStats);
} else if(event->input == InputDown) {
} else if(event->key == InputKeyDown) {
view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleDebug);
}
}
@ -49,13 +49,13 @@ bool dolphin_view_idle_stats_input(InputEvent* event, void* context) {
furi_assert(context);
Dolphin* dolphin = context;
if(!event->state) return false;
if(event->type != InputTypeShort) return false;
if(event->input == InputLeft) {
if(event->key == InputKeyLeft) {
dolphin_deed(dolphin, DolphinDeedWrong);
} else if(event->input == InputRight) {
} else if(event->key == InputKeyRight) {
dolphin_deed(dolphin, DolphinDeedIButtonRead);
} else if(event->input == InputOk) {
} else if(event->key == InputKeyOk) {
dolphin_save(dolphin);
} else {
return false;

View File

@ -4,27 +4,17 @@
typedef union {
unsigned int packed;
InputState state;
InputType state;
} InputDump;
static void state_cb(const void* value, void* ctx) {
InputDump dump = {.packed = 0};
dump.state = *(InputState*)value;
printf("state: %02x\r\n", dump.packed);
}
static void event_cb(const void* value, void* ctx) {
const InputEvent* event = value;
printf("event: %02x %s\r\n", event->input, event->state ? "pressed" : "released");
printf("event: %02x %s\r\n", event->key, event->type ? "pressed" : "released");
}
void application_input_dump(void* p) {
// open record
ValueManager* state_record = furi_record_open("input_state");
subscribe_pubsub(&state_record->pubsub, state_cb, NULL);
PubSub* event_record = furi_record_open("input_events");
subscribe_pubsub(event_record, event_cb, NULL);

View File

@ -7,11 +7,11 @@ static void event_cb(const void* value, void* ctx) {
uint32_t* delay_time = acquire_mutex(ctx, 0);
if(delay_time == NULL) return;
if(event->input == InputUp && *delay_time < 1000) {
if(event->key == InputKeyUp && *delay_time < 1000) {
*delay_time += 5;
}
if(event->input == InputDown && *delay_time > 10) {
if(event->key == InputKeyDown && *delay_time > 10) {
*delay_time -= 5;
}
release_mutex(ctx, delay_time);

View File

@ -10,9 +10,14 @@ static void button_handler(const void* value, void* _ctx) {
const InputEvent* event = value;
Ctx* ctx = (Ctx*)_ctx;
if(event->input == InputOk) {
gpio_write(ctx->vibro, event->state);
gpio_write(ctx->led, !event->state);
if(event->key != InputKeyOk) return;
if(event->type == InputTypePress) {
gpio_write(ctx->led, false);
gpio_write(ctx->vibro, true);
} else if(event->type == InputTypeRelease) {
gpio_write(ctx->led, true);
gpio_write(ctx->vibro, false);
}
}

@ -1 +1 @@
Subproject commit 318b5f6c43b0219ec490a088ef51421fc8b94ac5
Subproject commit 598edd54197d58b35d8cc2513549ddda3938fa38

View File

@ -58,7 +58,7 @@ static void input_callback(InputEvent* input_event, void* ctx) {
}
void app_gpio_test(void* p) {
osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL);
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
furi_check(event_queue);
State _state;
@ -88,34 +88,41 @@ void app_gpio_test(void* p) {
AppEvent event;
while(1) {
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 150);
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
State* state = (State*)acquire_mutex_block(&state_mutex);
if(event_status == osOK) {
if(event.type == EventTypeKey) {
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyBack) {
printf("[gpio-tester] bye!\r\n");
// TODO remove all view_ports create by app
view_port_enabled_set(view_port, false);
furiac_exit(NULL);
}
if(event.value.input.state && event.value.input.input == InputRight) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyRight) {
if(state->gpio_index < (sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]) - 1)) {
state->gpio_index++;
}
}
if(event.value.input.state && event.value.input.input == InputLeft) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyLeft) {
if(state->gpio_index > 0) {
state->gpio_index--;
}
}
if(event.value.input.input == InputOk) {
gpio_write(
(GpioPin*)&GPIO_PINS[state->gpio_index].pin, event.value.input.state);
gpio_write((GpioPin*)&led_gpio[1], !event.value.input.state);
if(event.value.input.key == InputKeyOk) {
if(event.value.input.type == InputTypePress) {
gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, true);
gpio_write((GpioPin*)&led_gpio[1], false);
} else if(event.value.input.type == InputTypeRelease) {
gpio_write((GpioPin*)&GPIO_PINS[state->gpio_index].pin, false);
gpio_write((GpioPin*)&led_gpio[1], true);
}
}
}
}

View File

@ -43,11 +43,11 @@ static bool dialog_view_input_callback(InputEvent* event, void* context) {
bool consumed = false;
// Process key presses only
if(event->state && dialog->callback) {
if(event->input == InputLeft) {
if(event->type == InputTypeShort && dialog->callback) {
if(event->key == InputKeyLeft) {
dialog->callback(DialogResultLeft, dialog->context);
consumed = true;
} else if(event->input == InputRight) {
} else if(event->key == InputKeyRight) {
dialog->callback(DialogResultRight, dialog->context);
consumed = true;
}

View File

@ -97,14 +97,14 @@ static bool dialog_ex_view_input_callback(InputEvent* event, void* context) {
});
// Process key presses only
if(event->state && dialog_ex->callback) {
if(event->input == InputLeft && left_text != NULL) {
if(event->type == InputTypeShort && dialog_ex->callback) {
if(event->key == InputKeyLeft && left_text != NULL) {
dialog_ex->callback(DialogExResultLeft, dialog_ex->context);
consumed = true;
} else if(event->input == InputOk && center_text != NULL) {
} else if(event->key == InputKeyOk && center_text != NULL) {
dialog_ex->callback(DialogExResultCenter, dialog_ex->context);
consumed = true;
} else if(event->input == InputRight && right_text != NULL) {
} else if(event->key == InputKeyRight && right_text != NULL) {
dialog_ex->callback(DialogExResultRight, dialog_ex->context);
consumed = true;
}

View File

@ -83,7 +83,7 @@ static bool popup_view_input_callback(InputEvent* event, void* context) {
bool consumed = false;
// Process key presses only
if(event->state && popup->callback) {
if(event->type == InputTypeShort && popup->callback) {
popup->callback(popup->context);
consumed = true;
}

View File

@ -74,17 +74,17 @@ static bool submenu_view_input_callback(InputEvent* event, void* context) {
furi_assert(submenu);
bool consumed = false;
if(event->state) {
switch(event->input) {
case InputUp:
if(event->type == InputTypeShort) {
switch(event->key) {
case InputKeyUp:
consumed = true;
submenu_process_up(submenu);
break;
case InputDown:
case InputKeyDown:
consumed = true;
submenu_process_down(submenu);
break;
case InputOk:
case InputKeyOk:
consumed = true;
submenu_process_ok(submenu);
break;

View File

@ -289,25 +289,25 @@ static bool text_input_view_input_callback(InputEvent* event, void* context) {
furi_assert(text_input);
bool consumed = false;
if(event->state) {
switch(event->input) {
case InputUp:
if(event->type == InputTypeShort) {
switch(event->key) {
case InputKeyUp:
text_input_handle_up(text_input);
consumed = true;
break;
case InputDown:
case InputKeyDown:
text_input_handle_down(text_input);
consumed = true;
break;
case InputLeft:
case InputKeyLeft:
text_input_handle_left(text_input);
consumed = true;
break;
case InputRight:
case InputKeyRight:
text_input_handle_right(text_input);
consumed = true;
break;
case InputOk:
case InputKeyOk:
text_input_handle_ok(text_input);
consumed = true;
break;

View File

@ -89,11 +89,11 @@ void view_dispatcher_input_callback(InputEvent* event, void* context) {
if(view_dispatcher->current_view) {
is_consumed = view_input(view_dispatcher->current_view, event);
}
if(!is_consumed && event->state) {
if(!is_consumed && event->type == InputTypeShort) {
uint32_t view_id = VIEW_IGNORE;
if(event->input == InputBack) {
if(event->key == InputKeyBack) {
view_id = view_previous(view_dispatcher->current_view);
} else if(event->input == InputOk) {
} else if(event->key == InputKeyOk) {
view_id = view_next(view_dispatcher->current_view);
}
view_dispatcher_switch_to_view(view_dispatcher, view_id);

View File

@ -28,10 +28,11 @@ void AppiButton::run() {
AppiButtonEvent event;
while(1) {
if(get_event(&event, 20)) {
if(get_event(&event, 1024 / 8)) {
if(event.type == AppiButtonEvent::EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyBack) {
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
api_hal_timebase_insomnia_exit();
@ -39,11 +40,13 @@ void AppiButton::run() {
osThreadExit();
}
if(event.value.input.state && event.value.input.input == InputLeft) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyLeft) {
decrease_mode();
}
if(event.value.input.state && event.value.input.input == InputRight) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyRight) {
increase_mode();
}
}

View File

@ -29,11 +29,11 @@ void AppiButtonModeCyfralEmulate::event(AppiButtonEvent* event, AppiButtonState*
app->blink_green();
} else if(event->type == AppiButtonEvent::EventTypeKey) {
if(event->value.input.state && event->value.input.input == InputUp) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
app->decrease_cyfral_address();
}
if(event->value.input.state && event->value.input.input == InputDown) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
app->increase_cyfral_address();
}
}

View File

@ -59,11 +59,11 @@ void AppiButtonModeCyfralRead::event(AppiButtonEvent* event, AppiButtonState* st
}
}
} else if(event->type == AppiButtonEvent::EventTypeKey) {
if(event->value.input.state && event->value.input.input == InputUp) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
app->decrease_cyfral_address();
}
if(event->value.input.state && event->value.input.input == InputDown) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
app->increase_cyfral_address();
}
}

View File

@ -48,11 +48,11 @@ void AppiButtonModeDallasEmulate::event(AppiButtonEvent* event, AppiButtonState*
app->blink_green();
}
} else if(event->type == AppiButtonEvent::EventTypeKey) {
if(event->value.input.state && event->value.input.input == InputUp) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
app->decrease_dallas_address();
}
if(event->value.input.state && event->value.input.input == InputDown) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
app->increase_dallas_address();
}
}

View File

@ -46,11 +46,11 @@ void AppiButtonModeDallasRead::event(AppiButtonEvent* event, AppiButtonState* st
}
}
} else if(event->type == AppiButtonEvent::EventTypeKey) {
if(event->value.input.state && event->value.input.input == InputUp) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
app->decrease_dallas_address();
}
if(event->value.input.state && event->value.input.input == InputDown) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
app->increase_dallas_address();
}
}

View File

@ -39,11 +39,11 @@ void AppiButtonModeDallasWrite::event(AppiButtonEvent* event, AppiButtonState* s
}
} else if(event->type == AppiButtonEvent::EventTypeKey) {
if(event->value.input.state && event->value.input.input == InputUp) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
app->decrease_dallas_address();
}
if(event->value.input.state && event->value.input.input == InputDown) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
app->increase_dallas_address();
}
}

View File

@ -1,131 +1,72 @@
#include <input/input.h>
#include <stdio.h>
#include <furi.h>
#include "input_i.h"
#ifdef APP_NFC
void nfc_isr(void);
#endif
#define GPIO_Read(input_pin) \
(HAL_GPIO_ReadPin((GPIO_TypeDef*)input_pin.pin->port, input_pin.pin->pin) ^ \
input_pin.pin->inverted)
#ifdef BUILD_CC1101
void cc1101_isr();
#endif
static Input* input = NULL;
static volatile bool initialized = false;
static ValueManager input_state_record;
static PubSub input_events_record;
static Event event;
static InputState input_state = {
false,
};
void input_press_timer_callback(void* arg) {
InputPin* input_pin = arg;
InputEvent event;
event.key = input_pin->key;
event.type = InputTypeLong;
notify_pubsub(&input->event_pubsub, &event);
}
static void exti_input_callback(void* _pin, void* _ctx);
void input_isr(void* _pin, void* _ctx) {
osThreadFlagsSet(input->thread, INPUT_THREAD_FLAG_ISR);
}
void input_task(void* p) {
uint32_t state_bits = 0;
uint8_t debounce_counters[INPUT_COUNT];
void input_task() {
input = furi_alloc(sizeof(Input));
input->thread = osThreadGetId();
init_pubsub(&input->event_pubsub);
furi_record_create("input_events", &input->event_pubsub);
if(!init_managed(&input_state_record, &input_state, sizeof(input_state))) {
printf("[input_task] cannot initialize ValueManager for input_state\r\n");
furiac_exit(NULL);
}
if(!init_pubsub(&input_events_record)) {
printf("[input_task] cannot initialize PubSub for input_events\r\n");
furiac_exit(NULL);
}
if(!init_event(&event)) {
printf("[input_task] cannot initialize Event\r\n");
furiac_exit(NULL);
const size_t pin_count = input_pins_count;
input->pin_states = furi_alloc(pin_count * sizeof(InputPinState));
api_interrupt_add(input_isr, InterruptTypeExternalInterrupt, NULL);
for(size_t i = 0; i < pin_count; i++) {
input->pin_states[i].pin = &input_pins[i];
input->pin_states[i].state = GPIO_Read(input->pin_states[i]);
input->pin_states[i].debounce = INPUT_DEBOUNCE_TICKS_HALF;
input->pin_states[i].press_timer =
osTimerNew(input_press_timer_callback, osTimerOnce, &input->pin_states[i], NULL);
}
furi_record_create("input_state", &input_state_record);
furi_record_create("input_events", &input_events_record);
api_interrupt_add(exti_input_callback, InterruptTypeExternalInterrupt, NULL);
// we ready to work
initialized = true;
// Force state update
for(uint32_t i = 0; i < INPUT_COUNT; i++) {
debounce_counters[i] = DEBOUNCE_TICKS / 2;
}
for(;;) {
bool changed = false;
for(uint32_t i = 0; i < INPUT_COUNT; i++) {
bool input_state = false;
// dirty hack, f3 has no CHARGING pin
// TODO rewrite this
if(i < GPIO_INPUT_PINS_COUNT) {
input_state = gpio_read(&input_gpio[i]) ^ input_invert[i];
}
if(input_state) {
if(debounce_counters[i] < DEBOUNCE_TICKS) {
debounce_counters[i] += 1;
changed = true;
}
} else {
if(debounce_counters[i] > 0) {
debounce_counters[i] -= 1;
changed = true;
while(1) {
bool is_changing = false;
for(size_t i = 0; i < pin_count; i++) {
bool state = GPIO_Read(input->pin_states[i]);
if(input->pin_states[i].debounce > 0 &&
input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) {
is_changing = true;
input->pin_states[i].debounce += (state ? 1 : -1);
} else if(input->pin_states[i].state != state) {
input->pin_states[i].state = state;
// Common state info
InputEvent event;
event.type = input->pin_states[i].state ? InputTypePress : InputTypeRelease;
event.key = input->pin_states[i].pin->key;
// Send Press/Release event
notify_pubsub(&input->event_pubsub, &event);
// Short/Long press logic
if(state) {
osTimerStart(input->pin_states[i].press_timer, INPUT_LONG_PRESS_TICKS);
} else if(osTimerStop(input->pin_states[i].press_timer) == osOK) {
event.type = InputTypeShort;
notify_pubsub(&input->event_pubsub, &event);
}
}
}
if(!changed) {
uint32_t new_state_bits = 0;
for(uint32_t i = 0; i < INPUT_COUNT; i++) {
if(debounce_counters[i] == DEBOUNCE_TICKS) {
new_state_bits |= (1 << i);
}
}
uint32_t changed_bits = new_state_bits ^ state_bits;
if(changed_bits != 0) {
// printf("[input] %02x -> %02x\n", state_bits, new_state_bits);
InputState new_state = _BITS2STATE(new_state_bits);
write_managed(&input_state_record, &new_state, sizeof(new_state), osWaitForever);
state_bits = new_state_bits;
for(uint32_t i = 0; i < INPUT_COUNT; i++) {
if((changed_bits & (1 << i)) != 0) {
bool state = (new_state_bits & (1 << i)) != 0;
InputEvent event = {i, state};
notify_pubsub(&input_events_record, &event);
}
}
}
// Sleep: wait for event
wait_event(&event);
} else {
if(is_changing) {
osDelay(1);
} else {
osThreadFlagsWait(INPUT_THREAD_FLAG_ISR, osFlagsWaitAny, osWaitForever);
}
}
}
static void exti_input_callback(void* _pin, void* _ctx) {
// interrupt manager get us pin constant, so...
uint32_t pin = (uint32_t)_pin;
#ifdef APP_NFC
if(pin == NFC_IRQ_Pin) {
nfc_isr();
return;
}
#endif
#ifdef BUILD_CC1101
if(pin == CC1101_G0_Pin) {
cc1101_isr();
return;
}
#endif
if(!initialized) return;
signal_event(&event);
}

View File

@ -1,40 +1,19 @@
#ifndef __INPUT_H
#define __INPUT_H
#pragma once
#include <stdbool.h>
#define INPUT_COUNT 7
#include <api-hal-resources.h>
/* Input Types
* Some of them are physical events and some logical
*/
typedef enum {
InputUp = 0,
InputDown,
InputRight,
InputLeft,
InputOk,
InputBack,
InputCharging,
} Input;
InputTypePress, /* Press event, emitted after debounce */
InputTypeRelease, /* Release event, emitted after debounce */
InputTypeShort, /* Short event, emitted after InputTypeRelease done withing INPUT_LONG_PRESS interval */
InputTypeLong, /* Long event, emmited after INPUT_LONG_PRESS interval, asynchronouse to InputTypeRelease */
} InputType;
/* Input Event, dispatches with PubSub */
typedef struct {
Input input;
bool state;
InputKey key;
InputType type;
} InputEvent;
typedef struct {
bool up : 1;
bool down : 1;
bool right : 1;
bool left : 1;
bool ok : 1;
bool back : 1;
bool charging : 1;
} __attribute__((packed)) InputState;
#define _BITS2STATE(bits) \
{ \
.up = (((bits)&0x01) != 0), .down = (((bits)&0x02) != 0), .right = (((bits)&0x04) != 0), \
.left = (((bits)&0x08) != 0), .ok = (((bits)&0x10) != 0), .back = (((bits)&0x20) != 0), \
.charging = (((bits)&0x40) != 0) \
}
#endif /* __INPUT_H */

View File

@ -0,0 +1,34 @@
#pragma once
#include "input.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <furi.h>
#define INPUT_DEBOUNCE_TICKS_HALF (INPUT_DEBOUNCE_TICKS / 2)
#define INPUT_LONG_PRESS_TICKS 2048
#define INPUT_THREAD_FLAG_ISR 0x00000001
/* Input pin state */
typedef struct {
const InputPin* pin;
// State
volatile bool state;
volatile uint8_t debounce;
volatile osTimerId_t press_timer;
} InputPinState;
/* Input state */
typedef struct {
osThreadId_t thread;
PubSub event_pubsub;
InputPinState* pin_states;
} Input;
/* Input press timer callback */
void input_press_timer_callback(void* arg);
/* Input interrupt handler */
void input_isr(void* _pin, void* _ctx);

View File

@ -78,15 +78,15 @@ void render_carrier(Canvas* canvas, State* state) {
}
void input_carrier(AppEvent* event, State* state) {
if(event->value.input.input == InputOk) {
if(event->value.input.state) {
if(event->value.input.key == InputKeyOk) {
if(event->value.input.type == InputTypePress) {
irda_pwm_set(duty_cycles[state->carrier_duty_cycle_id], state->carrier_freq);
} else {
} else if(event->value.input.type == InputTypeRelease) {
irda_pwm_stop();
}
}
if(event->value.input.state && event->value.input.input == InputUp) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
if(state->carrier_freq < 45000) {
state->carrier_freq += 1000;
} else {
@ -94,7 +94,7 @@ void input_carrier(AppEvent* event, State* state) {
}
}
if(event->value.input.state && event->value.input.input == InputDown) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]);
if(state->carrier_duty_cycle_id < (duty_cycles_count - 1)) {
state->carrier_duty_cycle_id++;
@ -137,8 +137,8 @@ void render_packet(Canvas* canvas, State* state) {
}
void input_packet(AppEvent* event, State* state) {
if(event->value.input.input == InputOk) {
if(event->value.input.state) {
if(event->value.input.key == InputKeyOk) {
if(event->value.input.type == InputTypeShort) {
switch(state->packets[state->packet_id].protocol) {
case IRDA_NEC:
ir_nec_send(
@ -156,13 +156,13 @@ void input_packet(AppEvent* event, State* state) {
}
}
if(event->value.input.state && event->value.input.input == InputDown) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyDown) {
if(state->packet_id < (IRDA_PACKET_COUNT - 1)) {
state->packet_id++;
};
}
if(event->value.input.state && event->value.input.input == InputUp) {
if(event->value.input.type == InputTypeShort && event->value.input.key == InputKeyUp) {
if(state->packet_id > 0) {
state->packet_id--;
};
@ -299,7 +299,8 @@ void irda(void* p) {
if(event_status == osOK) {
if(event.type == EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyBack) {
// remove all view_ports create by app
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
@ -311,13 +312,15 @@ void irda(void* p) {
furiac_exit(NULL);
}
if(event.value.input.state && event.value.input.input == InputLeft) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyLeft) {
if(state->mode_id > 0) {
state->mode_id--;
}
}
if(event.value.input.state && event.value.input.input == InputRight) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyRight) {
if(state->mode_id < (mode_count - 1)) {
state->mode_id++;
}

View File

@ -161,7 +161,7 @@ static void extract_data(uint8_t* buf, uint8_t* customer, uint32_t* em_data) {
}
void lf_rfid_workaround(void* p) {
osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL);
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
// create pin
GpioPin pull_pin = {.pin = RFID_PULL_Pin, .port = RFID_PULL_GPIO_Port};
@ -222,7 +222,7 @@ void lf_rfid_workaround(void* p) {
}
while(1) {
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 100);
osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, 1024 / 8);
if(event.type == EventTypeRx && event_status == osOK) {
uint32_t dt = (event.value.rx.dwt_value - prev_dwt) / (SystemCoreClock / 1000000.0f);
@ -285,7 +285,8 @@ void lf_rfid_workaround(void* p) {
if(event_status == osOK) {
if(event.type == EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyBack) {
hal_pwmn_stop(&TIM_C, TIM_CHANNEL_1); // TODO: move to furiac_onexit
gpio_init(pull_pin_record, GpioModeInput);
gpio_init((GpioPin*)&ibutton_gpio, GpioModeInput);
@ -295,23 +296,28 @@ void lf_rfid_workaround(void* p) {
furiac_exit(NULL);
}
if(event.value.input.state && event.value.input.input == InputUp) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyUp) {
state->dirty = true;
state->freq_khz += 10;
}
if(event.value.input.state && event.value.input.input == InputDown) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyDown) {
state->dirty = true;
state->freq_khz -= 10;
}
if(event.value.input.state && event.value.input.input == InputLeft) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyLeft) {
}
if(event.value.input.state && event.value.input.input == InputRight) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyRight) {
}
if(event.value.input.state && event.value.input.input == InputOk) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyOk) {
state->dirty = true;
state->on = !state->on;
}

View File

@ -55,19 +55,19 @@ void menu_event_input_callback(InputEvent* input_event, void* context) {
MenuEvent* menu_event = context;
MenuMessage message;
if(!input_event->state) return;
if(input_event->type != InputTypeShort) return;
if(input_event->input == InputUp) {
if(input_event->key == InputKeyUp) {
message.type = MenuMessageTypeUp;
} else if(input_event->input == InputDown) {
} else if(input_event->key == InputKeyDown) {
message.type = MenuMessageTypeDown;
} else if(input_event->input == InputRight) {
} else if(input_event->key == InputKeyRight) {
message.type = MenuMessageTypeRight;
} else if(input_event->input == InputLeft) {
} else if(input_event->key == InputKeyLeft) {
message.type = MenuMessageTypeLeft;
} else if(input_event->input == InputOk) {
} else if(input_event->key == InputKeyOk) {
message.type = MenuMessageTypeOk;
} else if(input_event->input == InputBack) {
} else if(input_event->key == InputKeyBack) {
message.type = MenuMessageTypeBack;
} else {
message.type = MenuMessageTypeUnknown;

View File

@ -357,7 +357,7 @@ void music_player_thread(void* p) {
}
void music_player(void* p) {
osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(MusicDemoEvent), NULL);
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(MusicDemoEvent), NULL);
State _state;
_state.note_record = NULL;
@ -384,7 +384,7 @@ void music_player(void* p) {
// open input record
PubSub* input_events_record = furi_record_open("input_events");
// prepare "do nothing" event
InputEvent input_event = {InputRight, true};
InputEvent input_event = {InputKeyRight, true};
// start player thread
// TODO change to fuirac_start
@ -406,24 +406,29 @@ void music_player(void* p) {
if(event_status == osOK) {
if(event.type == EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyBack) {
}
if(event.value.input.state && event.value.input.input == InputUp) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyUp) {
if(state->volume_id < state->volume_id_max - 1) state->volume_id++;
}
if(event.value.input.state && event.value.input.input == InputDown) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyDown) {
if(state->volume_id > 0) state->volume_id--;
}
if(event.value.input.state && event.value.input.input == InputLeft) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyLeft) {
}
if(event.value.input.state && event.value.input.input == InputRight) {
if(event.value.input.type == InputTypePress &&
event.value.input.key == InputKeyRight) {
}
if(event.value.input.input == InputOk) {
if(event.value.input.key == InputKeyOk) {
}
} else if(event.type == EventTypeNote) {

View File

@ -57,8 +57,8 @@ public:
void render(Canvas* canvas);
template <class T> void set_text(std::initializer_list<T> list);
template <class T> void set_error(std::initializer_list<T> list);
void wait_for_button(Input input_button);
bool ask(Input input_button_cancel, Input input_button_ok);
void wait_for_button(InputKey input_button);
bool ask(InputKey input_button_cancel, InputKey input_button_ok);
void blink_red();
void set_red();
void blink_green();
@ -145,7 +145,7 @@ void SdTest::run() {
"",
"press BACK to exit",
});
wait_for_button(InputBack);
wait_for_button(InputKeyBack);
exit();
}
@ -184,9 +184,9 @@ void SdTest::show_warning() {
"",
"press UP DOWN OK to continue"});
wait_for_button(InputUp);
wait_for_button(InputDown);
wait_for_button(InputOk);
wait_for_button(InputKeyUp);
wait_for_button(InputKeyDown);
wait_for_button(InputKeyOk);
}
// get info about sd card, label, sn
@ -216,7 +216,7 @@ void SdTest::get_sd_card_info() {
blink_green();
wait_for_button(InputOk);
wait_for_button(InputKeyOk);
}
// prepare benchmark data (allocate data in ram)
@ -296,7 +296,7 @@ void SdTest::write_benchmark() {
blink_green();
wait_for_button(InputOk);
wait_for_button(InputKeyOk);
}
uint32_t SdTest::write_benchmark_internal(const uint32_t size, const uint32_t count, bool silent) {
@ -436,7 +436,7 @@ void SdTest::read_benchmark() {
blink_green();
wait_for_button(InputOk);
wait_for_button(InputKeyOk);
}
uint32_t SdTest::read_benchmark_internal(
@ -590,7 +590,7 @@ void SdTest::hash_benchmark() {
blink_green();
wait_for_button(InputOk);
wait_for_button(InputKeyOk);
}
void SdTest::cli_read_benchmark(string_t args, void* _ctx) {
@ -786,18 +786,18 @@ void SdTest::cli_write_benchmark(string_t args, void* _ctx) {
}
// wait for button press
void SdTest::wait_for_button(Input input_button) {
void SdTest::wait_for_button(InputKey input_button) {
SdTestEvent event;
osMessageQueueReset(event_queue);
while(1) {
osStatus_t result = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
if(result == osOK && event.type == SdTestEvent::EventTypeKey) {
if(event.value.input.state == true) {
if(event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort) {
if(event.value.input.key == InputKeyBack) {
exit();
} else {
if(event.value.input.input == input_button) {
if(event.value.input.key == input_button) {
blink_green();
break;
} else {
@ -811,7 +811,7 @@ void SdTest::wait_for_button(Input input_button) {
}
// ask user to proceed or cancel
bool SdTest::ask(Input input_button_cancel, Input input_button_ok) {
bool SdTest::ask(InputKey input_button_cancel, InputKey input_button_ok) {
bool return_result;
SdTestEvent event;
osMessageQueueReset(event_queue);
@ -819,15 +819,15 @@ bool SdTest::ask(Input input_button_cancel, Input input_button_ok) {
osStatus_t result = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
if(result == osOK && event.type == SdTestEvent::EventTypeKey) {
if(event.value.input.state == true) {
if(event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort) {
if(event.value.input.key == InputKeyBack) {
exit();
} else {
if(event.value.input.input == input_button_ok) {
if(event.value.input.key == input_button_ok) {
blink_green();
return_result = true;
break;
} else if(event.value.input.input == input_button_cancel) {
} else if(event.value.input.key == input_button_cancel) {
blink_green();
return_result = false;
break;
@ -865,7 +865,7 @@ void SdTest::blink_green() {
template <class T> void SdTest::set_error(std::initializer_list<T> list) {
set_text(list);
set_red();
wait_for_button(InputBack);
wait_for_button(InputKeyBack);
exit();
}

View File

@ -105,7 +105,7 @@ SdApp* sd_app_alloc() {
furiac_exit(NULL);
}
sd_app->event_queue = osMessageQueueNew(1, sizeof(InputEvent), NULL);
sd_app->event_queue = osMessageQueueNew(8, sizeof(InputEvent), NULL);
// init view_port
sd_app->view_port = view_port_alloc();
@ -127,7 +127,7 @@ SdApp* sd_app_alloc() {
return sd_app;
}
bool app_sd_ask(SdApp* sd_app, Input input_true, Input input_false) {
bool app_sd_ask(SdApp* sd_app, InputKey input_true, InputKey input_false) {
bool result;
InputEvent event;
@ -136,11 +136,11 @@ bool app_sd_ask(SdApp* sd_app, Input input_true, Input input_false) {
osMessageQueueGet(sd_app->event_queue, &event, NULL, osWaitForever);
if(event_status == osOK) {
if(event.state && event.input == input_true) {
if(event.type == InputTypeShort && event.key == input_true) {
result = true;
break;
}
if(event.state && event.input == InputBack) {
if(event.type == InputTypeShort && event.key == InputKeyBack) {
result = false;
break;
}
@ -254,7 +254,7 @@ void app_sd_info_callback(void* context) {
str_buffer[5]);
}
app_sd_ask(sd_app, InputBack, InputBack);
app_sd_ask(sd_app, InputKeyBack, InputKeyBack);
sd_set_lines(sd_app, 0);
view_port_enabled_set(sd_app->view_port, false);
@ -294,7 +294,7 @@ void app_sd_format_callback(void* context) {
view_port_enabled_set(sd_app->view_port, true);
// wait for input
if(!app_sd_ask(sd_app, InputUp, InputBack)) {
if(!app_sd_ask(sd_app, InputKeyUp, InputKeyBack)) {
view_port_enabled_set(sd_app->view_port, false);
return;
}
@ -313,7 +313,7 @@ void app_sd_format_callback(void* context) {
}
// wait for BACK
app_sd_ask(sd_app, InputBack, InputBack);
app_sd_ask(sd_app, InputKeyBack, InputKeyBack);
view_port_enabled_set(sd_app->view_port, false);
}
@ -357,7 +357,7 @@ void app_sd_eject_callback(void* context) {
sd_set_lines(sd_app, 1, "SD card can be pulled out");
// wait for BACK
app_sd_ask(sd_app, InputBack, InputBack);
app_sd_ask(sd_app, InputKeyBack, InputKeyBack);
view_port_enabled_set(sd_app->view_port, false);
}

View File

@ -105,7 +105,8 @@ void AppSdNFC::run() {
if(get_event(&event, 1000)) {
if(event.type == AppSdNFCEvent::EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort &&
event.value.input.key == InputKeyBack) {
exit();
}
}

View File

@ -38,7 +38,7 @@ static void input_callback(InputEvent* input_event, void* ctx) {
}
void template_app(void* p) {
osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(Event), NULL);
osMessageQueueId_t event_queue = osMessageQueueNew(8, sizeof(Event), NULL);
State _state;
/* init state here */
@ -72,22 +72,22 @@ void template_app(void* p) {
if(event_status == osOK) {
if(event.type == EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyBack) {
}
if(event.value.input.state && event.value.input.input == InputUp) {
if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyUp) {
}
if(event.value.input.state && event.value.input.input == InputDown) {
if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyDown) {
}
if(event.value.input.state && event.value.input.input == InputLeft) {
if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyLeft) {
}
if(event.value.input.state && event.value.input.input == InputRight) {
if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyRight) {
}
if(event.value.input.input == InputOk) {
if(event.value.input.key == InputKeyOk) {
}
}
} else {

View File

@ -1,11 +0,0 @@
#include "main.h"
#include <furi.h>
const bool input_invert[GPIO_INPUT_PINS_COUNT] = {
true, // {BUTTON_UP_GPIO_Port, BUTTON_UP_Pin},
true, // {BUTTON_DOWN_GPIO_Port, BUTTON_DOWN_Pin},
true, // {BUTTON_RIGHT_GPIO_Port, BUTTON_RIGHT_Pin},
true, // {BUTTON_LEFT_GPIO_Port, BUTTON_LEFT_Pin},
false, // {BUTTON_OK_GPIO_Port, BUTTON_OK_Pin},
true, // {BUTTON_BACK_GPIO_Port, BUTTON_BACK_Pin},
};

View File

@ -1,15 +1,30 @@
#include <api-hal-resources.h>
#include "main.h"
#include <furi.h>
const GpioPin input_gpio[GPIO_INPUT_PINS_COUNT] = {
{BUTTON_UP_GPIO_Port, BUTTON_UP_Pin},
{BUTTON_DOWN_GPIO_Port, BUTTON_DOWN_Pin},
{BUTTON_RIGHT_GPIO_Port, BUTTON_RIGHT_Pin},
{BUTTON_LEFT_GPIO_Port, BUTTON_LEFT_Pin},
{BUTTON_OK_GPIO_Port, BUTTON_OK_Pin},
{BUTTON_BACK_GPIO_Port, BUTTON_BACK_Pin},
const InputPin input_pins[] = {
{.port = BUTTON_UP_GPIO_Port, .pin = BUTTON_UP_Pin, .key = InputKeyUp, .inverted = true},
{.port = BUTTON_DOWN_GPIO_Port,
.pin = BUTTON_DOWN_Pin,
.key = InputKeyDown,
.inverted = true},
{.port = BUTTON_RIGHT_GPIO_Port,
.pin = BUTTON_RIGHT_Pin,
.key = InputKeyRight,
.inverted = true},
{.port = BUTTON_LEFT_GPIO_Port,
.pin = BUTTON_LEFT_Pin,
.key = InputKeyLeft,
.inverted = true},
{.port = BUTTON_OK_GPIO_Port, .pin = BUTTON_OK_Pin, .key = InputKeyOk, .inverted = false},
{.port = BUTTON_BACK_GPIO_Port,
.pin = BUTTON_BACK_Pin,
.key = InputKeyBack,
.inverted = true},
};
const size_t input_pins_count = sizeof(input_pins) / sizeof(InputPin);
const GpioPin led_gpio[3] = {
{LED_RED_GPIO_Port, LED_RED_Pin},
{LED_GREEN_GPIO_Port, LED_GREEN_Pin},

View File

@ -2,11 +2,28 @@
#include "main.h"
#include <furi.h>
#define DEBOUNCE_TICKS 10
#define GPIO_INPUT_PINS_COUNT 6
/* Input Related Constants */
#define INPUT_DEBOUNCE_TICKS 20
extern const GpioPin input_gpio[GPIO_INPUT_PINS_COUNT];
extern const bool input_invert[GPIO_INPUT_PINS_COUNT];
/* Input Keys */
typedef enum {
InputKeyUp,
InputKeyDown,
InputKeyRight,
InputKeyLeft,
InputKeyOk,
InputKeyBack,
} InputKey;
typedef struct {
const GPIO_TypeDef* port;
const uint16_t pin;
const InputKey key;
const bool inverted;
} InputPin;
extern const InputPin input_pins[];
extern const size_t input_pins_count;
extern const GpioPin led_gpio[3];
extern const GpioPin backlight_gpio;

View File

@ -1,14 +1,18 @@
#include "platform.h"
#include <assert.h>
#include <main.h>
#include <furi.h>
#include <api-hal-spi.h>
static osThreadAttr_t platform_irq_thread_attr;
static volatile osThreadId_t platform_irq_thread_id = NULL;
static volatile PlatformIrqCallback platform_irq_callback = NULL;
void nfc_isr() {
if(platform_irq_callback && platformGpioIsHigh( ST25R_INT_PORT, ST25R_INT_PIN )) {
void nfc_isr(void* _pin, void* _ctx) {
uint32_t pin = (uint32_t)_pin;
if(pin == NFC_IRQ_Pin
&& platform_irq_callback
&& platformGpioIsHigh(ST25R_INT_PORT, ST25R_INT_PIN)) {
osThreadFlagsSet(platform_irq_thread_id, 0x1);
}
}
@ -28,6 +32,7 @@ void platformSetIrqCallback(PlatformIrqCallback callback) {
platform_irq_thread_attr.stack_size = 512;
platform_irq_thread_attr.priority = osPriorityISR;
platform_irq_thread_id = osThreadNew(platformIrqWorker, NULL, &platform_irq_thread_attr);
api_interrupt_add(nfc_isr, InterruptTypeExternalInterrupt, NULL);
}
HAL_StatusTypeDef platformSpiTxRx(const uint8_t *txBuf, uint8_t *rxBuf, uint16_t len) {

View File

@ -65,12 +65,12 @@ void AppExample::run() {
if(get_event(&event, 1000)) {
if(event.type == AppExampleEvent::EventTypeKey) {
// press events
if(event.value.input.state && event.value.input.input == InputBack) {
if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyBack) {
printf("bye!\n");
exit();
}
if(event.value.input.state && event.value.input.input == InputUp) {
if(event.value.input.type == InputTypeShort && event.value.input.key == InputKeyUp) {
// to read or write state you need to execute
// acquire modify release state
acquire_state();