board/main/ui_input.c

235 lines
7.6 KiB
C

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config_key.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
#include "gui.c"
#include "light.c"
#include "pca9555.c"
#define ENCODER_0_CLK_PORT_IO CONFIG_ENCODER_0_CLK_PORT_IO
#define ENCODER_0_DT_PORT_IO CONFIG_ENCODER_0_DT_PORT_IO
#define ENCODER_0_SW_PORT_IO CONFIG_ENCODER_0_SW_PORT_IO
#define ENCODER_1_CLK_PORT_IO CONFIG_ENCODER_1_CLK_PORT_IO
#define ENCODER_1_DT_PORT_IO CONFIG_ENCODER_1_DT_PORT_IO
#define ENCODER_1_SW_PORT_IO CONFIG_ENCODER_1_SW_PORT_IO
#define ENCODER_INT_GPIO GPIO_NUM_3
#define ESP_INTR_FLAG_DEFAULT 0
#define RISING_EDGE_NOT_ROTATING 0b00000000
#define RISING_EDGE_CLOCKWISE 0b10000000
#define RISING_EDGE_COUNTER_CLOCKWISE 0b11000000
#define RISING_EDGE_ROTATING_MASK 0b11000000
#define FALLING_EDGE_NOT_ROTATING 0b00000000
#define FALLING_EDGE_CLOCKWISE 0b00100000
#define FALLING_EDGE_COUNTER_CLOCKWISE 0b00110000
#define FALLING_EDGE_ROTATING_MASK 0b00110000
static const char *UI_INPUT_TAG = "UiInput";
static QueueHandle_t ui_input_event = NULL;
static QueueHandle_t ui_input_raw_event = NULL;
typedef struct encoder_state {
e_ui_input_raw_key_t key;
uint8_t bits; // rising_edge_rotation_direction,
// falling_edge_rotation_direction, dt, clk, sw
uint8_t value; // dt, clk, sw
} encoder_state_t;
static encoder_state_t encoder_0_state = {.key = ui_input_raw_key_encoder_0,
.bits = 0};
static encoder_state_t encoder_1_state = {.key = ui_input_raw_key_encoder_1,
.bits = 0};
uint8_t level_byte;
int8_t delta = 0;
int64_t ec0_last_time = 0;
int64_t ec1_last_time = 0;
int64_t ec0_interval = 0;
int64_t ec1_interval = 0;
static void IRAM_ATTR gpio_isr_handler(void *arg) {
xQueueSendFromISR(ui_input_raw_event, NULL, NULL);
}
static void ui_input_update_embedded_display(void *arg) {
s_ui_input_t input;
char changing_str[20] = "NC";
for (;;) {
if (xQueueReceive(ui_input_event, &input, portMAX_DELAY)) {
switch (input.key) {
case ui_input_key_display_0_brightness:
sprintf(changing_str, "Dis0: % 3d", input.value);
break;
case ui_input_key_display_1_brightness:
sprintf(changing_str, "Dis1: % 3d", input.value);
break;
case ui_input_key_computer_volume:
sprintf(changing_str, "CVol: % 3d", input.value);
break;
case ui_input_key_display_ambient_lighting_level:
break;
case ui_input_key_display_ambient_lighting_mode:
sprintf(changing_str, "ALMd: % 3d", input.value);
break;
case ui_input_key_display_0_mode:
sprintf(changing_str, "Dis0M: % 2d", input.value);
break;
case ui_input_key_display_1_mode:
sprintf(changing_str, "Dis1M: % 2d", input.value);
break;
default:
strcpy(changing_str, "NC");
break;
}
ESP_LOGI(UI_INPUT_TAG, "%s", changing_str);
}
}
}
static void encoder_value_change(encoder_state_t *state) {
if ((state->value >> 1 & 1) == (state->bits >> 1 & 1)) {
return;
}
state->bits = (state->bits & 0b11111000) | (state->value & 0b111);
if (state->value >> 1 & 1) {
state->bits = (state->bits & (~RISING_EDGE_ROTATING_MASK)) | 0x80 |
~(state->value >> 2 & 1) << 6;
if (((state->bits & FALLING_EDGE_ROTATING_MASK) >> 4) ==
((state->bits & RISING_EDGE_ROTATING_MASK) >> 6)) {
if ((state->bits & RISING_EDGE_ROTATING_MASK) == RISING_EDGE_CLOCKWISE) {
delta = -1;
} else {
delta = 1;
}
state->bits = (state->bits & (~FALLING_EDGE_ROTATING_MASK)) |
FALLING_EDGE_NOT_ROTATING;
} else {
delta = 0;
if ((state->bits & FALLING_EDGE_ROTATING_MASK) !=
FALLING_EDGE_NOT_ROTATING) {
state->bits = (state->bits & (~FALLING_EDGE_ROTATING_MASK)) |
FALLING_EDGE_NOT_ROTATING;
}
}
} else {
state->bits = (state->bits & (~FALLING_EDGE_ROTATING_MASK)) | 0x20 |
(state->value >> 2 & 1) << 4;
if (((state->bits & FALLING_EDGE_ROTATING_MASK) >> 4) ==
((state->bits & RISING_EDGE_ROTATING_MASK) >> 6)) {
if ((state->bits & FALLING_EDGE_ROTATING_MASK) ==
FALLING_EDGE_CLOCKWISE) {
delta = -1;
} else {
delta = 1;
}
state->bits = (state->bits & (~RISING_EDGE_ROTATING_MASK)) |
RISING_EDGE_NOT_ROTATING;
} else {
delta = 0;
if ((state->bits & RISING_EDGE_ROTATING_MASK) !=
RISING_EDGE_NOT_ROTATING) {
state->bits = (state->bits & (~RISING_EDGE_ROTATING_MASK)) |
RISING_EDGE_NOT_ROTATING;
}
}
}
if (delta == 0) {
return;
}
s_ui_input_t event = {.value = delta};
if (state->key == ui_input_raw_key_encoder_0) {
ec0_interval = esp_timer_get_time() - ec0_last_time;
if (ec0_interval < 10000) { // 100ms
event.value = event.value * 5;
} else if (ec0_interval < 20000) { // 100ms
event.value = event.value * 4;
} else if (ec0_interval < 50000) { // 100ms
event.value = event.value * 3;
} else if (ec0_interval < 100000) { // 100ms
event.value = event.value * 2;
}
ec0_last_time = esp_timer_get_time();
if (state->value & 1) {
event.key = ui_input_key_computer_volume;
} else {
event.key = ui_input_key_display_1_brightness;
}
} else if (state->key == ui_input_raw_key_encoder_1) {
if (state->value & 1) {
ec1_interval = esp_timer_get_time() - ec1_last_time;
if (ec1_interval < 20000) { // 100ms
event.value = event.value * 7;
} else if (ec1_interval < 30000) { // 100ms
event.value = event.value * 5;
} else if (ec1_interval < 40000) { // 100ms
event.value = event.value * 3;
} else if (ec1_interval < 50000) {
event.value = event.value * 2;
}
ec1_last_time = esp_timer_get_time();
event.key = ui_input_key_display_ambient_lighting_level;
led_strip_set_brightness(display_ambient_lighting_level + event.value);
gui_change_strip_level(display_ambient_lighting_level);
} else {
event.key = ui_input_key_display_0_brightness;
}
}
xQueueSend(ui_input_event, &event, NULL);
ESP_LOGD(UI_INPUT_TAG, "key: %d, delta: %d. delay: %lld, %lld", state->key,
event.value, ec0_interval, ec1_interval);
}
static void ui_input_raw_handler(void *arg) {
for (;;) {
if (xQueueReceive(ui_input_raw_event, NULL, portMAX_DELAY)) {
pca9555_read_one_input(PCA95555_CMD_INPUT_PORT_1, &level_byte);
encoder_0_state.value = level_byte & 0x7;
encoder_value_change(&encoder_0_state);
encoder_1_state.value = level_byte >> 3 & 0x7;
encoder_value_change(&encoder_1_state);
}
}
}
void ui_input_init(void) {
// zero-initialize the config structure.
gpio_config_t io_conf = {};
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pull_up_en = 1;
io_conf.pull_down_en = 0;
// interrupt of rising edge
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.pin_bit_mask = 1ULL << ENCODER_INT_GPIO;
gpio_config(&io_conf);
// start encoder task
ui_input_event = xQueueCreate(5, sizeof(s_ui_input_t));
ui_input_raw_event = xQueueCreate(10, 0);
// hook isr handler for specific gpio pin
gpio_isr_handler_add(ENCODER_INT_GPIO, gpio_isr_handler, NULL);
// xTaskCreate(ui_input_update_embedded_display, "ui_input_event", 2048, NULL,
// 10, NULL);
xTaskCreate(ui_input_raw_handler, "ui_input_event", 2048, NULL, 10, NULL);
}