Initial commit

IMU and bubble level working
This commit is contained in:
Brent Perteet
2025-06-14 16:38:53 -05:00
commit f59eb660cf
21 changed files with 6704 additions and 0 deletions

200
main/keypad.c Normal file
View File

@@ -0,0 +1,200 @@
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "keypad.h"
// ───────────── CONFIGURATION ─────────────
typedef enum {
BUTTON1_GPIO = GPIO_NUM_36,
BUTTON2_GPIO = GPIO_NUM_39,
} button_gpio_t;
#define BUTTON_COUNT 2
// If your buttons are activelow, set this to 0. If activehigh, set it to 1.
#define KEYPAD_INACTIVE 1
#define KEYPAD_ACTIVE 0
// Now we run the task every 50 ms and assume that is enough to debounce:
#define DEBOUNCE_INTERVAL_MS 50 // Poll once every 50 ms
// No more stablecount logic—one sample/50 ms is considered “debounced.”
// Short vs. long press threshold (in ms):
#define LONG_PRESS_MS 1000 // ≥1000 ms = “long press”
// Queue length for pending button events:
#define BTN_EVT_QUEUE_LEN 10
// ───────────── EVENT ENUM & QUEUE HANDLE ─────────────
typedef struct
{
keycode_t key;
gpio_num_t gpio;
int prevState;
int currentState;
TickType_t activeTime;
uint32_t event;
} button_t;
static button_t _buttons[2];
// The queue handle that the debounce task will push events into:
static QueueHandle_t s_btn_evt_queue = NULL;
// Call this to get the queue, so the main task can xQueueReceive():
QueueHandle_t keypad_getQueue(void) {
return s_btn_evt_queue;
}
// ───────────── INTERNAL STATE ─────────────
// Current debounced state: 0 = released, 1 = pressed
static int s_debounced[2] = { 0, 0 };
// Tick count when each button was debounced to “pressed”
static TickType_t s_press_tick[2] = { 0, 0 };
// If we suppress an individualbutton event (because it was part of a “both” press), this is true
static bool s_suppress_event[2] = { false, false };
// Tracks if we are currently in “both buttons pressed” phase:
static bool s_was_both = false;
// Tick count when “both buttons” first became debouncedpressed:
static TickType_t s_both_press_tick = 0;
// ───────────── TAG FOR LOGGING ─────────────
static const char *TAG = "btn_debounce";
// ───────────── GPIO SETUP ─────────────
static void init_button_gpio(void)
{
// Configure both as inputs with pullup (assuming activelow buttons)
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << BUTTON1_GPIO) | (1ULL << BUTTON2_GPIO),
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
ESP_ERROR_CHECK(gpio_config(&io_conf));
_buttons[0].activeTime = 0;
_buttons[0].gpio = BUTTON1_GPIO;
_buttons[0].key = KEY0;
_buttons[0].prevState = KEYPAD_INACTIVE;
_buttons[0].currentState = KEYPAD_INACTIVE;
_buttons[1].activeTime = 0;
_buttons[1].gpio = BUTTON2_GPIO;
_buttons[1].key = KEY1;
_buttons[1].prevState = KEYPAD_INACTIVE;
_buttons[1].currentState = KEYPAD_INACTIVE;
}
// ───────────── BUTTON DEBOUNCE & PRESSTYPE TASK ─────────────
static void vButtonDebounceTask(void *arg)
{
(void)arg;
TickType_t now = xTaskGetTickCount();
TickType_t xLastWake = now;
const TickType_t long_press_thresh = pdMS_TO_TICKS(LONG_PRESS_MS);
while (1) {
now = xTaskGetTickCount();
for (int i=0; i < BUTTON_COUNT; ++i)
{
button_t *button = &_buttons[i];
button->currentState = gpio_get_level(button->gpio);
if (button->currentState == KEYPAD_ACTIVE)
{
// just pressed
if (button->prevState == KEYPAD_INACTIVE)
{
button->activeTime = now;
}
else
{
if ((now - button->activeTime) >= long_press_thresh)
{
if (button->event == 0)
{
ESP_LOGI(TAG, "%d LONG", button->key);
button->event = (button->key << KEY_LONG_PRESS);
xQueueSend(s_btn_evt_queue, &button->event, 0);
}
}
}
}
else
if (button->currentState == KEYPAD_INACTIVE)
{
// just released
if (button->prevState == KEYPAD_ACTIVE)
{
if (button->event == 0)
{
ESP_LOGI(TAG, "%d SHORT", button->key);
button->event = (button->key << KEY_SHORT_PRESS);
xQueueSend(s_btn_evt_queue, &button->event, 0);
}
else
{
ESP_LOGI(TAG, "%d LONG RELEASE", button->key);
}
button->event = 0;
}
button->activeTime = 0;
}
button->prevState = button->currentState;
}
// 7) Wait 50 ms and repeat
vTaskDelayUntil(&xLastWake, pdMS_TO_TICKS(DEBOUNCE_INTERVAL_MS));
xLastWake = now;
}
}
// ───────────── PUBLIC “START” FUNCTION ─────────────
void keypad_start(void)
{
// 1) Create the queue for button events
s_btn_evt_queue = xQueueCreate(BTN_EVT_QUEUE_LEN, sizeof(uint32_t));
if (s_btn_evt_queue == NULL) {
ESP_LOGE(TAG, "Failed to create button event queue");
return;
}
// 2) Initialize GPIOs & initial state
init_button_gpio();
// 3) Launch the FreeRTOS task (low priority)
xTaskCreate(vButtonDebounceTask,
"btn_debounce",
2048,
NULL,
tskIDLE_PRIORITY + 1,
NULL);
}