espvban/ESPIDFNEW/main/button.c
2024-08-29 21:38:48 +02:00

160 lines
4 KiB
C

#include "button.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include <hal/cpu_hal.h>
static QueueHandle_t callbackQueue = NULL;
static QueueHandle_t parameterQueue = NULL;
static int64_t pinHistory[32] = {0};
#ifndef GPIO_IN_REG
#define GPIO_IN_REG 0x6000403c
#endif
static void IRAM_ATTR rotaryPinChange(void *arg)
{
rotaryPins *encoder = (rotaryPins *)arg;
static char oldpinA = 0;
static char oldpinB = 0;
uint32_t io = REG_READ(GPIO_IN_REG);
char pinA = (io >> encoder->PIN1) & 0x01;
char pinB = (io >> encoder->PIN2) & 0x01;
static uint8_t state = 0;
switch (state)
{
case 0:
// PINA Fallng CW
if (oldpinA == 1 && pinA == 0 && pinB)
{
state++;
}
else if (oldpinB == 1 && pinB == 0 && pinA)
{
state++;
}
break;
case 1:
// PINB Falling CW
if (oldpinB == 1 && pinB == 0 && !pinA)
{
state++;
}
else if (oldpinA == 1 && pinA == 0 && !pinB)
{
state++;
}
break;
// PINA Rising
case 2:
if (oldpinA == 0 && pinA == 1 && !pinB)
{
state++;
}
else if (oldpinB == 0 && pinB == 1 && !pinA)
{
state++;
}
break;
// PINB RISING
case 3:
if (oldpinB == 0 && pinB == 1 && pinA)
{
state = 0;
xQueueSendFromISR(callbackQueue, &encoder->CWCallback, NULL);
xQueueSendFromISR(parameterQueue, encoder, NULL);
}
else if (oldpinA == 0 && pinA == 1 && pinB)
{
state = 0;
xQueueSendFromISR(callbackQueue, &encoder->CCWCallback, NULL);
xQueueSendFromISR(parameterQueue, encoder, NULL);
}
break;
default:
break;
}
oldpinA = pinA;
oldpinB = pinB;
}
static void IRAM_ATTR buttonPress(void *arg)
{
rotaryPins *encoder = (rotaryPins *)arg;
uint64_t time = esp_timer_get_time();
if (time - encoder->lastButtonCall > 1000)
{
xQueueSendFromISR(callbackQueue, &encoder->buttonCallback, NULL);
xQueueSendFromISR(parameterQueue, encoder, NULL);
encoder->lastButtonCall = time;
}
}
static void printStatus(void *arg)
{
rotaryCallback callbackFunc;
rotaryPins *rotStruct;
for (;;)
{
if (xQueueReceive(callbackQueue, &callbackFunc, portMAX_DELAY) && xQueueReceive(parameterQueue, &rotStruct, portMAX_DELAY))
{
if (callbackFunc)
callbackFunc(rotStruct);
}
vTaskDelay(20/portTICK_PERIOD_MS);
}
}
void registerInterrupt(rotaryPins *rot)
{
rot->ioMask = ((1ULL << rot->PIN1) | (1ULL << rot->PIN2) | (1ULL << rot->BUT));
// zero-initialize the config structure.
gpio_config_t io_conf = {};
// interrupt of rising edge
io_conf.intr_type = GPIO_INTR_ANYEDGE;
// bit mask of the pins, use GPIO4/5 here
io_conf.pin_bit_mask = rot->ioMask;
// set as input mode
io_conf.mode = GPIO_MODE_INPUT;
// enable pull-up mode
io_conf.pull_up_en = 1;
io_conf.pull_down_en = 0;
gpio_config(&io_conf);
gpio_set_intr_type(rot->BUT,GPIO_INTR_POSEDGE);
// create a queue to handle gpio event from isr
callbackQueue = xQueueCreate(10, sizeof(rotaryCallback));
parameterQueue = xQueueCreate(10, sizeof(rotaryPins *));
// start gpio task
xTaskCreate(printStatus, "rotaryQueueHandler", 2048, NULL, 10, NULL);
// install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
// hook isr handler for specific gpio pin
gpio_isr_handler_add(rot->PIN1, rotaryPinChange, (void *)rot);
// hook isr handler for specific gpio pin
gpio_isr_handler_add(rot->PIN2, rotaryPinChange, (void *)rot);
gpio_isr_handler_add(rot->BUT, buttonPress, (void *)rot);
esp_timer_early_init();
}