blk_box_tc/main/drivers/event_based_bottom_half.cpp

327 lines
9.5 KiB
C++

#include "bottom_half.h"
#include "inputs.hpp"
#include <array>
static uint8_t reverse_4_bits(uint8_t value) {
return static_cast<uint8_t>(((value & 0x1) << 3) |
((value & 0x2) << 1) |
((value & 0x4) >> 1) |
((value & 0x8) >> 3));
}
static KeypadKey map_input_keypad_key(InputKeypadKey key) {
switch (key) {
case InputKeypadKey::K0: return KeypadKey::k0;
case InputKeypadKey::K1: return KeypadKey::k1;
case InputKeypadKey::K2: return KeypadKey::k2;
case InputKeypadKey::K3: return KeypadKey::k3;
case InputKeypadKey::K4: return KeypadKey::k4;
case InputKeypadKey::K5: return KeypadKey::k5;
case InputKeypadKey::K6: return KeypadKey::k6;
case InputKeypadKey::K7: return KeypadKey::k7;
case InputKeypadKey::K8: return KeypadKey::k8;
case InputKeypadKey::K9: return KeypadKey::k9;
case InputKeypadKey::A: return KeypadKey::ka;
case InputKeypadKey::B: return KeypadKey::kb;
case InputKeypadKey::C: return KeypadKey::kc;
case InputKeypadKey::D: return KeypadKey::kd;
case InputKeypadKey::STAR: return KeypadKey::star;
case InputKeypadKey::POUND: return KeypadKey::pound;
default: return KeypadKey::k0;
}
}
static uint8_t get_fingerprint_touch_state() {
InputsState current = InputsController::get_input_state();
return static_cast<uint8_t>((current.touch_state >> 4) & 0x1);
}
static bool touch_state_initialized = false;
static bool touch_state_last = false;
static bool update_fingerprint_transition(bool want_pressed) {
bool current = get_fingerprint_touch_state();
if (!touch_state_initialized) {
touch_state_last = current;
touch_state_initialized = true;
return false;
}
bool transition = want_pressed ? (current && !touch_state_last)
: (!current && touch_state_last);
touch_state_last = current;
return transition;
}
static std::array<SwitchFlip, 8> pending_switch_flips;
static size_t pending_switch_flip_count = 0;
static void push_pending_switch_flip(const SwitchFlip& event) {
if (pending_switch_flip_count < pending_switch_flips.size()) {
pending_switch_flips[pending_switch_flip_count++] = event;
return;
}
// Drop the oldest event if the buffer is full.
for (size_t i = 1; i < pending_switch_flips.size(); ++i) {
pending_switch_flips[i - 1] = pending_switch_flips[i];
}
pending_switch_flips.back() = event;
}
static bool pop_pending_switch_flip(bool want_up, SwitchFlip& out) {
for (size_t i = 0; i < pending_switch_flip_count; ++i) {
if (pending_switch_flips[i].is_up() == want_up) {
out = pending_switch_flips[i];
for (size_t j = i + 1; j < pending_switch_flip_count; ++j) {
pending_switch_flips[j - 1] = pending_switch_flips[j];
}
--pending_switch_flip_count;
return true;
}
}
return false;
}
static void clear_pending_switch_flips() {
pending_switch_flip_count = 0;
}
static std::array<SwitchTouch, 8> pending_switch_touches;
static size_t pending_switch_touch_count = 0;
static void push_pending_switch_touch(const SwitchTouch& event) {
if (pending_switch_touch_count < pending_switch_touches.size()) {
pending_switch_touches[pending_switch_touch_count++] = event;
return;
}
for (size_t i = 1; i < pending_switch_touches.size(); ++i) {
pending_switch_touches[i - 1] = pending_switch_touches[i];
}
pending_switch_touches.back() = event;
}
static bool pop_pending_switch_touch(bool want_touched, SwitchTouch& out) {
for (size_t i = 0; i < pending_switch_touch_count; ++i) {
if (pending_switch_touches[i].is_touched() == want_touched) {
out = pending_switch_touches[i];
for (size_t j = i + 1; j < pending_switch_touch_count; ++j) {
pending_switch_touches[j - 1] = pending_switch_touches[j];
}
--pending_switch_touch_count;
return true;
}
}
return false;
}
static void clear_pending_switch_touches() {
pending_switch_touch_count = 0;
}
void init_bottom_half() {
init_expander();
clear_all_pressed_released();
}
void clear_all_pressed_released() {
InputsController::clear_all_events();
clear_pending_switch_flips();
clear_pending_switch_touches();
touch_state_initialized = false;
}
bool get_keypad_pressed(KeypadKey* kp) {
auto opt = InputsController::get_keypad_press();
if (!opt.has_value()) {
return false;
}
if (kp != nullptr) {
*kp = map_input_keypad_key(opt.value());
}
return true;
}
bool get_keypad_released(KeypadKey* kp) {
auto opt = InputsController::get_keypad_release();
if (!opt.has_value()) {
return false;
}
if (kp != nullptr) {
*kp = map_input_keypad_key(opt.value());
}
return true;
}
char char_of_keypad_key(KeypadKey kp) {
switch (kp) {
case KeypadKey::k1: return '1';
case KeypadKey::k2: return '2';
case KeypadKey::k3: return '3';
case KeypadKey::k4: return '4';
case KeypadKey::k5: return '5';
case KeypadKey::k6: return '6';
case KeypadKey::k7: return '7';
case KeypadKey::k8: return '8';
case KeypadKey::k9: return '9';
case KeypadKey::k0: return '0';
case KeypadKey::ka: return 'A';
case KeypadKey::kb: return 'B';
case KeypadKey::kc: return 'C';
case KeypadKey::kd: return 'D';
case KeypadKey::star: return '*';
case KeypadKey::pound: return '#';
default: return ' ';
}
}
static bool take_button(ButtonKey* button, std::optional<Button> opt) {
if (!opt.has_value()) {
return false;
}
if (button != nullptr) {
*button = static_cast<ButtonKey>(static_cast<uint8_t>(opt.value()));
}
return true;
}
bool get_button_pressed(ButtonKey* button) {
return take_button(button, InputsController::get_button_press());
}
bool get_button_released(ButtonKey* button) {
return take_button(button, InputsController::get_button_release());
}
uint8_t get_button_state() {
return reverse_4_bits(InputsController::button_state() & 0xF);
}
static bool take_switch_key(SwitchKey* switch_, const SwitchFlip& event) {
if (switch_ != nullptr) {
*switch_ = static_cast<SwitchKey>(static_cast<uint8_t>(event.get_switch()));
}
return true;
}
bool get_switch_flipped_up(SwitchKey* switch_) {
SwitchFlip event;
if (pop_pending_switch_flip(true, event)) {
return take_switch_key(switch_, event);
}
while (true) {
auto opt = InputsController::get_switch_flip();
if (!opt.has_value()) {
return false;
}
if (opt->is_up()) {
return take_switch_key(switch_, *opt);
}
push_pending_switch_flip(*opt);
}
}
bool get_switch_flipped_down(SwitchKey* switch_) {
SwitchFlip event;
if (pop_pending_switch_flip(false, event)) {
return take_switch_key(switch_, event);
}
while (true) {
auto opt = InputsController::get_switch_flip();
if (!opt.has_value()) {
return false;
}
if (!opt->is_up()) {
return take_switch_key(switch_, *opt);
}
push_pending_switch_flip(*opt);
}
}
bool get_switch_flipped(SwitchKey* switch_) {
if (pending_switch_flip_count > 0) {
SwitchFlip event = pending_switch_flips[0];
for (size_t i = 1; i < pending_switch_flip_count; ++i) {
pending_switch_flips[i - 1] = pending_switch_flips[i];
}
--pending_switch_flip_count;
return take_switch_key(switch_, event);
}
auto opt = InputsController::get_switch_flip();
if (!opt.has_value()) {
return false;
}
return take_switch_key(switch_, *opt);
}
uint8_t get_switch_state() {
return reverse_4_bits(InputsController::switch_state() & 0xF);
}
static bool take_switch_touch(SwitchKey* switch_, const SwitchTouch& event) {
if (switch_ != nullptr) {
*switch_ = static_cast<SwitchKey>(static_cast<uint8_t>(event.get_switch()));
}
return true;
}
bool get_switch_touch_pressed(SwitchKey* switch_) {
SwitchTouch event;
if (pop_pending_switch_touch(true, event)) {
return take_switch_touch(switch_, event);
}
while (true) {
auto opt = InputsController::get_switch_touch();
if (!opt.has_value()) {
return false;
}
if (opt->is_touched()) {
return take_switch_touch(switch_, *opt);
}
push_pending_switch_touch(*opt);
}
}
bool get_switch_touch_released(SwitchKey* switch_) {
SwitchTouch event;
if (pop_pending_switch_touch(false, event)) {
return take_switch_touch(switch_, event);
}
while (true) {
auto opt = InputsController::get_switch_touch();
if (!opt.has_value()) {
return false;
}
if (!opt->is_touched()) {
return take_switch_touch(switch_, *opt);
}
push_pending_switch_touch(*opt);
}
}
uint8_t get_switch_touch_state() {
return reverse_4_bits(InputsController::switch_touch_state() & 0xF);
}
bool get_touch_state() {
return get_fingerprint_touch_state() != 0;
}
bool get_touch_pressed() {
return update_fingerprint_transition(true);
}
bool get_touch_released() {
return update_fingerprint_transition(false);
}