diff --git a/.vscode/settings.json b/.vscode/settings.json index 69f7b9d..818b670 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,7 @@ "idf.openOcdConfigs": [ "board/esp32c3-builtin.cfg" ], - "idf.port": "/dev/cu.usbserial-14910", + "idf.port": "/dev/cu.usbmodem149201", "idf.pythonBinPath": "/Users/ivan/.espressif/python_env/idf4.4_py3.8_env/bin/python", "idf.toolsPath": "/Users/ivan/.espressif", "idf.gitPath": "/usr/bin/git", diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 11efc7b..52596c7 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "mqtt.c" "main.c" "wifi.c" "light.c" "mqtt.c" +idf_component_register(SRCS "ui.c" "mqtt.c" "main.c" "wifi.c" "light.c" "mqtt.c" INCLUDE_DIRS ".") \ No newline at end of file diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 1f5ed36..5d6a51a 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -62,4 +62,45 @@ menu "MQTT Configuration" help URL of the broker to connect to +endmenu + +menu "GPIO Configuration" + config ENCODER_0_CLK_PIN + int "encoder 0 click GPIO" + range 1 32 + default 2 + help + Encoder 0 clock pin + config ENCODER_0_DT_PIN + int "encoder 0 data GPIO" + range 1 32 + default 3 + help + Encoder 0 clock data + config ENCODER_0_SW_PIN + int "encoder 0 switch GPIO" + range 1 32 + default 4 + help + Encoder 0 switch pin + + config ENCODER_1_CLK_PIN + int "encoder 1 click GPIO" + range 1 32 + default 5 + help + Encoder 1 clock pin + config ENCODER_1_DT_PIN + int "encoder 1 data GPIO" + range 1 32 + default 6 + help + Encoder 1 clock data + config ENCODER_1_SW_PIN + int "encoder 1 switch GPIO" + range 1 32 + default 7 + help + Encoder 1 switch pin + endmenu \ No newline at end of file diff --git a/main/main.c b/main/main.c index ac6db2a..e5f36d1 100644 --- a/main/main.c +++ b/main/main.c @@ -10,6 +10,8 @@ static const char *TAG = "DisplayAmbientLight"; void app_main(void) { light_init_strip(); + init_ui(); + xTaskCreate(publish_ui_input, "ui_input_event", 2048, NULL, 10, NULL); vTaskDelay(pdMS_TO_TICKS(10)); light_play(light_mode_connection_wifi); if (connect_wifi()) { diff --git a/main/mqtt.c b/main/mqtt.c index 7e44e2a..48a1387 100644 --- a/main/mqtt.c +++ b/main/mqtt.c @@ -2,6 +2,7 @@ #include #include +#include "cJSON.h" #include "esp_bit_defs.h" #include "esp_event.h" #include "esp_log.h" @@ -12,6 +13,7 @@ #include "freertos/semphr.h" #include "freertos/task.h" #include "mqtt_client.h" +#include "ui.c" #define MQTT_BROKER_URL CONFIG_MQTT_BROKER_URL #define NUMBER_OF_LEDS CONFIG_NUMBER_OF_LEDS @@ -31,6 +33,7 @@ #define MQTT_ALL_SUFFIX "#" #define MQTT_KEY_BOARD_ONLINE MQTT_BOARD_KEY_PREFIX MQTT_ONLINE_SUFFIX +#define MQTT_KEY_DISPLAY_BRIGHTNESS_INPUT MQTT_BOARD_KEY_PREFIX "brightness" #define MQTT_KEY_DESKTOP_ONLINE MQTT_DESKTOP_KEY_PREFIX MQTT_ONLINE_SUFFIX #define MQTT_KEY_DESKTOP_COLORS MQTT_DESKTOP_KEY_PREFIX MQTT_COLORS_SUFFIX #define MQTT_KEY_DESKTOP_ALL MQTT_DESKTOP_KEY_PREFIX MQTT_ALL_SUFFIX @@ -38,6 +41,7 @@ static const char *MQTT_TAG = "DisplayAmbientLight_MQTT"; static EventGroupHandle_t s_mqtt_event_group; +static esp_mqtt_client_handle_t client = NULL; typedef struct colors { uint8_t *buffer; @@ -57,7 +61,7 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, ESP_LOGD(MQTT_TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); esp_mqtt_event_handle_t event = event_data; - esp_mqtt_client_handle_t client = event->client; + client = event->client; int msg_id; switch ((esp_mqtt_event_id_t)event_id) { case MQTT_EVENT_CONNECTED: @@ -187,4 +191,32 @@ static bool waiting_and_get_colors() { ESP_LOGE(MQTT_TAG, "UNEXPECTED EVENT"); return 0; } +} + +static void publish_ui_input(void *arg) { + s_ui_input_t input; + for (;;) { + if (xQueueReceive(ui_input_event, &input, portMAX_DELAY)) { + switch (input.key) { + case UI_INPUT_DISPLAY_0_BRIGHTNESS: + case UI_INPUT_DISPLAY_1_BRIGHTNESS: { + cJSON *publish_json_root, *brightness; + publish_json_root = cJSON_CreateObject(); + cJSON_AddNumberToObject( + publish_json_root, "display_index", + UI_INPUT_DISPLAY_0_BRIGHTNESS == input.key ? 0 : 1); + cJSON_AddItemToObject(publish_json_root, "brightness", + brightness = cJSON_CreateObject()); + cJSON_AddNumberToObject(brightness, "Absolute", input.value); + char *publish_str = cJSON_Print(publish_json_root); + cJSON_Delete(publish_json_root); + esp_mqtt_client_publish(client, MQTT_KEY_DISPLAY_BRIGHTNESS_INPUT, + publish_str, 0, 1, 0); + } break; + + default: + break; + } + } + } } \ No newline at end of file diff --git a/main/ui.c b/main/ui.c new file mode 100644 index 0000000..0da6a6a --- /dev/null +++ b/main/ui.c @@ -0,0 +1,170 @@ +#include +#include +#include + +#include "driver/gpio.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "freertos/task.h" + +#define GPIO_OUTPUT_IO_0 5 +#define GPIO_OUTPUT_IO_1 6 +#define GPIO_OUTPUT_PIN_SEL \ + ((1ULL << GPIO_OUTPUT_IO_0) | (1ULL << GPIO_OUTPUT_IO_1)) +#define ENCODER_0_CLK_PIN CONFIG_ENCODER_0_CLK_PIN +#define ENCODER_0_DT_PIN CONFIG_ENCODER_0_DT_PIN +#define ENCODER_0_CLK_PIN_MASK 1ULL << ENCODER_0_CLK_PIN +#define ENCODER_0_DT_PIN_MASK 1ULL << ENCODER_0_DT_PIN +#define ENCODER_1_CLK_PIN CONFIG_ENCODER_1_CLK_PIN +#define ENCODER_1_DT_PIN CONFIG_ENCODER_1_DT_PIN +#define ENCODER_1_CLK_PIN_MASK 1ULL << ENCODER_1_CLK_PIN +#define ENCODER_1_DT_PIN_MASK 1ULL << ENCODER_1_DT_PIN +#define ESP_INTR_FLAG_DEFAULT 0 + +#define NOT_ROTATING -1 +#define CLOCKWISE 1 +#define COUNTER_CLOCKWISE 0 + +#define UI_INPUT_DISPLAY_0_BRIGHTNESS 1 +#define UI_INPUT_DISPLAY_1_BRIGHTNESS 2 + +typedef struct s_ui_input { + uint8_t key; + uint16_t value; +} s_ui_input_t; + +static xQueueHandle encoder_event_queue = NULL; +static xQueueHandle ui_input_event = NULL; + +static void IRAM_ATTR gpio_isr_handler(void* arg) { + uint8_t input_key = (uint8_t)arg; + xQueueSendFromISR(encoder_event_queue, &input_key, NULL); +} + +static int8_t rising_edge_rotation_direction = NOT_ROTATING; +static int8_t falling_edge_rotation_direction = NOT_ROTATING; +static int8_t display_0_brightness = 20; +static int8_t display_1_brightness = 20; + +static s_ui_input_t current_ui_input = {}; + +static void encoder_value_change(void* arg) { + uint8_t input_key; + uint8_t clk_pin = ENCODER_0_CLK_PIN; + uint8_t dt_pin = ENCODER_0_DT_PIN; + uint8_t* value = &display_0_brightness; + for (;;) { + if (xQueueReceive(encoder_event_queue, &input_key, portMAX_DELAY)) { + switch (input_key) { + case UI_INPUT_DISPLAY_0_BRIGHTNESS: + clk_pin = ENCODER_0_CLK_PIN; + dt_pin = ENCODER_0_DT_PIN; + value = &display_0_brightness; + break; + case UI_INPUT_DISPLAY_1_BRIGHTNESS: + clk_pin = ENCODER_1_CLK_PIN; + dt_pin = ENCODER_1_DT_PIN; + value = &display_1_brightness; + break; + default: + break; + } + if (gpio_get_level(clk_pin)) { + rising_edge_rotation_direction = gpio_get_level(dt_pin) == 0; + // printf("R %d\t", rising_edge_rotation_direction); + if (falling_edge_rotation_direction == rising_edge_rotation_direction) { + if (rising_edge_rotation_direction) { + gpio_set_level(GPIO_OUTPUT_IO_0, 1); + gpio_set_level(GPIO_OUTPUT_IO_1, 0); + *value += 1; + printf("CW\tvalue: %d\n", *value); + } else { + gpio_set_level(GPIO_OUTPUT_IO_0, 0); + gpio_set_level(GPIO_OUTPUT_IO_1, 1); + *value -= 1; + printf("CCW\tvalue: %d\n", *value); + } + falling_edge_rotation_direction = NOT_ROTATING; + + current_ui_input.key = input_key; + current_ui_input.value = *value; + xQueueSend(ui_input_event, ¤t_ui_input, NULL); + } else { + if (falling_edge_rotation_direction != NOT_ROTATING) { + rising_edge_rotation_direction = NOT_ROTATING; + } + } + } else { + falling_edge_rotation_direction = gpio_get_level(dt_pin); + // printf("F %d\t", falling_edge_rotation_direction); + if (rising_edge_rotation_direction == falling_edge_rotation_direction) { + if (falling_edge_rotation_direction) { + gpio_set_level(GPIO_OUTPUT_IO_0, 1); + gpio_set_level(GPIO_OUTPUT_IO_1, 0); + *value += 1; + printf("CW\tvalue: %d\n", *value); + } else { + gpio_set_level(GPIO_OUTPUT_IO_0, 0); + gpio_set_level(GPIO_OUTPUT_IO_1, 1); + *value -= 1; + printf("CCW\tvalue: %d\n", *value); + } + rising_edge_rotation_direction = NOT_ROTATING; + + current_ui_input.key = input_key; + current_ui_input.value = *value; + xQueueSend(ui_input_event, ¤t_ui_input, NULL); + + } else { + if (rising_edge_rotation_direction != NOT_ROTATING) { + falling_edge_rotation_direction = NOT_ROTATING; + } + } + } + } + } +} + +void init_ui(void) { + // zero-initialize the config structure. + gpio_config_t io_conf = {}; + // disable interrupt + io_conf.intr_type = GPIO_INTR_DISABLE; + // set as output mode + io_conf.mode = GPIO_MODE_OUTPUT; + // bit mask of the pins that you want to set,e.g.GPIO18/19 + io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL; + // disable pull-down mode + io_conf.pull_down_en = 0; + // disable pull-up mode + io_conf.pull_up_en = 0; + // configure GPIO with the given settings + gpio_config(&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_ANYEDGE; + io_conf.pin_bit_mask = ENCODER_0_CLK_PIN_MASK | ENCODER_1_CLK_PIN_MASK; + gpio_config(&io_conf); + io_conf.intr_type = GPIO_INTR_DISABLE; + io_conf.pin_bit_mask = ENCODER_0_DT_PIN_MASK | ENCODER_1_DT_PIN_MASK; + gpio_config(&io_conf); + + // create a queue to handle gpio event from isr + encoder_event_queue = xQueueCreate(10, sizeof(uint8_t)); + // start encoder task + xTaskCreate(encoder_value_change, "encoder_value_change", 2048, NULL, 10, + NULL); + ui_input_event = xQueueCreate(10, sizeof(s_ui_input_t)); + + // install gpio isr service + gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); + // hook isr handler for specific gpio pin + gpio_isr_handler_add(ENCODER_0_CLK_PIN, gpio_isr_handler, + (void*)UI_INPUT_DISPLAY_0_BRIGHTNESS); + // hook isr handler for specific gpio pin + gpio_isr_handler_add(ENCODER_1_CLK_PIN, gpio_isr_handler, + (void*)UI_INPUT_DISPLAY_1_BRIGHTNESS); +}