diff --git a/src/button.c b/src/button.c index 9f8c59a..75be7c6 100644 --- a/src/button.c +++ b/src/button.c @@ -35,6 +35,13 @@ extern void execute_tasks(void); int (*button_pressed_cb)(uint8_t) = NULL; static bool req_button_pending = false; +#ifndef ENABLE_EMULATION +static bool async_button_wait = false; +static bool async_button_pressed = false; +static uint32_t async_button_started = 0; +static uint32_t async_button_timeout = 0; +static uint32_t async_button_led_mode = MODE_MOUNTED; +#endif bool is_req_button_pending(void) { return req_button_pending; @@ -101,17 +108,16 @@ static uint32_t button_hold_started = 0; static uint32_t button_last_poll = 0; volatile uint32_t button_pressed_duration = 0; -int button_wait(void) { +void button_wait_start(void) { /* Disabled by default. As LED may not be properly configured, it will not be possible to indicate button press unless it is commissioned. */ - uint32_t button_timeout = 0; - if (phy_data.up_btn_present) { - button_timeout = phy_data.up_btn * 1000; - } + uint32_t button_timeout = phy_data.up_btn_present ? phy_data.up_btn * 1000 : 0; if (button_timeout == 0 && !force_button_wait) { signal_emit(SIGNAL_USER_PRESENCE_COMPLETED); - return 0; + uint32_t flag = EV_BUTTON_PRESSED; + queue_try_add(&usb_to_card_q, &flag); + return; } if (button_timeout == 0) { button_timeout = 30000; @@ -120,55 +126,61 @@ int button_wait(void) { .timeout = button_timeout / 1000, }; signal_emit_param(SIGNAL_USER_PRESENCE_REQUEST, &data); - uint32_t start_button = board_millis(); - const uint32_t button_poll_interval_ms = 2; - uint32_t next_button_poll_ms = start_button; - bool button_pressed = picok_board_button_read(); - bool timeout = false; cancel_button = false; - uint32_t led_mode = led_get_mode(); - led_set_mode(MODE_BUTTON); + async_button_wait = true; + async_button_pressed = picok_board_button_read(); + async_button_started = board_millis(); + async_button_timeout = button_timeout; + async_button_led_mode = led_get_mode(); req_button_pending = true; - while (button_pressed == false && cancel_button == false) { - execute_tasks(); - uint32_t now = board_millis(); - if (now >= next_button_poll_ms) { - button_pressed = picok_board_button_read(); - next_button_poll_ms = now + button_poll_interval_ms; - } - //sleep_ms(10); - if (start_button + button_timeout < now) { /* timeout */ - timeout = true; - break; - } + led_set_mode(MODE_BUTTON); +} + +void button_wait_poll(void) { + if (!async_button_wait) { + return; } - if (!timeout) { - while (button_pressed == true && cancel_button == false) { - execute_tasks(); - uint32_t now = board_millis(); - if (now >= next_button_poll_ms) { - button_pressed = picok_board_button_read(); - next_button_poll_ms = now + button_poll_interval_ms; - } - //sleep_ms(10); - if (start_button + 15000 < now) { /* timeout */ - timeout = true; - break; - } - } + bool pressed = picok_board_button_read(); + uint32_t now = board_millis(); + if (!async_button_pressed && pressed) { + async_button_pressed = true; } - led_set_mode(led_mode); + button_event_t result = BUTTON_EV_NONE; + if (cancel_button) { + result = BUTTON_EV_CANCELLED; + } + else if (async_button_started + async_button_timeout < now || (async_button_pressed && async_button_started + 15000 < now)) { + result = BUTTON_EV_TIMEOUT; + } + else if (async_button_pressed && !pressed) { + result = BUTTON_EV_PRESSED; + } + if (result == BUTTON_EV_NONE) { + return; + } + async_button_wait = false; req_button_pending = false; - if (timeout) { + led_set_mode(async_button_led_mode); + uint32_t flag = 0; + if (result == BUTTON_EV_PRESSED) { + flag = EV_BUTTON_PRESSED; + } + else if (result == BUTTON_EV_TIMEOUT) { + flag = EV_BUTTON_TIMEOUT; + } + else if (result == BUTTON_EV_CANCELLED) { + flag = EV_BUTTON_CANCELLED; + } + queue_try_add(&usb_to_card_q, &flag); + if (result == BUTTON_EV_PRESSED) { + signal_emit(SIGNAL_USER_PRESENCE_COMPLETED); + } + else if (result == BUTTON_EV_TIMEOUT) { signal_emit(SIGNAL_USER_PRESENCE_TIMEOUT); - return 1; } - else if (cancel_button) { + else { signal_emit(SIGNAL_USER_PRESENCE_CANCELLED); - return 2; } - signal_emit(SIGNAL_USER_PRESENCE_COMPLETED); - return 0; } #endif @@ -176,7 +188,7 @@ int button_wait(void) { void button_task(void) { #ifndef ENABLE_EMULATION uint32_t now = board_millis(); - if (now > 1000 && now - button_last_poll >= 10 && !is_busy()) { // wait 1 second to boot up + if (now > 1000 && now - button_last_poll >= 10 && (async_button_wait || !is_busy())) { // wait 1 second to boot up #ifdef PICO_PLATFORM if (!multicore_lockout_start_timeout_us(1000)) { return; @@ -187,6 +199,10 @@ void button_task(void) { multicore_lockout_end_timeout_us(1000); #endif button_last_poll = now; + if (async_button_wait) { + button_wait_poll(); + return; + } if (current_button_state && !button_hold_state) { button_hold_started = now; button_pressed_duration = 0; diff --git a/src/button.h b/src/button.h index a9a9bf3..97959cb 100644 --- a/src/button.h +++ b/src/button.h @@ -25,11 +25,23 @@ #define BOOT_PIN GPIO_NUM_0 #endif -extern int button_wait(void); +typedef enum { + BUTTON_EV_PRESSED, + BUTTON_EV_TIMEOUT, + BUTTON_EV_CANCELLED, + BUTTON_EV_NONE, +} button_event_t; + +extern void button_wait_start(void); +extern void button_wait_poll(void); extern volatile uint32_t button_pressed_duration; extern void button_task(void); extern volatile bool cancel_button; extern bool touch_accept_button; extern volatile bool force_button_wait; +extern int (*button_pressed_cb)(uint8_t); + +extern bool is_req_button_pending(void); + #endif // BUTTON_H diff --git a/src/picokeys.h b/src/picokeys.h index 0337495..110335b 100644 --- a/src/picokeys.h +++ b/src/picokeys.h @@ -149,10 +149,6 @@ static inline uint32_t put_uint64_le(uint64_t n, uint8_t *b) { return 8; } -extern int (*button_pressed_cb)(uint8_t); - -extern bool is_req_button_pending(void); - #define PICOKEYS_OK 0 #define PICOKEYS_ERR_NO_MEMORY -1000 #define PICOKEYS_ERR_MEMORY_FATAL -1001 diff --git a/src/usb/hid/hid.c b/src/usb/hid/hid.c index 734e977..921eb3e 100644 --- a/src/usb/hid/hid.c +++ b/src/usb/hid/hid.c @@ -31,6 +31,7 @@ static portMUX_TYPE mutex = portMUX_INITIALIZER_UNLOCKED; #include "picokeys_version.h" #include "apdu.h" #include "usb.h" +#include "button.h" extern void init_fido(void); bool is_nk = false; @@ -331,7 +332,6 @@ static uint32_t allocate_cid(void) { } uint8_t thread_type = 0; //1 is APDU, 2 is CBOR -extern volatile bool cancel_button; extern int cbor_process(uint8_t last_cmd, const uint8_t *data, size_t len); static uint32_t last_keepalive_time = 0; diff --git a/src/usb/usb.c b/src/usb/usb.c index c61a74d..646fbe5 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -350,15 +350,7 @@ int card_status(uint8_t itf) { } #ifndef ENABLE_EMULATION else if (m == EV_PRESS_BUTTON) { - int ret = button_wait(); - uint32_t flag = EV_BUTTON_PRESSED; - if (ret == 1) { //timeout - flag = EV_BUTTON_TIMEOUT; - } - else if (ret == 2) { //cancelled - flag = EV_BUTTON_CANCELLED; - } - queue_try_add(&usb_to_card_q, &flag); + button_wait_start(); } #endif #ifdef PICO_PLATFORM