From db0e997aad3d62c7ded7c0adc029a5c54ae57dfc Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Sat, 14 Jun 2025 08:33:02 +0300 Subject: [PATCH] wip: --- include/zh_encoder.h | 48 +++++++++++++--- zh_encoder.c | 129 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 167 insertions(+), 10 deletions(-) diff --git a/include/zh_encoder.h b/include/zh_encoder.h index 5dec487..dc7aa62 100644 --- a/include/zh_encoder.h +++ b/include/zh_encoder.h @@ -23,6 +23,33 @@ extern "C" { #endif + typedef int32_t rotary_encoder_position_t; + + // /** + // * @brief Enum representing the direction of rotation. + // */ + typedef enum + { + ROTARY_ENCODER_DIRECTION_NOT_SET = 0, ///< Direction not yet known (stationary since reset) + ROTARY_ENCODER_DIRECTION_CLOCKWISE, + ROTARY_ENCODER_DIRECTION_COUNTER_CLOCKWISE, + } rotary_encoder_direction_t; + +// // Used internally +// ///@cond INTERNAL +#define TABLE_COLS 4 + typedef uint8_t table_row_t[TABLE_COLS]; + // ///@endcond + + // /** + // * @brief Struct represents the current state of the device in terms of incremental position and direction of last movement + // */ + typedef struct + { + rotary_encoder_position_t position; ///< Numerical position since reset. This value increments on clockwise rotation, and decrements on counter-clockewise rotation. Counts full or half steps depending on mode. Set to zero on reset. + rotary_encoder_direction_t direction; ///< Direction of last movement. Set to NOT_SET on reset. + } rotary_encoder_state_t; + typedef struct // Structure for initial initialization of encoder. { uint8_t task_priority; // Task priority for the encoder isr processing. @note It is not recommended to set a value less than 10. @@ -47,6 +74,9 @@ extern "C" uint8_t encoder_number; // Encoder unique number. bool is_initialized; // Encoder initialization flag. + const table_row_t *table; ///< Pointer to active state transition table + uint8_t table_state; ///< Internal state + volatile rotary_encoder_state_t state; ///< Device state } zh_encoder_handle_t; ESP_EVENT_DECLARE_BASE(ZH_ENCODER); @@ -115,9 +145,9 @@ extern "C" // typedef int32_t rotary_encoder_position_t; -// /** -// * @brief Enum representing the direction of rotation. -// */ +// // /** +// // * @brief Enum representing the direction of rotation. +// // */ // typedef enum // { // ROTARY_ENCODER_DIRECTION_NOT_SET = 0, ///< Direction not yet known (stationary since reset) @@ -125,15 +155,15 @@ extern "C" // ROTARY_ENCODER_DIRECTION_COUNTER_CLOCKWISE, // } rotary_encoder_direction_t; -// // Used internally -// ///@cond INTERNAL +// // // Used internally +// // ///@cond INTERNAL // #define TABLE_COLS 4 // typedef uint8_t table_row_t[TABLE_COLS]; -// ///@endcond +// // ///@endcond -// /** -// * @brief Struct represents the current state of the device in terms of incremental position and direction of last movement -// */ +// // /** +// // * @brief Struct represents the current state of the device in terms of incremental position and direction of last movement +// // */ // typedef struct // { // rotary_encoder_position_t position; ///< Numerical position since reset. This value increments on clockwise rotation, and decrements on counter-clockewise rotation. Counts full or half steps depending on mode. Set to zero on reset. diff --git a/zh_encoder.c b/zh_encoder.c index ace3e39..e4742d2 100644 --- a/zh_encoder.c +++ b/zh_encoder.c @@ -104,9 +104,15 @@ esp_err_t zh_encoder_init(const zh_encoder_init_config_t *config, zh_encoder_han { _zh_encoder_validate_config(config); _zh_encoder_gpio_init(config); + handle->a_gpio_number = config->a_gpio_number; + handle->b_gpio_number = config->b_gpio_number; _zh_encoder_configure_interrupts(config, handle); _zh_encoder_init_resources(config); _zh_encoder_create_task(config); + handle->table = &_encoder_matrix[0]; // enable_half_step ? &_ttable_half[0] : &_ttable_full[0]; + handle->table_state = R_START; + handle->state.position = 0; + handle->state.direction = ROTARY_ENCODER_DIRECTION_NOT_SET; return ESP_OK; } @@ -365,6 +371,8 @@ static esp_err_t _zh_encoder_configure_interrupts(const zh_encoder_init_config_t ZH_ENCODER_CHECK(err == ESP_OK, err, "Interrupt initialization failed."); err = gpio_isr_handler_add(config->b_gpio_number, _zh_encoder_isr_handler, handle); ZH_ENCODER_CHECK(err == ESP_OK, err, "Interrupt initialization failed."); + // printf("queue.b_gpio_number %d\n", handle->b_gpio_number); + // printf("queue.q_gpio_number %d\n", handle->a_gpio_number); return ESP_OK; } @@ -397,8 +405,36 @@ static esp_err_t _zh_encoder_create_task(const zh_encoder_init_config_t *config) static void _zh_encoder_isr_handler(void *arg) { + zh_encoder_handle_t *queue = (zh_encoder_handle_t *)arg; BaseType_t xHigherPriorityTaskWoken = pdFALSE; - xQueueSendFromISR(_queue_handle, arg, &xHigherPriorityTaskWoken); + uint8_t pin_state = (gpio_get_level(queue->b_gpio_number) << 1) | gpio_get_level(queue->a_gpio_number); + // printf("pin_state %d\n", pin_state); + queue->table_state = queue->table[queue->table_state & 0xf][pin_state]; + uint8_t event = queue->table_state & 0x30; + switch (event) + { + case DIR_CW: + ++queue->state.position; + queue->state.direction = ROTARY_ENCODER_DIRECTION_CLOCKWISE; + // printf("event %d\n", event); + // send_event = true; + // printf("state.position %ld\n", queue->state.position); + xQueueSendFromISR(_queue_handle, queue, &xHigherPriorityTaskWoken); + break; + case DIR_CCW: + --queue->state.position; + queue->state.direction = ROTARY_ENCODER_DIRECTION_COUNTER_CLOCKWISE; + // printf("event %d\n", event); + // send_event = true; + // printf("state.position %ld\n", queue.state.position); + xQueueSendFromISR(_queue_handle, queue, &xHigherPriorityTaskWoken); + break; + default: + break; + } + + // BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // xQueueSendFromISR(_queue_handle, queue, &xHigherPriorityTaskWoken); if (xHigherPriorityTaskWoken == pdTRUE) { portYIELD_FROM_ISR(); @@ -407,4 +443,95 @@ static void _zh_encoder_isr_handler(void *arg) static void _zh_encoder_isr_processing_task(void *pvParameter) { + zh_encoder_handle_t queue = {0}; + while (xQueueReceive(_queue_handle, &queue, portMAX_DELAY) == pdTRUE) + { + // printf("queue.b_gpio_number %d\n", queue.b_gpio_number); + // printf("queue.q_gpio_number %d\n", queue.a_gpio_number); + // uint8_t pin_state = (gpio_get_level(queue.b_gpio_number) << 1) | gpio_get_level(queue.a_gpio_number); + // // printf("pin_state %d\n", pin_state); + // queue.table_state = queue.table[queue.table_state & 0xf][pin_state]; + // uint8_t event = queue.table_state & 0x30; + // switch (event) + // { + // case DIR_CW: + // ++queue.state.position; + // queue.state.direction = ROTARY_ENCODER_DIRECTION_CLOCKWISE; + // printf("event %d\n", event); + // // send_event = true; + // printf("state.position %ld\n", queue.state.position); + // break; + // case DIR_CCW: + // --queue.state.position; + // queue.state.direction = ROTARY_ENCODER_DIRECTION_COUNTER_CLOCKWISE; + // printf("event %d\n", event); + // // send_event = true; + // printf("state.position %ld\n", queue.state.position); + // break; + // default: + // break; + // } + printf("state.position %ld\n", queue.state.position); + } + vTaskDelete(NULL); + + // rotary_encoder_info_t *info = (rotary_encoder_info_t *)args; + + // uint8_t event = 0; + // if (info != NULL) + // { + // // Get state of input pins. + // uint8_t pin_state = (gpio_get_level(info->pin_b) << 1) | gpio_get_level(info->pin_a); + + // // Determine new state from the pins and state table. + // #ifdef ROTARY_ENCODER_DEBUG + // uint8_t old_state = info->table_state; + // #endif + // queue.table_state = queue.table[queue.table_state & 0xf][pin_state]; + + // // Return emit bits, i.e. the generated event. + // event = queue.table_state & 0x30; + // #ifdef ROTARY_ENCODER_DEBUG + // ESP_EARLY_LOGD(TAG, "BA %d%d, state 0x%02x, new state 0x%02x, event 0x%02x", + // pin_state >> 1, pin_state & 1, old_state, info->table_state, event); + // #endif + // } + // return event; + + // uint8_t event = _process(info); + // bool send_event = false; + + // switch (event) + // { + // case DIR_CW: + // ++info->state.position; + // info->state.direction = ROTARY_ENCODER_DIRECTION_CLOCKWISE; + // // send_event = true; + // break; + // case DIR_CCW: + // --info->state.position; + // info->state.direction = ROTARY_ENCODER_DIRECTION_COUNTER_CLOCKWISE; + // send_event = true; + // break; + // default: + // break; + // } + + // if (send_event && info->queue) + // { + // rotary_encoder_event_t queue_event = + // { + // .state = + // { + // .position = info->state.position, + // .direction = info->state.direction, + // }, + // }; + // BaseType_t task_woken = pdFALSE; + // xQueueSendFromISR(info->queue, &queue_event, &task_woken); + // if (task_woken) + // { + // portYIELD_FROM_ISR(); + // } + // } } \ No newline at end of file