From eb70315c9a82c2adea86a6491eecad4237906510 Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Sun, 4 Oct 2026 20:27:24 +0300 Subject: [PATCH] perf: updated error checks --- README.md | 10 ----- include/zh_pcf8574.h | 48 +++++++++++++----------- zh_pcf8574.c | 89 +++++++++++++++++++++++--------------------- 3 files changed, 73 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index c340fd2..337f9b6 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,6 @@ 4. Event-based architecture using esp_event framework. 5. Statistics tracking for debugging and monitoring. -## Note - -Enable the following settings in menuconfig: - -```text -GPIO_CTRL_FUNC_IN_IRAM -I2C_ISR_IRAM_SAFE -I2C_MASTER_ISR_HANDLER_IN_IRAM -``` - ## Using In an existing project, run the following command to install the components: diff --git a/include/zh_pcf8574.h b/include/zh_pcf8574.h index c611484..d6445fe 100755 --- a/include/zh_pcf8574.h +++ b/include/zh_pcf8574.h @@ -16,7 +16,8 @@ * * @note The driver creates an internal task for interrupt processing. * @note Requires ESP-IDF v5.0+ with I2C master driver. - * @note Enable GPIO_CTRL_FUNC_IN_IRAM, I2C_ISR_IRAM_SAFE and I2C_MASTER_ISR_HANDLER_IN_IRAM in menuconfig. + * @warning All I2C and GPIO operations run in thread context with ESP_INTR_FLAG_LOWMED, so the + * interrupt service is not IRAM-safe and does not execute from IRAM. */ #pragma once @@ -39,7 +40,7 @@ { \ .task_priority = 1, \ .stack_size = configMINIMAL_STACK_SIZE, \ - .i2c_address = 0xFF, \ + .i2c_address = 0x20, \ .i2c_frequency = 100000, \ .p0_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \ .p1_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \ @@ -56,7 +57,7 @@ extern "C" { #endif - extern TaskHandle_t zh_pcf8574; /*!< Handle of the internal PCF8574 processing task. */ + extern TaskHandle_t zh_pcf8574; /*!< Handle of the internal PCF8574 processing task */ /** * @brief Opaque handle for PCF8574 device instance. @@ -125,7 +126,7 @@ extern "C" uint32_t event_post_error; /*!< Counter of event posting errors */ uint32_t vector_error; /*!< Counter of vector operation errors */ uint32_t queue_overflow_error; /*!< Counter of queue overflow errors */ - uint32_t min_stack_size; /*!< Minimum remaining stack size recorded */ + uint32_t min_stack_size; /*!< Minimum remaining stack size in words since last reset */ } zh_pcf8574_stats_t; ESP_EVENT_DECLARE_BASE(ZH_PCF8574); @@ -152,11 +153,11 @@ extern "C" * provided configuration. * * @param[in] config Pointer to initialization configuration structure (must not be NULL) - * @param[out] handle Pointer to receive the device handle (must be NULL) + * @param[in,out] handle Pointer to the device handle (must not be NULL, the handle it points to must be NULL) * * @return ESP_OK on success - * @return ESP_ERR_INVALID_ARG if config is NULL or handle points to non-NULL - * @return ESP_ERR_INVALID_STATE if device is already initialized + * @return ESP_ERR_INVALID_ARG if config is NULL or handle is NULL + * @return ESP_ERR_INVALID_STATE if the handle pointed to by handle is not NULL * @return ESP_ERR_NO_MEM if memory allocation fails * @return ESP_FAIL if configuration validation, I2C communication, or task creation fails */ @@ -168,10 +169,10 @@ extern "C" * Releases I2C resources and the device handle. Deletes the internal * task only when the last device instance is deinitialized. * - * @param[in] handle Pointer to the device handle (must not be NULL) + * @param[in] handle Pointer to the device handle (must not be NULL, the handle it points to must not be NULL) * * @return ESP_OK on success - * @return ESP_ERR_INVALID_ARG if handle is NULL + * @return ESP_ERR_INVALID_ARG if handle is NULL or the handle it points to is NULL * @return ESP_ERR_NOT_FOUND if handle does not correspond to a valid device instance * @return ESP_FAIL if I2C removal or vector operations fail */ @@ -183,11 +184,11 @@ extern "C" * Reads a byte from the PCF8574 input ports via I2C communication * and updates the internal device state. * - * @param[in] handle Pointer to the device handle (must not be NULL) + * @param[in] handle Pointer to the device handle (must not be NULL, the handle it points to must not be NULL) * @param[out] reg Pointer to receive the read value (must not be NULL) * * @return ESP_OK on success - * @return ESP_ERR_INVALID_ARG if handle or reg is NULL + * @return ESP_ERR_INVALID_ARG if handle or reg is NULL or the handle it points to is NULL * @return ESP_ERR_NOT_FOUND if handle does not correspond to a valid device instance * @return ESP_FAIL if I2C communication or vector operations fail */ @@ -199,11 +200,11 @@ extern "C" * Writes a byte to the PCF8574 output ports via I2C communication * and updates the internal device state. * - * @param[in] handle Pointer to the device handle (must not be NULL) + * @param[in] handle Pointer to the device handle (must not be NULL, the handle it points to must not be NULL) * @param[in] reg Value to write to the output ports * * @return ESP_OK on success - * @return ESP_ERR_INVALID_ARG if handle is NULL + * @return ESP_ERR_INVALID_ARG if handle is NULL or the handle it points to is NULL * @return ESP_ERR_NOT_FOUND if handle does not correspond to a valid device instance * @return ESP_FAIL if I2C communication or vector operations fail */ @@ -212,13 +213,14 @@ extern "C" /** * @brief Reset PCF8574 device. * - * Resets all outputs to their default input configuration + * Writes the configured GPIO direction mask to the port, returning + * output pins to their low level and input pins to their high level, * and updates the internal device state. * - * @param[in] handle Pointer to the device handle (must not be NULL) + * @param[in] handle Pointer to the device handle (must not be NULL, the handle it points to must not be NULL) * * @return ESP_OK on success - * @return ESP_ERR_INVALID_ARG if handle is NULL + * @return ESP_ERR_INVALID_ARG if handle is NULL or the handle it points to is NULL * @return ESP_ERR_NOT_FOUND if handle does not correspond to a valid device instance * @return ESP_FAIL if I2C communication or vector operations fail */ @@ -229,13 +231,14 @@ extern "C" * * Reads the current logical level of a specified GPIO pin. * - * @param[in] handle Pointer to the device handle (must not be NULL) + * @param[in] handle Pointer to the device handle (must not be NULL, the handle it points to must not be NULL) * @param[in] gpio GPIO pin number to read * @param[out] status Pointer to receive the pin state (true = high, false = low) * * @return ESP_OK on success - * @return ESP_ERR_INVALID_ARG if handle or status is NULL - * @return ESP_FAIL if gpio is invalid, handle is invalid, or I2C communication fails + * @return ESP_ERR_INVALID_ARG if handle or status is NULL or the handle it points to is NULL + * @return ESP_ERR_NOT_FOUND if handle does not correspond to a valid device instance + * @return ESP_FAIL if gpio is invalid or I2C communication fails */ esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t **handle, zh_pcf8574_gpio_num_t gpio, bool *status); @@ -244,13 +247,14 @@ extern "C" * * Sets the logical level of a specified GPIO pin configured as output. * - * @param[in] handle Pointer to the device handle (must not be NULL) + * @param[in] handle Pointer to the device handle (must not be NULL, the handle it points to must not be NULL) * @param[in] gpio GPIO pin number to write * @param[in] status Logical level to set (true = high, false = low) * * @return ESP_OK on success - * @return ESP_ERR_INVALID_ARG if handle is NULL - * @return ESP_FAIL if gpio is invalid, handle is invalid, or I2C communication fails + * @return ESP_ERR_INVALID_ARG if handle is NULL or the handle it points to is NULL + * @return ESP_ERR_NOT_FOUND if handle does not correspond to a valid device instance + * @return ESP_FAIL if gpio is invalid or I2C communication fails */ esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t **handle, zh_pcf8574_gpio_num_t gpio, bool status); diff --git a/zh_pcf8574.c b/zh_pcf8574.c index e065512..5f8e5b7 100755 --- a/zh_pcf8574.c +++ b/zh_pcf8574.c @@ -18,7 +18,6 @@ static const char *TAG = "zh_pcf8574"; { \ ZH_LOGE(msg, ESP_FAIL, ##__VA_ARGS__); \ cleanup; \ - continue; \ } /** @@ -26,6 +25,9 @@ static const char *TAG = "zh_pcf8574"; * * Minimal handle storing the I2C address of the device instance. * The full state is maintained in the internal vector. + * + * @note The handle is allocated by zh_pcf8574_init() and freed by zh_pcf8574_deinit(). + * @warning The handle becomes invalid after deinitialization and must not be used afterwards. */ struct _zh_pcf8574_handle_t { @@ -46,14 +48,14 @@ typedef struct i2c_master_dev_handle_t dev_handle; /*!< I2C device handle for communication */ } _zh_pcf8574_vector_data_t; -TaskHandle_t zh_pcf8574 = NULL; /*!< Handle of the internal PCF8574 processing task */ -static SemaphoreHandle_t _interrupt_semaphore = NULL; /*!< Semaphore for interrupt-to-task synchronization */ +TaskHandle_t zh_pcf8574 = NULL; +static SemaphoreHandle_t _interrupt_semaphore = NULL; -volatile static gpio_num_t _interrupt_gpio = GPIO_NUM_MAX; /*!< GPIO pin used for interrupt detection */ -static const uint8_t _gpio_matrix[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; /*!< Bit mask for each GPIO pin (P0-P7) */ -static zh_pcf8574_stats_t _stats = {0}; /*!< Statistics structure for error tracking */ +volatile static gpio_num_t _interrupt_gpio = GPIO_NUM_MAX; +static const uint8_t _gpio_matrix[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; +static zh_pcf8574_stats_t _stats = {0}; -static zh_vector_t *_vector = NULL; /*!< Vector storing PCF8574 device data */ +static zh_vector_t *_vector = NULL; /** * @brief Validate initialization configuration. @@ -123,7 +125,6 @@ static esp_err_t _zh_pcf8574_task_init(const zh_pcf8574_init_config_t *config); * * Called when an interrupt occurs on the configured GPIO pin. * Posts a signal to the semaphore to wake up the processing task. - * Executed in ISR context (IRAM). * * @param arg Unused callback argument */ @@ -134,7 +135,7 @@ static void _zh_pcf8574_isr_handler(void *arg); * * Waits for interrupt signals, reads all PCF8574 devices, detects * level changes on input pins, and posts events for each change. - * Monitors stack usage continuously. + * Updates the remaining stack size statistic after each iteration. * * @param pvParameter Unused task parameter */ @@ -184,25 +185,29 @@ esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_han ZH_ERROR_CHECK(_zh_pcf8574_i2c_init(config, &vector_data) == ESP_OK, ESP_FAIL, NULL, "PCF8574 initialization failed. Failed to add I2C device."); *handle = heap_caps_calloc(1, sizeof(zh_pcf8574_handle_t), MALLOC_CAP_8BIT); ZH_ERROR_CHECK(*handle != NULL, ESP_ERR_NO_MEM, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}, "PCF8574 initialization failed. Failed to allocate PCF8574 handle."); + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}, "PCF8574 initialization failed. Failed to allocate PCF8574 handle."); ZH_ERROR_CHECK(zh_vector_push_back(&_vector, &vector_data) == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}; + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}; heap_caps_free(*handle); *handle = NULL, "PCF8574 initialization failed. Failed to add vector data."); if (_interrupt_gpio == GPIO_NUM_MAX && config->interrupt_gpio < GPIO_NUM_MAX && vector_data.gpio_work_mode != 0) { - ZH_ERROR_CHECK(_zh_pcf8574_gpio_init(config) == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}; - zh_vector_delete_back(&_vector); heap_caps_free(*handle); *handle = NULL, "PCF8574 initialization failed. Interrupt GPIO initialization failed."); ZH_ERROR_CHECK(_zh_pcf8574_resources_init() == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}; - {ZH_ERROR_CHECK(gpio_isr_handler_remove(config->interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "Remove GPIO isr handler failed.")}; - {ZH_ERROR_CHECK(gpio_reset_pin(config->interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset GPIO failed.")}; - zh_vector_delete_back(&_vector); heap_caps_free(*handle); *handle = NULL, "PCF8574 initialization failed. Resources initialization failed."); + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}; + ZH_ERROR_CHECK_CONT(zh_vector_delete_back(&_vector) == ESP_OK, NULL, "Failed delete vector data."); + heap_caps_free(*handle); *handle = NULL, "PCF8574 initialization failed. Resources initialization failed."); + ZH_ERROR_CHECK(_zh_pcf8574_gpio_init(config) == ESP_OK, ESP_FAIL, + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}; + vSemaphoreDelete(_interrupt_semaphore); _interrupt_semaphore = NULL; + ZH_ERROR_CHECK_CONT(zh_vector_delete_back(&_vector) == ESP_OK, NULL, "Failed delete vector data."); + heap_caps_free(*handle); + *handle = NULL, "PCF8574 initialization failed. Interrupt GPIO initialization failed."); ZH_ERROR_CHECK(_zh_pcf8574_task_init(config) == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}; - {ZH_ERROR_CHECK(gpio_isr_handler_remove(config->interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "Remove gpio isr handler failed.")}; - {ZH_ERROR_CHECK(gpio_reset_pin(config->interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset gpio failed.")}; - vSemaphoreDelete(_interrupt_semaphore); _interrupt_semaphore = NULL; zh_vector_delete_back(&_vector); heap_caps_free(*handle); *handle = NULL, "PCF8574 initialization failed. Task initialization failed."); + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}; + {ZH_ERROR_CHECK_CONT(gpio_isr_handler_remove(config->interrupt_gpio) == ESP_OK, NULL, "Remove gpio isr handler failed.")}; + {ZH_ERROR_CHECK_CONT(gpio_reset_pin(config->interrupt_gpio) == ESP_OK, NULL, "Reset gpio failed.")}; + vSemaphoreDelete(_interrupt_semaphore); _interrupt_semaphore = NULL; + ZH_ERROR_CHECK_CONT(zh_vector_delete_back(&_vector) == ESP_OK, NULL, "Failed delete vector data."); + heap_caps_free(*handle); *handle = NULL, "PCF8574 initialization failed. Task initialization failed."); _interrupt_gpio = config->interrupt_gpio; } if (_stats.min_stack_size == 0) @@ -223,16 +228,16 @@ esp_err_t zh_pcf8574_deinit(zh_pcf8574_handle_t **handle) ZH_ERROR_CHECK(zh_vector_find_item_in_field(&_vector, &vector_data, &vector_data.i2c_address, sizeof(vector_data.i2c_address), &(*handle)->i2c_address, 0, &index) == ESP_OK, ESP_ERR_NOT_FOUND, NULL, "PCF8574 deinitialization failed. Failed to find vector item."); ZH_ERROR_CHECK(zh_vector_get_item(&_vector, (uint16_t)index, &vector_data) == ESP_OK, ESP_FAIL, NULL, "PCF8574 deinitialization failed. Failed to get vector item data."); - ZH_ERROR_CHECK(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, ESP_FAIL, NULL, "PCF8574 deinitialization failed. I2C remove device failed."); - ZH_ERROR_CHECK(zh_vector_delete_item(&_vector, (uint16_t)index) == ESP_OK, ESP_FAIL, NULL, "PCF8574 deinitialization failed. Vector delete item failed."); + ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(vector_data.dev_handle) == ESP_OK, NULL, "PCF8574 deinitialization failed. I2C remove device failed."); + ZH_ERROR_CHECK_CONT(zh_vector_delete_item(&_vector, (uint16_t)index) == ESP_OK, NULL, "PCF8574 deinitialization failed. Vector delete item failed."); uint16_t vector_size = 0; ZH_ERROR_CHECK(zh_vector_get_size(&_vector, &vector_size) == ESP_OK, ESP_FAIL, NULL, "PCF8574 deinitialization failed. Failed to get vector size."); if (vector_size == 0) { if (_interrupt_gpio != GPIO_NUM_MAX) { - ZH_ERROR_CHECK(gpio_isr_handler_remove(_interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "PCF8574 deinitialization failed. Remove GPIO isr handler failed."); - ZH_ERROR_CHECK(gpio_reset_pin(_interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "PCF8574 deinitialization failed. Reset GPIO failed."); + ZH_ERROR_CHECK_CONT(gpio_isr_handler_remove(_interrupt_gpio) == ESP_OK, NULL, "PCF8574 deinitialization failed. Remove GPIO isr handler failed."); + ZH_ERROR_CHECK_CONT(gpio_reset_pin(_interrupt_gpio) == ESP_OK, NULL, "PCF8574 deinitialization failed. Reset GPIO failed."); vTaskDelete(zh_pcf8574); zh_pcf8574 = NULL; vSemaphoreDelete(_interrupt_semaphore); @@ -322,11 +327,11 @@ esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t **handle, zh_pcf8574_gpio_nu ZH_ERROR_CHECK(zh_vector_get_item(&_vector, (uint16_t)index, &vector_data) == ESP_OK, ESP_FAIL, NULL, "PCF8574 write GPIO failed. Failed to get vector item data."); if (status == true) { - ZH_ERROR_CHECK(_zh_pcf8574_write_register(&vector_data, vector_data.gpio_status | vector_data.gpio_work_mode | _gpio_matrix[(uint8_t)gpio]) == ESP_OK, ESP_FAIL, NULL, "PCF8574 write GPIO failed. PCF8574 write register failed."); /*!< Set GPIO pin high, preserving work mode. */ + ZH_ERROR_CHECK(_zh_pcf8574_write_register(&vector_data, vector_data.gpio_status | vector_data.gpio_work_mode | _gpio_matrix[(uint8_t)gpio]) == ESP_OK, ESP_FAIL, NULL, "PCF8574 write GPIO failed. PCF8574 write register failed."); } else { - ZH_ERROR_CHECK(_zh_pcf8574_write_register(&vector_data, (vector_data.gpio_status & ~_gpio_matrix[(uint8_t)gpio]) | vector_data.gpio_work_mode) == ESP_OK, ESP_FAIL, NULL, "PCF8574 write GPIO failed. PCF8574 write register failed."); /*!< Clear GPIO pin, preserving work mode. */ + ZH_ERROR_CHECK(_zh_pcf8574_write_register(&vector_data, (vector_data.gpio_status & ~_gpio_matrix[(uint8_t)gpio]) | vector_data.gpio_work_mode) == ESP_OK, ESP_FAIL, NULL, "PCF8574 write GPIO failed. PCF8574 write register failed."); } ZH_ERROR_CHECK(zh_vector_change_item(&_vector, (uint16_t)index, &vector_data) == ESP_OK, ESP_FAIL, NULL, "PCF8574 write GPIO failed. Failed to change vector item data."); ZH_LOGI("PCF8574 write GPIO completed successfully."); @@ -352,7 +357,7 @@ void zh_pcf8574_reset_stats(void) static esp_err_t _zh_pcf8574_validate_config(const zh_pcf8574_init_config_t *config) { ZH_ERROR_CHECK((config->i2c_address >= 0x20 && config->i2c_address <= 0x27) || (config->i2c_address >= 0x38 && config->i2c_address <= 0x3F), ESP_ERR_INVALID_ARG, NULL, "Invalid I2C address."); - ZH_ERROR_CHECK(config->i2c_frequency <= 100000, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C frequency."); + ZH_ERROR_CHECK(config->i2c_frequency <= 100000 && config->i2c_frequency > 0, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C frequency."); ZH_ERROR_CHECK(config->task_priority >= 1 && config->stack_size >= configMINIMAL_STACK_SIZE, ESP_ERR_INVALID_ARG, NULL, "Invalid task settings."); ZH_ERROR_CHECK(config->interrupt_gpio <= GPIO_NUM_MAX, ESP_ERR_INVALID_ARG, NULL, "Invalid GPIO number."); ZH_ERROR_CHECK(config->i2c_handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C handle."); @@ -378,9 +383,9 @@ static esp_err_t _zh_pcf8574_gpio_init(const zh_pcf8574_init_config_t *config) ZH_ERROR_CHECK(gpio_config(&interrupt_gpio_config) == ESP_OK, ESP_FAIL, NULL, "GPIO configuration failed.") esp_err_t err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED); ZH_ERROR_CHECK(err == ESP_OK || err == ESP_ERR_INVALID_STATE, ESP_FAIL, - {ZH_ERROR_CHECK(gpio_reset_pin(config->interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset gpio failed.")}, "Failed install isr service.") + {ZH_ERROR_CHECK_CONT(gpio_reset_pin(config->interrupt_gpio) == ESP_OK, NULL, "Reset gpio failed.")}, "Failed install isr service.") ZH_ERROR_CHECK(gpio_isr_handler_add(config->interrupt_gpio, _zh_pcf8574_isr_handler, NULL) == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(gpio_reset_pin(config->interrupt_gpio) == ESP_OK, ESP_FAIL, NULL, "Reset gpio failed.")}, "Failed add isr handler.") + {ZH_ERROR_CHECK_CONT(gpio_reset_pin(config->interrupt_gpio) == ESP_OK, NULL, "Reset gpio failed.")}, "Failed add isr handler.") return ESP_OK; } @@ -393,18 +398,18 @@ static esp_err_t _zh_pcf8574_i2c_init(const zh_pcf8574_init_config_t *config, _z }; i2c_master_dev_handle_t _dev_handle = NULL; ZH_ERROR_CHECK(i2c_master_bus_add_device(config->i2c_handle, &pcf8574_config, &_dev_handle) == ESP_OK, ESP_FAIL, NULL, "Failed to add I2C device."); - ZH_ERROR_CHECK(i2c_master_probe(config->i2c_handle, config->i2c_address, 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}, "Expander not connected or not responding."); + ZH_ERROR_CHECK(i2c_master_probe(config->i2c_handle, config->i2c_address, 100) == ESP_OK, ESP_FAIL, + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}, "Expander not connected or not responding."); vector_data->gpio_work_mode = (config->p7_gpio_work_mode << 7) | (config->p6_gpio_work_mode << 6) | (config->p5_gpio_work_mode << 5) | (config->p4_gpio_work_mode << 4) | (config->p3_gpio_work_mode << 3) | (config->p2_gpio_work_mode << 2) | (config->p1_gpio_work_mode << 1) | (config->p0_gpio_work_mode << 0); vector_data->dev_handle = _dev_handle; vector_data->i2c_address = config->i2c_address; ZH_ERROR_CHECK(_zh_pcf8574_write_register(vector_data, vector_data->gpio_work_mode) == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}, "Failed extender initial GPIO setup."); + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}, "Failed extender initial GPIO setup."); uint8_t reg_temp = 0; ZH_ERROR_CHECK(_zh_pcf8574_read_register(vector_data, ®_temp) == ESP_OK, ESP_FAIL, - {ZH_ERROR_CHECK(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, ESP_FAIL, NULL, "I2C remove device failed.")}, "Failed to read expander register."); + {ZH_ERROR_CHECK_CONT(i2c_master_bus_rm_device(_dev_handle) == ESP_OK, NULL, "I2C remove device failed.")}, "Failed to read expander register."); return ESP_OK; } @@ -422,7 +427,7 @@ static esp_err_t _zh_pcf8574_task_init(const zh_pcf8574_init_config_t *config) return ESP_OK; } -static void IRAM_ATTR _zh_pcf8574_isr_handler(void *arg) +static void _zh_pcf8574_isr_handler(void *arg) { (void)arg; BaseType_t xHigherPriorityTaskWoken = pdFALSE; @@ -436,7 +441,7 @@ static void IRAM_ATTR _zh_pcf8574_isr_handler(void *arg) }; } -static void IRAM_ATTR _zh_pcf8574_isr_processing_task(void *pvParameter) +static void _zh_pcf8574_isr_processing_task(void *pvParameter) { (void)pvParameter; for (;;) @@ -454,8 +459,8 @@ static void IRAM_ATTR _zh_pcf8574_isr_processing_task(void *pvParameter) event.i2c_address = vector_data.i2c_address; uint8_t old_reg = vector_data.gpio_status; uint8_t new_reg = 0; - ZH_ERROR_CHECK_CONT(_zh_pcf8574_read_register(&vector_data, &new_reg) == ESP_OK, NULL, "PCF8574 isr processing failed. Failed to read expander register."); - ZH_ERROR_CHECK_CONT(zh_vector_change_item(&_vector, i, &vector_data) == ESP_OK, ++_stats.vector_error, "PCF8574 isr processing failed. Failed to change vector item data."); + ZH_ERROR_CHECK_CONT(_zh_pcf8574_read_register(&vector_data, &new_reg) == ESP_OK, continue, "PCF8574 isr processing failed. Failed to read expander register."); + ZH_ERROR_CHECK_CONT(zh_vector_change_item(&_vector, i, &vector_data) == ESP_OK, ++_stats.vector_error; continue, "PCF8574 isr processing failed. Failed to change vector item data."); for (uint8_t j = 0; j <= 7; ++j) { if ((vector_data.gpio_work_mode & _gpio_matrix[j]) != 0) @@ -465,7 +470,7 @@ static void IRAM_ATTR _zh_pcf8574_isr_processing_task(void *pvParameter) event.gpio_number = j; event.gpio_level = new_reg & _gpio_matrix[j]; event.interrupt_time = esp_timer_get_time(); - ZH_ERROR_CHECK_CONT(esp_event_post(ZH_PCF8574, 0, &event, sizeof(event), 1000 / portTICK_PERIOD_MS) == ESP_OK, ++_stats.event_post_error, "PCF8574 isr processing failed. Failed to post interrupt event."); + ZH_ERROR_CHECK_CONT(esp_event_post(ZH_PCF8574, 0, &event, sizeof(event), pdMS_TO_TICKS(10)) == ESP_OK, ++_stats.event_post_error, "PCF8574 isr processing failed. Failed to post interrupt event."); } } } @@ -478,7 +483,7 @@ static void IRAM_ATTR _zh_pcf8574_isr_processing_task(void *pvParameter) static esp_err_t _zh_pcf8574_read_register(_zh_pcf8574_vector_data_t *vector_data, uint8_t *reg) { - ZH_ERROR_CHECK(i2c_master_receive(vector_data->dev_handle, &vector_data->gpio_status, sizeof(vector_data->gpio_status), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL, + ZH_ERROR_CHECK(i2c_master_receive(vector_data->dev_handle, &vector_data->gpio_status, sizeof(vector_data->gpio_status), 100) == ESP_OK, ESP_FAIL, ++_stats.i2c_driver_error, "I2C driver error."); *reg = vector_data->gpio_status; return ESP_OK; @@ -486,7 +491,7 @@ static esp_err_t _zh_pcf8574_read_register(_zh_pcf8574_vector_data_t *vector_dat static esp_err_t _zh_pcf8574_write_register(_zh_pcf8574_vector_data_t *vector_data, uint8_t reg) { - ZH_ERROR_CHECK(i2c_master_transmit(vector_data->dev_handle, ®, sizeof(reg), 1000 / portTICK_PERIOD_MS) == ESP_OK, ESP_FAIL, + ZH_ERROR_CHECK(i2c_master_transmit(vector_data->dev_handle, ®, sizeof(reg), 100) == ESP_OK, ESP_FAIL, ++_stats.i2c_driver_error, "I2C driver error."); vector_data->gpio_status = reg; return ESP_OK;