switch to event based input system (untested)
This commit is contained in:
parent
2f1ff23678
commit
f5c938d61f
@ -4,7 +4,9 @@ set(SOURCES
|
||||
"TM1640/TM1640.cpp"
|
||||
"SparkFunBQ27441/SparkFunBQ27441.cpp"
|
||||
"esp_lcd_ili9488/esp_lcd_ili9488.c"
|
||||
"bottom_half.cpp"
|
||||
# "bottom_half.cpp"
|
||||
"event_based_bottom_half.cpp"
|
||||
"inputs.cpp"
|
||||
"char_lcd.cpp"
|
||||
"game_timer.cpp"
|
||||
"i2c_lcd_pcf8574.c"
|
||||
|
||||
326
main/drivers/event_based_bottom_half.cpp
Normal file
326
main/drivers/event_based_bottom_half.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
#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);
|
||||
}
|
||||
475
main/drivers/inputs.cpp
Normal file
475
main/drivers/inputs.cpp
Normal file
@ -0,0 +1,475 @@
|
||||
#include "inputs.hpp"
|
||||
#include "pins.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
static const char *TAG = "INPUTS";
|
||||
|
||||
static TaskHandle_t expander_task_handle = NULL;
|
||||
|
||||
const static uint8_t REG_WHOAMI = 0x01;
|
||||
const static uint8_t REG_SW_VERSION = 0x02;
|
||||
const static uint8_t REG_EVENT_QUEUE_POP = 0x10;
|
||||
const static uint8_t REG_EVENT_QUEUE_LEN = 0x11;
|
||||
const static uint8_t REG_STATE_BUTTONS = 0x20;
|
||||
const static uint8_t REG_STATE_SWITCHES = 0x21;
|
||||
const static uint8_t REG_STATE_KEYPAD = 0x22;
|
||||
const static uint8_t REG_STATE_TOUCH = 0x23;
|
||||
const static uint8_t REG_STATE_RFID = 0x24;
|
||||
const static uint8_t REG_STATE_HALL = 0x25;
|
||||
const static uint8_t REG_STATE_CLOSE = 0x26;
|
||||
const static uint8_t REG_RESET = 0x30;
|
||||
const static uint8_t REG_HALL_SENSITIVITY = 0x31;
|
||||
const static uint8_t REG_CLOSE_SENSITIVITY = 0x32;
|
||||
const static uint8_t REG_SWITCH_TOUCH_EVENT = 0x33;
|
||||
|
||||
/// The global data for the expander peripheral.
|
||||
class ExpanderPeripheral {
|
||||
// TODO: change these to private
|
||||
// or even make this class hidden
|
||||
public:
|
||||
SemaphoreHandle_t state_mutex;
|
||||
InputsState state;
|
||||
|
||||
// channels
|
||||
QueueHandle_t button_press_events;
|
||||
QueueHandle_t button_release_events;
|
||||
QueueHandle_t switch_flip_events;
|
||||
QueueHandle_t switch_touch_events;
|
||||
QueueHandle_t touch_events;
|
||||
QueueHandle_t keypad_press_events;
|
||||
QueueHandle_t keypad_release_events;
|
||||
};
|
||||
|
||||
ExpanderPeripheral expander_peripheral_singleton;
|
||||
|
||||
// forward declarations
|
||||
static void get_events();
|
||||
static void handle_event(uint8_t event);
|
||||
static void handle_button_switch_event(uint8_t event);
|
||||
static void handle_keypad_event(uint8_t event);
|
||||
static void handle_touch_event(uint8_t event);
|
||||
static void handle_rfid_event(uint8_t event);
|
||||
static void handle_close_hal_event(uint8_t event);
|
||||
static void expander_task(void *arg);
|
||||
|
||||
// ISR handler
|
||||
static void IRAM_ATTR expander_isr_handler(void *arg) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
|
||||
if (expander_task_handle != NULL) {
|
||||
vTaskNotifyGiveFromISR(expander_task_handle, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void init_expander() {
|
||||
ESP_LOGI(TAG, "Initializing expander...");
|
||||
|
||||
// legacy I2C driver: use the shared I2C_NUM_0 bus already configured elsewhere.
|
||||
// TODO: replace all these ESP_ERROR_CHECK with proper error handling that doesn't just crash the program
|
||||
|
||||
// setup interrupt on PIN_EXPANDER_INT
|
||||
gpio_config_t io_conf = {
|
||||
.pin_bit_mask = (1ULL << PIN_EXPANDER_INT),
|
||||
.mode = GPIO_MODE_INPUT,
|
||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.intr_type = GPIO_INTR_NEGEDGE
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
|
||||
// Install ISR service (only call once in your program)
|
||||
ESP_ERROR_CHECK(gpio_install_isr_service(0));
|
||||
|
||||
// Attach the ISR to the expander pin
|
||||
ESP_ERROR_CHECK(gpio_isr_handler_add(PIN_EXPANDER_INT, expander_isr_handler, NULL));
|
||||
|
||||
// verify the expander connection status by reading the WHOAMI register
|
||||
uint8_t read_buf[2] = {0};
|
||||
|
||||
ESP_ERROR_CHECK(i2c_master_write_read_device(I2C_NUM_0, EXPANDER_I2C_ADDR, ®_WHOAMI, 1, read_buf, 1, pdMS_TO_TICKS(EXPANDER_TIMEOUT_MS)));
|
||||
|
||||
if (read_buf[0] != EXPANDER_WHOAMI_VALUE) {
|
||||
ESP_LOGE(TAG, "WHOAMI mismatch, expected 0x%02X, got 0x%02X", EXPANDER_WHOAMI_VALUE, read_buf[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Expander WHOAMI check passed");
|
||||
|
||||
ESP_ERROR_CHECK(i2c_master_write_read_device(I2C_NUM_0, EXPANDER_I2C_ADDR, ®_SW_VERSION, 1, read_buf, 2, pdMS_TO_TICKS(EXPANDER_TIMEOUT_MS)));
|
||||
|
||||
// init the peripheral struct
|
||||
expander_peripheral_singleton.state_mutex = xSemaphoreCreateMutex();
|
||||
expander_peripheral_singleton.button_press_events= xQueueCreate(EXPANDER_EVENT_QUEUE_SIZE, sizeof(Button));
|
||||
expander_peripheral_singleton.button_release_events= xQueueCreate(EXPANDER_EVENT_QUEUE_SIZE, sizeof(Button));
|
||||
expander_peripheral_singleton.switch_flip_events= xQueueCreate(EXPANDER_EVENT_QUEUE_SIZE, sizeof(SwitchFlip));
|
||||
expander_peripheral_singleton.switch_touch_events= xQueueCreate(EXPANDER_EVENT_QUEUE_SIZE, sizeof(SwitchTouch));
|
||||
expander_peripheral_singleton.touch_events= xQueueCreate(EXPANDER_EVENT_QUEUE_SIZE, sizeof(TouchedReleased));
|
||||
expander_peripheral_singleton.keypad_press_events= xQueueCreate(EXPANDER_KEYPAD_QUEUE_SIZE, sizeof(InputKeypadKey));
|
||||
expander_peripheral_singleton.keypad_release_events= xQueueCreate(EXPANDER_KEYPAD_QUEUE_SIZE, sizeof(InputKeypadKey));
|
||||
|
||||
ESP_LOGI(TAG, "Expander initialized! SW version: v%d.%d", read_buf[0], read_buf[1]);
|
||||
|
||||
// Create the expander background worker task
|
||||
BaseType_t task_created = xTaskCreate(
|
||||
expander_task,
|
||||
"expander_task",
|
||||
4096,
|
||||
NULL,
|
||||
tskIDLE_PRIORITY + 1,
|
||||
&expander_task_handle
|
||||
);
|
||||
|
||||
if (task_created != pdPASS) {
|
||||
ESP_LOGE(TAG, "Failed to create expander task");
|
||||
}
|
||||
}
|
||||
|
||||
static void expander_task(void *arg) {
|
||||
(void)arg;
|
||||
|
||||
while (true) {
|
||||
get_events();
|
||||
|
||||
// Wait for interrupt notification (signal is sent when INT falls)
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_events() {
|
||||
uint8_t recv;
|
||||
while (gpio_get_level(PIN_EXPANDER_INT) == 0) {
|
||||
ESP_ERROR_CHECK(i2c_master_write_read_device(I2C_NUM_0, EXPANDER_I2C_ADDR, ®_EVENT_QUEUE_POP, 1, &recv, 1, pdMS_TO_TICKS(EXPANDER_TIMEOUT_MS)));
|
||||
handle_event(recv);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_event(uint8_t event) {
|
||||
const uint8_t BUTTON_SWITCH = 0b000;
|
||||
const uint8_t KEYPAD = 0b001;
|
||||
const uint8_t TOUCH = 0b010;
|
||||
const uint8_t RFID = 0b011;
|
||||
|
||||
ESP_LOGD(TAG, "Expander event: 0b%08b (0x%02X)", event, event);
|
||||
|
||||
if (event == 0) {
|
||||
ESP_LOGE(TAG, "We read from event queue while it was empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t type_bits = event >> 5;
|
||||
|
||||
switch (type_bits) {
|
||||
case BUTTON_SWITCH:
|
||||
handle_button_switch_event(event);
|
||||
break;
|
||||
case KEYPAD:
|
||||
handle_keypad_event(event);
|
||||
break;
|
||||
case TOUCH:
|
||||
handle_touch_event(event);
|
||||
break;
|
||||
case RFID:
|
||||
handle_rfid_event(event);
|
||||
break;
|
||||
default:
|
||||
handle_close_hal_event(event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_button_switch_event(uint8_t event) {
|
||||
const uint8_t PRESSED_NOT_RELEASED_BIT = 0b10000;
|
||||
const uint8_t SWITCH_NOT_BUTTON_BIT = 0b01000;
|
||||
const uint8_t SWITCH_UP_NOT_DOWN_BIT = 0b00100;
|
||||
const uint8_t NUMBER_MASK = 0b00011;
|
||||
|
||||
bool pressed = (event & PRESSED_NOT_RELEASED_BIT) != 0;
|
||||
uint8_t number = event & NUMBER_MASK;
|
||||
|
||||
if ((event & SWITCH_NOT_BUTTON_BIT) != 0) {
|
||||
// For now, we support two position switches by only looking at the switch up events
|
||||
bool switch_up = (event & SWITCH_UP_NOT_DOWN_BIT) != 0;
|
||||
if (!switch_up) {
|
||||
return;
|
||||
}
|
||||
|
||||
Switch sw = static_cast<Switch>(number);
|
||||
SwitchFlip sw_flip = SwitchFlip(sw, pressed);
|
||||
xQueueSendToBack(expander_peripheral_singleton.switch_flip_events, &sw_flip, 0);
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
if (pressed) {
|
||||
// set
|
||||
expander_peripheral_singleton.state.switch_state |= 1 << number;
|
||||
} else {
|
||||
// clear
|
||||
expander_peripheral_singleton.state.switch_state &= ~(1 << number);
|
||||
}
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
} else {
|
||||
// button
|
||||
Button button = static_cast<Button>(number);
|
||||
if (pressed) {
|
||||
xQueueSendToBack(expander_peripheral_singleton.button_press_events, &button, 0);
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
expander_peripheral_singleton.state.button_state |= 1 << number;
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
} else {
|
||||
xQueueSendToBack(expander_peripheral_singleton.button_release_events, &button, 0);
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
expander_peripheral_singleton.state.button_state &= ~(1 << number);
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_keypad_event(uint8_t event) {
|
||||
const uint8_t PRESSED_NOT_RELEASED_BIT = 0b10000;
|
||||
const uint8_t KEY_MASK = 0b1111;
|
||||
|
||||
bool pressed = (event & PRESSED_NOT_RELEASED_BIT) != 0;
|
||||
uint8_t number = event & KEY_MASK;
|
||||
InputKeypadKey key = static_cast<InputKeypadKey>(number);
|
||||
|
||||
// starcode system gets first dibs
|
||||
// TODO: do starcode inbetweener
|
||||
// if starcode_handle_keypad(key, pressed).await {
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (pressed) {
|
||||
xQueueSendToBack(expander_peripheral_singleton.keypad_press_events, &key, 0);
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
expander_peripheral_singleton.state.keypad_state |= 1 << number;
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
} else {
|
||||
xQueueSendToBack(expander_peripheral_singleton.keypad_release_events, &key, 0);
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
expander_peripheral_singleton.state.keypad_state &= ~(1 << number);
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_touch_event(uint8_t event) {
|
||||
const uint8_t TOUCHED_NOT_UNTOUCHED_BIT = 0b10000;
|
||||
const uint8_t SENSOR_MASK = 0b0111;
|
||||
const uint8_t FINGERPRINT_BIT = 0b0100;
|
||||
|
||||
bool touched = (event & TOUCHED_NOT_UNTOUCHED_BIT) != 0;
|
||||
uint8_t sensor = event & SENSOR_MASK;
|
||||
|
||||
if ((sensor & FINGERPRINT_BIT) != 0) {
|
||||
TouchedReleased touch_state = static_cast<TouchedReleased>(touched);
|
||||
xQueueSendToBack(expander_peripheral_singleton.touch_events, &touch_state, 0);
|
||||
} else {
|
||||
Switch sw = static_cast<Switch>(sensor);
|
||||
SwitchTouch sw_touch = SwitchTouch(sw, touched);
|
||||
xQueueSendToBack(expander_peripheral_singleton.switch_touch_events, &sw_touch, 0);
|
||||
}
|
||||
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
if (touched) {
|
||||
expander_peripheral_singleton.state.touch_state |= 1 << sensor;
|
||||
} else {
|
||||
expander_peripheral_singleton.state.touch_state &= ~(1 << sensor);
|
||||
}
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
}
|
||||
|
||||
static void handle_rfid_event(uint8_t event) {
|
||||
// TODO: impl
|
||||
(void)event;
|
||||
}
|
||||
|
||||
static void handle_close_hal_event(uint8_t event) {
|
||||
// TODO: impl
|
||||
(void)event;
|
||||
}
|
||||
|
||||
// InputsController implementations
|
||||
|
||||
/// Clears all events waiting in the queues.
|
||||
void InputsController::clear_all_events() {
|
||||
xQueueReset(expander_peripheral_singleton.button_press_events);
|
||||
xQueueReset(expander_peripheral_singleton.button_release_events);
|
||||
xQueueReset(expander_peripheral_singleton.switch_flip_events);
|
||||
xQueueReset(expander_peripheral_singleton.switch_touch_events);
|
||||
xQueueReset(expander_peripheral_singleton.touch_events);
|
||||
xQueueReset(expander_peripheral_singleton.keypad_press_events);
|
||||
xQueueReset(expander_peripheral_singleton.keypad_release_events);
|
||||
}
|
||||
|
||||
InputsState InputsController::get_input_state() {
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
InputsState state_copy = expander_peripheral_singleton.state;
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
return state_copy;
|
||||
}
|
||||
|
||||
/// Returns `true` iff there is a button press event waiting.
|
||||
bool InputsController::has_button_press() {
|
||||
return uxQueueMessagesWaiting(expander_peripheral_singleton.button_press_events) > 0;
|
||||
}
|
||||
|
||||
/// Gets the next button press event (if any).
|
||||
std::optional<Button> InputsController::get_button_press() {
|
||||
Button b;
|
||||
if (xQueueReceive(expander_peripheral_singleton.button_press_events, &b, 0) == pdTRUE) {
|
||||
return b;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Gets the next button press event, waiting if neccesary.
|
||||
Button InputsController::wait_button_press() {
|
||||
Button b;
|
||||
xQueueReceive(expander_peripheral_singleton.button_press_events, &b, portMAX_DELAY);
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Gets the current state of the buttons.
|
||||
uint8_t InputsController::button_state() {
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
uint8_t value = expander_peripheral_singleton.state.button_state;
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Returns `true` iff there is a button release event waiting.
|
||||
bool InputsController::has_button_release() {
|
||||
return uxQueueMessagesWaiting(expander_peripheral_singleton.button_release_events) > 0;
|
||||
}
|
||||
|
||||
/// Gets the next button release event (if any).
|
||||
std::optional<Button> InputsController::get_button_release() {
|
||||
Button b;
|
||||
if (xQueueReceive(expander_peripheral_singleton.button_release_events, &b, 0) == pdTRUE) {
|
||||
return b;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Gets the next button release event, waiting if neccesary.
|
||||
Button InputsController::wait_button_release() {
|
||||
Button b;
|
||||
xQueueReceive(expander_peripheral_singleton.button_release_events, &b, portMAX_DELAY);
|
||||
return b;
|
||||
}
|
||||
|
||||
/// Returns `true` iff there is a switch flip event waiting.
|
||||
bool InputsController::has_switch_flip() {
|
||||
return uxQueueMessagesWaiting(expander_peripheral_singleton.switch_flip_events) > 0;
|
||||
}
|
||||
|
||||
/// Gets the next switch flip event (if any).
|
||||
std::optional<SwitchFlip> InputsController::get_switch_flip() {
|
||||
SwitchFlip s;
|
||||
if (xQueueReceive(expander_peripheral_singleton.switch_flip_events, &s, 0) == pdTRUE) {
|
||||
return s;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Gets the next switch flip event, waiting if neccesary.
|
||||
SwitchFlip InputsController::wait_switch_flip() {
|
||||
SwitchFlip s;
|
||||
xQueueReceive(expander_peripheral_singleton.switch_flip_events, &s, portMAX_DELAY);
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Gets the current state of the switches.
|
||||
uint8_t InputsController::switch_state() {
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
uint8_t value = expander_peripheral_singleton.state.switch_state;
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Returns `true` iff there is a switch touch event waiting.
|
||||
bool InputsController::has_switch_touch() {
|
||||
return uxQueueMessagesWaiting(expander_peripheral_singleton.switch_touch_events) > 0;
|
||||
}
|
||||
|
||||
/// Gets the next switch touch event (if any).
|
||||
std::optional<SwitchTouch> InputsController::get_switch_touch() {
|
||||
SwitchTouch s;
|
||||
if (xQueueReceive(expander_peripheral_singleton.switch_touch_events, &s, 0) == pdTRUE) {
|
||||
return s;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Gets the next switch touch event, waiting if neccesary.
|
||||
SwitchTouch InputsController::wait_switch_touch() {
|
||||
SwitchTouch s;
|
||||
xQueueReceive(expander_peripheral_singleton.switch_touch_events, &s, portMAX_DELAY);
|
||||
return s;
|
||||
}
|
||||
|
||||
/// Gets the current state of the touch sensors.
|
||||
uint8_t InputsController::switch_touch_state() {
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
uint8_t value = expander_peripheral_singleton.state.touch_state;
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// Returns `true` iff there is a keypad press event waiting.
|
||||
bool InputsController::has_keypad_press() {
|
||||
return uxQueueMessagesWaiting(expander_peripheral_singleton.keypad_press_events) > 0;
|
||||
}
|
||||
|
||||
/// Gets the next keypad press event (if any).
|
||||
std::optional<InputKeypadKey> InputsController::get_keypad_press() {
|
||||
InputKeypadKey k;
|
||||
if (xQueueReceive(expander_peripheral_singleton.keypad_press_events, &k, 0) == pdTRUE) {
|
||||
return k;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Gets the next keypad press event, waiting if neccesary.
|
||||
InputKeypadKey InputsController::wait_keypad_press() {
|
||||
InputKeypadKey k;
|
||||
xQueueReceive(expander_peripheral_singleton.keypad_press_events, &k, portMAX_DELAY);
|
||||
return k;
|
||||
}
|
||||
|
||||
/// Returns `true` iff there is a keypad release event waiting.
|
||||
bool InputsController::has_keypad_release() {
|
||||
return uxQueueMessagesWaiting(expander_peripheral_singleton.keypad_release_events) > 0;
|
||||
}
|
||||
|
||||
/// Gets the next keypad release event (if any).
|
||||
std::optional<InputKeypadKey> InputsController::get_keypad_release() {
|
||||
InputKeypadKey k;
|
||||
if (xQueueReceive(expander_peripheral_singleton.keypad_release_events, &k, 0) == pdTRUE) {
|
||||
return k;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
/// Gets the next keypad release event, waiting if neccesary.
|
||||
InputKeypadKey InputsController::wait_keypad_release() {
|
||||
InputKeypadKey k;
|
||||
xQueueReceive(expander_peripheral_singleton.keypad_release_events, &k, portMAX_DELAY);
|
||||
return k;
|
||||
}
|
||||
|
||||
/// Gets the current state of the keypad.
|
||||
uint16_t InputsController::keypad_state() {
|
||||
xSemaphoreTake(expander_peripheral_singleton.state_mutex, portMAX_DELAY);
|
||||
uint16_t value = expander_peripheral_singleton.state.keypad_state;
|
||||
xSemaphoreGive(expander_peripheral_singleton.state_mutex);
|
||||
return value;
|
||||
}
|
||||
|
||||
275
main/drivers/inputs.hpp
Normal file
275
main/drivers/inputs.hpp
Normal file
@ -0,0 +1,275 @@
|
||||
#ifndef INPUTS_H
|
||||
#define INPUTS_H
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <optional>
|
||||
|
||||
#define EXPANDER_I2C_ADDR (0x7E)
|
||||
#define EXPANDER_I2C_SPEED (400000)
|
||||
// the actual transaction takes ~0.3ms, but for some reason a timout of ~10 or lower causes issues.
|
||||
#define EXPANDER_TIMEOUT_MS (100)
|
||||
|
||||
#define EXPANDER_WHOAMI_VALUE (0x85)
|
||||
|
||||
// queue sizes
|
||||
#define EXPANDER_EVENT_QUEUE_SIZE 4
|
||||
#define EXPANDER_KEYPAD_QUEUE_SIZE 16
|
||||
|
||||
void init_expander();
|
||||
|
||||
/// The four buttons on the bottom half.
|
||||
enum class Button: uint8_t {
|
||||
B1 = 0,
|
||||
B2 = 1,
|
||||
B3 = 2,
|
||||
B4 = 3,
|
||||
GREEN = 0,
|
||||
YELLOW = 1,
|
||||
RED = 2,
|
||||
BLUE = 3,
|
||||
};
|
||||
|
||||
constexpr uint8_t raw_value(Button v) { return static_cast<uint8_t>(v); }
|
||||
constexpr Button button_from_raw(uint8_t raw) { return static_cast<Button>(raw & 0b11); }
|
||||
|
||||
/// The four switches on the bottom half.
|
||||
enum class Switch: uint8_t {
|
||||
S1 = 0,
|
||||
S2 = 1,
|
||||
S3 = 2,
|
||||
S4 = 3,
|
||||
};
|
||||
|
||||
constexpr uint8_t raw_value(Switch v) { return static_cast<uint8_t>(v); }
|
||||
constexpr Switch switch_from_raw(uint8_t raw) { return static_cast<Switch>(raw & 0b11); }
|
||||
|
||||
enum class TouchedReleased: uint8_t {
|
||||
Released = 0,
|
||||
Touched = 1,
|
||||
};
|
||||
|
||||
constexpr uint8_t raw_value(TouchedReleased v) { return static_cast<uint8_t>(v); }
|
||||
constexpr TouchedReleased touched_released_from_raw(uint8_t raw) { return static_cast<TouchedReleased>(raw & 0b1); }
|
||||
|
||||
/// One of the keys on the keypad.
|
||||
enum class InputKeypadKey: uint8_t {
|
||||
K0 = 0,
|
||||
K1 = 1,
|
||||
K2 = 2,
|
||||
K3 = 3,
|
||||
K4 = 4,
|
||||
K5 = 5,
|
||||
K6 = 6,
|
||||
K7 = 7,
|
||||
K8 = 8,
|
||||
K9 = 9,
|
||||
A = 10,
|
||||
B = 11,
|
||||
C = 12,
|
||||
D = 13,
|
||||
STAR = 14,
|
||||
POUND = 15,
|
||||
};
|
||||
|
||||
constexpr uint8_t raw_value(InputKeypadKey v) { return static_cast<uint8_t>(v); }
|
||||
constexpr InputKeypadKey keypad_key_from_raw(uint8_t raw) { return static_cast<InputKeypadKey>(raw & 0b1111); }
|
||||
|
||||
constexpr char keypad_key_to_char(InputKeypadKey key) {
|
||||
static constexpr char lookup[16] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', '*', '#'
|
||||
};
|
||||
return lookup[static_cast<uint8_t>(key) & 0b1111];
|
||||
}
|
||||
|
||||
|
||||
struct SwitchFlip {
|
||||
private:
|
||||
// [bit2: up] [bit1-0: switch]
|
||||
uint8_t data;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SwitchFlip(Switch sw, bool up)
|
||||
: data((static_cast<uint8_t>(sw) & 0b11) |
|
||||
((up ? 1 : 0) << 2)) {}
|
||||
|
||||
// Default constructor
|
||||
SwitchFlip() : data(0) {}
|
||||
|
||||
// Raw value constructor
|
||||
explicit SwitchFlip(uint8_t raw_data) : data(raw_data) {}
|
||||
|
||||
// Raw value getter
|
||||
uint8_t raw() const { return data; }
|
||||
|
||||
// Getters
|
||||
Switch get_switch() const {
|
||||
return static_cast<Switch>(data & 0b11);
|
||||
}
|
||||
|
||||
bool is_up() const {
|
||||
return (data >> 2) & 1;
|
||||
}
|
||||
|
||||
// Setters
|
||||
void set_switch(Switch sw) {
|
||||
data = (data & ~0b11) | (static_cast<uint8_t>(sw) & 0b11);
|
||||
}
|
||||
|
||||
void set_up(bool up) {
|
||||
data = (data & ~(1 << 2)) | ((up ? 1 : 0) << 2);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(SwitchFlip) == 1);
|
||||
|
||||
struct SwitchTouch {
|
||||
private:
|
||||
// [bit2: touched] [bit1-0: switch]
|
||||
uint8_t data;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
SwitchTouch(Switch sw, bool touched)
|
||||
: data((static_cast<uint8_t>(sw) & 0b11) |
|
||||
((touched ? 1 : 0) << 2)) {}
|
||||
|
||||
// Default constructor
|
||||
SwitchTouch() : data(0) {}
|
||||
|
||||
// Raw value constructor
|
||||
explicit SwitchTouch(uint8_t raw_data) : data(raw_data) {}
|
||||
|
||||
// Raw value getter
|
||||
uint8_t raw() const { return data; }
|
||||
|
||||
// Getters
|
||||
Switch get_switch() const {
|
||||
return static_cast<Switch>(data & 0b11);
|
||||
}
|
||||
|
||||
bool is_touched() const {
|
||||
return (data >> 2) & 1;
|
||||
}
|
||||
|
||||
// Setters
|
||||
void set_switch(Switch sw) {
|
||||
data = (data & ~0b11) | (static_cast<uint8_t>(sw) & 0b11);
|
||||
}
|
||||
|
||||
void set_touched(bool touched) {
|
||||
data = (data & ~(1 << 2)) | ((touched ? 1 : 0) << 2);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(SwitchTouch) == 1);
|
||||
|
||||
struct ButtonOrSwitch {
|
||||
private:
|
||||
// [bit2: is_switch] [bit1-0: number]
|
||||
uint8_t data;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
ButtonOrSwitch(uint8_t number, bool is_switch)
|
||||
: data((number & 0b11) |
|
||||
((is_switch ? 1 : 0) << 2)) {}
|
||||
|
||||
ButtonOrSwitch() : data(0) {}
|
||||
|
||||
// Raw value constructor
|
||||
explicit ButtonOrSwitch(uint8_t raw_data) : data(raw_data) {}
|
||||
|
||||
// Raw value getter
|
||||
uint8_t raw() const { return data; }
|
||||
|
||||
// Getters
|
||||
uint8_t number() const {
|
||||
return data & 0b11;
|
||||
}
|
||||
|
||||
bool is_switch() const {
|
||||
return (data >> 2) & 1;
|
||||
}
|
||||
|
||||
// Setters
|
||||
void set_number(uint8_t number) {
|
||||
data = (data & ~0b11) | (number & 0b11);
|
||||
}
|
||||
|
||||
void set_is_switch(bool is_switch) {
|
||||
data = (data & ~(1 << 2)) | ((is_switch ? 1 : 0) << 2);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(ButtonOrSwitch) == 1);
|
||||
|
||||
|
||||
/// @brief The state of the bottom half of the box.
|
||||
struct InputsState {
|
||||
/// The touch state of the switches in the lower 4 bits.
|
||||
/// The touch pad state in bit 4.
|
||||
uint8_t touch_state;
|
||||
/// The current state of the buttons in the lower 4 bits.
|
||||
uint8_t button_state;
|
||||
/// The current state of the switches. Up switches are stored
|
||||
/// in the lower 4 bits, switches that are down are stored in
|
||||
/// the upper 4 bits. If switches are in the middle, the
|
||||
/// corresponding bit will be `0` in the upper and lower 4.
|
||||
uint8_t switch_state;
|
||||
/// The state of the keypad.
|
||||
uint16_t keypad_state;
|
||||
/// The sensitivity of the `hal` value to auto update.
|
||||
uint16_t hal_sense;
|
||||
/// The sensitivity of the `close_hal` value to auto update.
|
||||
uint16_t close_hal_sense;
|
||||
/// A non-exact hal value reading.
|
||||
/// This only gets updated when it changes by `hal_sense`
|
||||
uint16_t hal;
|
||||
/// A non-exact hal value reading.
|
||||
/// This only gets updated when it changes by `close_hal_sense`
|
||||
uint16_t close_hal;
|
||||
/// The RFID card that was presented last.
|
||||
uint32_t rfid_state;
|
||||
|
||||
InputsState() : touch_state(0), button_state(0), switch_state(0), keypad_state(0), hal_sense(0), close_hal_sense(0), hal(0), close_hal(0), rfid_state(0) {}
|
||||
};
|
||||
|
||||
class InputsController {
|
||||
public:
|
||||
static void clear_all_events();
|
||||
|
||||
static InputsState get_input_state();
|
||||
|
||||
static bool has_button_press();
|
||||
static std::optional<Button> get_button_press();
|
||||
static Button wait_button_press();
|
||||
static uint8_t button_state();
|
||||
|
||||
static bool has_button_release();
|
||||
static std::optional<Button> get_button_release();
|
||||
static Button wait_button_release();
|
||||
|
||||
static bool has_switch_flip();
|
||||
static std::optional<SwitchFlip> get_switch_flip();
|
||||
static SwitchFlip wait_switch_flip();
|
||||
static uint8_t switch_state();
|
||||
|
||||
static bool has_switch_touch();
|
||||
static std::optional<SwitchTouch> get_switch_touch();
|
||||
static SwitchTouch wait_switch_touch();
|
||||
static uint8_t switch_touch_state();
|
||||
|
||||
static bool has_keypad_press();
|
||||
static std::optional<InputKeypadKey> get_keypad_press();
|
||||
static InputKeypadKey wait_keypad_press();
|
||||
|
||||
static bool has_keypad_release();
|
||||
static std::optional<InputKeypadKey> get_keypad_release();
|
||||
static InputKeypadKey wait_keypad_release();
|
||||
static uint16_t keypad_state();
|
||||
|
||||
// TODO: impl and add the hal and RFID stuff
|
||||
};
|
||||
|
||||
#endif // INPUTS_H
|
||||
48
main/drivers/pins.h
Normal file
48
main/drivers/pins.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef PINS_H
|
||||
#define PINS_H
|
||||
|
||||
#include "driver/gpio.h"
|
||||
|
||||
// ONLY INPUTS.HPP uses this file
|
||||
|
||||
#define PIN_SDA (GPIO_NUM_7)
|
||||
#define PIN_SCL (GPIO_NUM_15)
|
||||
|
||||
#define PIN_LCD_MISO (GPIO_NUM_16)
|
||||
#define PIN_LCD_MOSI (GPIO_NUM_17)
|
||||
#define PIN_LCD_CLK (GPIO_NUM_18)
|
||||
#define PIN_LCD_RS (GPIO_NUM_8)
|
||||
#define PIN_LCD_RST (GPIO_NUM_9)
|
||||
|
||||
#define PIN_USB_DM (GPIO_NUM_19)
|
||||
#define PIN_USB_DP (GPIO_NUM_20)
|
||||
|
||||
#define PIN_I2S_DAT (GPIO_NUM_3)
|
||||
#define PIN_I2S_BCLK (GPIO_NUM_11)
|
||||
#define PIN_I2S_LRCLK (GPIO_NUM_12)
|
||||
|
||||
#define PIN_SSEG_DAT (GPIO_NUM_46)
|
||||
#define PIN_SSEG_CLK (GPIO_NUM_48)
|
||||
|
||||
#define PIN_MPU_INT (GPIO_NUM_10)
|
||||
#define PIN_EXPANDER_INT (GPIO_NUM_13)
|
||||
|
||||
#define PIN_IR_RCV (GPIO_NUM_14)
|
||||
|
||||
// #define PIN_NEOPIXEL (GPIO_NUM_21) // Rev 2.1
|
||||
#define PIN_NEOPIXEL (GPIO_NUM_0) // Rev 2.0
|
||||
|
||||
#define PIN_SD_DAT0 (GPIO_NUM_38)
|
||||
#define PIN_SD_DAT1 (GPIO_NUM_47)
|
||||
#define PIN_SD_DAT2 (GPIO_NUM_42)
|
||||
#define PIN_SD_DAT3 (GPIO_NUM_41)
|
||||
#define PIN_SD_CMD (GPIO_NUM_40)
|
||||
#define PIN_SD_CLK (GPIO_NUM_39)
|
||||
|
||||
#define PIN_PERH0 (GPIO_NUM_6)
|
||||
#define PIN_PERH1 (GPIO_NUM_5)
|
||||
#define PIN_PERH2 (GPIO_NUM_4)
|
||||
#define PIN_PERH3 (GPIO_NUM_2)
|
||||
#define PIN_PERH4 (GPIO_NUM_1)
|
||||
|
||||
#endif // PINS_H
|
||||
Loading…
Reference in New Issue
Block a user