11 Commits

4 changed files with 172 additions and 28 deletions

View File

@@ -4,6 +4,10 @@
1. [ESP32 ESP-IDF v5.5.1](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32/index.html) 1. [ESP32 ESP-IDF v5.5.1](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32/index.html)
## SAST Tools
[PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.
## Features ## Features
1. Support of 16 expanders on one bus. 1. Support of 16 expanders on one bus.
@@ -16,6 +20,14 @@
2. All the INT GPIO's on the extenders must be connected to the one GPIO on ESP. 2. All the INT GPIO's on the extenders must be connected to the one GPIO on ESP.
3. The input GPIO's are always pullup to the power supply. 3. The input GPIO's are always pullup to the power supply.
## Attention
For correct operation, please enable the following settings in the menuconfig:
```text
GPIO_CTRL_FUNC_IN_IRAM
```
## Dependencies ## Dependencies
1. [zh_vector](http://git.zh.com.ru/esp_components/zh_vector) 1. [zh_vector](http://git.zh.com.ru/esp_components/zh_vector)
@@ -76,12 +88,12 @@ void app_main(void)
i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle); i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
esp_event_loop_create_default(); // Required only if used input GPIO interrupts. esp_event_loop_create_default(); // Required only if used input GPIO interrupts.
esp_event_handler_instance_register(ZH_PCF8574, ESP_EVENT_ANY_ID, &zh_pcf8574_event_handler, NULL, NULL); // Required only if used input GPIO interrupts. esp_event_handler_instance_register(ZH_PCF8574, ESP_EVENT_ANY_ID, &zh_pcf8574_event_handler, NULL, NULL); // Required only if used input GPIO interrupts.
zh_pcf8574_init_config_t pcf8574_init_config = ZH_PCF8574_INIT_CONFIG_DEFAULT(); zh_pcf8574_init_config_t config = ZH_PCF8574_INIT_CONFIG_DEFAULT();
pcf8574_init_config.i2c_handle = i2c_bus_handle; config.i2c_handle = i2c_bus_handle;
pcf8574_init_config.i2c_address = 0x38; config.i2c_address = 0x38;
pcf8574_init_config.p0_gpio_work_mode = true; // Required only for input GPIO. config.p0_gpio_work_mode = true; // Required only for input GPIO.
pcf8574_init_config.interrupt_gpio = GPIO_NUM_14; // Required only if used input GPIO interrupts. config.interrupt_gpio = GPIO_NUM_14; // Required only if used input GPIO interrupts.
zh_pcf8574_init(&pcf8574_init_config, &pcf8574_handle); zh_pcf8574_init(&config, &pcf8574_handle);
uint8_t reg = 0; uint8_t reg = 0;
zh_pcf8574_read(&pcf8574_handle, &reg); zh_pcf8574_read(&pcf8574_handle, &reg);
print_gpio_status("GPIO status: ", reg); print_gpio_status("GPIO status: ", reg);
@@ -104,6 +116,16 @@ void app_main(void)
zh_pcf8574_reset(&pcf8574_handle); zh_pcf8574_reset(&pcf8574_handle);
zh_pcf8574_read(&pcf8574_handle, &reg); zh_pcf8574_read(&pcf8574_handle, &reg);
print_gpio_status("GPIO status: ", reg); print_gpio_status("GPIO status: ", reg);
for (;;)
{
const zh_pcf8574_stats_t *stats = zh_pcf8574_get_stats();
printf("Number of i2c driver error: %ld.\n", stats->i2c_driver_error);
printf("Number of event post error: %ld.\n", stats->event_post_error);
printf("Number of vector error: %ld.\n", stats->vector_error);
printf("Number of queue overflow error: %ld.\n", stats->queue_overflow_error);
printf("Minimum free stack size: %ld.\n", stats->min_stack_size);
vTaskDelay(60000 / portTICK_PERIOD_MS);
}
} }
void zh_pcf8574_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) // Required only if used input GPIO interrupts. void zh_pcf8574_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) // Required only if used input GPIO interrupts.

View File

@@ -35,6 +35,8 @@ extern "C"
{ {
#endif #endif
extern TaskHandle_t zh_pcf8574; /*!< Unique task handle. */
/** /**
* @brief Structure for initial initialization of PCF8574 expander. * @brief Structure for initial initialization of PCF8574 expander.
*/ */
@@ -68,6 +70,18 @@ extern "C"
void *system; /*!< System pointer for use in another components. */ void *system; /*!< System pointer for use in another components. */
} zh_pcf8574_handle_t; } zh_pcf8574_handle_t;
/**
* @brief Structure for error statistics storage.
*/
typedef struct
{
uint32_t i2c_driver_error; /*!< Number of i2c driver error. */
uint32_t event_post_error; /*!< Number of event post error. */
uint32_t vector_error; /*!< Number of vector error. */
uint32_t queue_overflow_error; /*!< Number of queue overflow error. */
uint32_t min_stack_size; /*!< Minimum free stack size. */
} zh_pcf8574_stats_t;
ESP_EVENT_DECLARE_BASE(ZH_PCF8574); ESP_EVENT_DECLARE_BASE(ZH_PCF8574);
/** /**
@@ -98,6 +112,15 @@ extern "C"
*/ */
esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle); esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle);
/**
* @brief Deinitialize PCF8574 expander.
*
* @param[in] handle Pointer to unique PCF8574 handle.
*
* @return ESP_OK if success or an error code otherwise.
*/
esp_err_t zh_pcf8574_deinit(zh_pcf8574_handle_t *handle);
/** /**
* @brief Read PCF8574 all GPIO's status. * @brief Read PCF8574 all GPIO's status.
* *
@@ -157,6 +180,18 @@ extern "C"
*/ */
esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool status); esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool status);
/**
* @brief Get error statistics.
*
* @return Pointer to the statistics structure.
*/
const zh_pcf8574_stats_t *zh_pcf8574_get_stats(void);
/**
* @brief Reset error statistics.
*/
void zh_pcf8574_reset_stats(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1 +1 @@
2.0.0 2.3.1

View File

@@ -13,9 +13,13 @@ static const char *TAG = "zh_pcf8574";
return err; \ return err; \
} }
static uint8_t _interrupt_gpio = GPIO_NUM_MAX; TaskHandle_t zh_pcf8574 = NULL;
static SemaphoreHandle_t _interrupt_semaphore = NULL; static SemaphoreHandle_t _interrupt_semaphore = NULL;
static uint8_t _interrupt_gpio = GPIO_NUM_MAX;
static const uint8_t _gpio_matrix[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; static const uint8_t _gpio_matrix[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
static bool _is_prev_gpio_isr_service = false;
static zh_pcf8574_stats_t _stats = {0};
static zh_vector_t _vector = {0}; static zh_vector_t _vector = {0};
@@ -31,7 +35,7 @@ static esp_err_t _zh_pcf8574_write_register(zh_pcf8574_handle_t *handle, uint8_t
ESP_EVENT_DEFINE_BASE(ZH_PCF8574); ESP_EVENT_DEFINE_BASE(ZH_PCF8574);
esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) // -V2008
{ {
ZH_LOGI("PCF8574 initialization started."); ZH_LOGI("PCF8574 initialization started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 initialization failed. Invalid argument."); ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 initialization failed. Invalid argument.");
@@ -47,21 +51,71 @@ esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_han
err = _zh_pcf8574_gpio_init(config, handle); err = _zh_pcf8574_gpio_init(config, handle);
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle), "PCF8574 initialization failed. Interrupt GPIO initialization failed."); ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle), "PCF8574 initialization failed. Interrupt GPIO initialization failed.");
err = _zh_pcf8574_resources_init(config); err = _zh_pcf8574_resources_init(config);
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove(config->interrupt_gpio); gpio_uninstall_isr_service(); if (_is_prev_gpio_isr_service == true)
gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector), "PCF8574 initialization failed. Resources initialization failed."); {
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "PCF8574 initialization failed. Resources initialization failed.");
}
else
{
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "PCF8574 initialization failed. Resources initialization failed.");
}
err = _zh_pcf8574_task_init(config); err = _zh_pcf8574_task_init(config);
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove(config->interrupt_gpio); gpio_uninstall_isr_service(); if (_is_prev_gpio_isr_service == true)
gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector); vSemaphoreDelete(_interrupt_semaphore), "PCF8574 initialization failed. Task initialization failed."); {
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector); vSemaphoreDelete(_interrupt_semaphore), "PCF8574 initialization failed. Task initialization failed.");
}
else
{
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(handle->dev_handle); gpio_isr_handler_remove((gpio_num_t)config->interrupt_gpio);
gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector); vSemaphoreDelete(_interrupt_semaphore), "PCF8574 initialization failed. Task initialization failed.");
}
} }
handle->is_initialized = true; handle->is_initialized = true;
ZH_LOGI("PCF8574 initialization completed successfully."); ZH_LOGI("PCF8574 initialization completed successfully.");
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_pcf8574_deinit(zh_pcf8574_handle_t *handle)
{
ZH_LOGI("PCF8574 deinitialization started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 deinitialization failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_INVALID_STATE, NULL, "PCF8574 deinitialization failed. PCF8574 not initialized.");
if (_interrupt_gpio < GPIO_NUM_MAX && handle->gpio_work_mode != 0)
{
for (uint16_t i = 0; i < zh_vector_get_size(&_vector); ++i)
{
zh_pcf8574_handle_t *temp_handle = zh_vector_get_item(&_vector, i);
if (handle->i2c_address == temp_handle->i2c_address)
{
zh_vector_delete_item(&_vector, i);
break;
}
}
if (zh_vector_get_size(&_vector) == 0)
{
gpio_isr_handler_remove((gpio_num_t)_interrupt_gpio);
gpio_reset_pin((gpio_num_t)_interrupt_gpio);
zh_vector_free(&_vector);
if (_is_prev_gpio_isr_service == false)
{
gpio_uninstall_isr_service();
}
_interrupt_gpio = GPIO_NUM_MAX;
}
}
i2c_master_bus_rm_device(handle->dev_handle);
handle->is_initialized = false;
ZH_LOGI("PCF8574 deinitialization completed successfully.");
return ESP_OK;
}
esp_err_t zh_pcf8574_read(zh_pcf8574_handle_t *handle, uint8_t *reg) esp_err_t zh_pcf8574_read(zh_pcf8574_handle_t *handle, uint8_t *reg)
{ {
ZH_LOGI("PCF8574 read register started."); ZH_LOGI("PCF8574 read register started.");
ZH_ERROR_CHECK(handle != NULL || reg != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 read register failed. Invalid argument."); ZH_ERROR_CHECK(handle != NULL && reg != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 read register failed. Invalid argument.");
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_NOT_FOUND, NULL, "PCF8574 read register failed. PCF8574 not initialized."); ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_NOT_FOUND, NULL, "PCF8574 read register failed. PCF8574 not initialized.");
esp_err_t err = _zh_pcf8574_read_register(handle, reg); esp_err_t err = _zh_pcf8574_read_register(handle, reg);
ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "PCF8574 read register failed."); ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "PCF8574 read register failed.");
@@ -91,10 +145,10 @@ esp_err_t zh_pcf8574_reset(zh_pcf8574_handle_t *handle)
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool *status) esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool *status) // -V2008
{ {
ZH_LOGI("PCF8574 read GPIO started."); ZH_LOGI("PCF8574 read GPIO started.");
ZH_ERROR_CHECK(handle != NULL || status != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 read GPIO failed. Invalid argument."); ZH_ERROR_CHECK(handle != NULL && status != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 read GPIO failed. Invalid argument.");
ZH_ERROR_CHECK(gpio <= 7, ESP_FAIL, NULL, "PCF8574 read GPIO failed. Invalid GPIO number.") ZH_ERROR_CHECK(gpio <= 7, ESP_FAIL, NULL, "PCF8574 read GPIO failed. Invalid GPIO number.")
ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_NOT_FOUND, NULL, "PCF8574 read GPIO failed. PCF8574 not initialized."); ZH_ERROR_CHECK(handle->is_initialized == true, ESP_ERR_NOT_FOUND, NULL, "PCF8574 read GPIO failed. PCF8574 not initialized.");
uint8_t gpio_temp = _gpio_matrix[gpio]; uint8_t gpio_temp = _gpio_matrix[gpio];
@@ -106,7 +160,7 @@ esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool *
return ESP_OK; return ESP_OK;
} }
esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool status) esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool status) // -V2008
{ {
ZH_LOGI("PCF8574 write GPIO started."); ZH_LOGI("PCF8574 write GPIO started.");
ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 write GPIO failed. Invalid argument."); ZH_ERROR_CHECK(handle != NULL, ESP_ERR_INVALID_ARG, NULL, "PCF8574 write GPIO failed. Invalid argument.");
@@ -127,17 +181,33 @@ esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t *handle, uint8_t gpio, bool
return ESP_OK; return ESP_OK;
} }
static esp_err_t _zh_pcf8574_validate_config(const zh_pcf8574_init_config_t *config) const zh_pcf8574_stats_t *zh_pcf8574_get_stats(void)
{
return &_stats;
}
void zh_pcf8574_reset_stats(void)
{
ZH_LOGI("Error statistic reset started.");
_stats.i2c_driver_error = 0;
_stats.event_post_error = 0;
_stats.vector_error = 0;
_stats.queue_overflow_error = 0;
_stats.min_stack_size = 0;
ZH_LOGI("Error statistic reset successfully.");
}
static esp_err_t _zh_pcf8574_validate_config(const zh_pcf8574_init_config_t *config) // -V2008
{ {
ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Initial config is NULL."); ZH_ERROR_CHECK(config != NULL, ESP_ERR_INVALID_ARG, NULL, "Initial config is NULL.");
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_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->task_priority >= 10 && config->stack_size >= 2048, ESP_ERR_INVALID_ARG, NULL, "Invalid task settings."); ZH_ERROR_CHECK(config->task_priority >= 10 && config->stack_size >= 2048, ESP_ERR_INVALID_ARG, NULL, "Invalid task settings.");
ZH_ERROR_CHECK(config->interrupt_gpio >= GPIO_NUM_0 && config->interrupt_gpio <= GPIO_NUM_MAX, ESP_ERR_INVALID_ARG, NULL, "Invalid GPIO number."); 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."); ZH_ERROR_CHECK(config->i2c_handle != NULL, ESP_ERR_INVALID_ARG, NULL, "Invalid I2C handle.");
return ESP_OK; return ESP_OK;
} }
static esp_err_t _zh_pcf8574_gpio_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) static esp_err_t _zh_pcf8574_gpio_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t *handle) // -V2008
{ {
if (_interrupt_gpio != GPIO_NUM_MAX) if (_interrupt_gpio != GPIO_NUM_MAX)
{ {
@@ -159,9 +229,20 @@ static esp_err_t _zh_pcf8574_gpio_init(const zh_pcf8574_init_config_t *config, z
err = gpio_config(&interrupt_gpio_config); err = gpio_config(&interrupt_gpio_config);
ZH_ERROR_CHECK(err == ESP_OK, err, zh_vector_free(&_vector), "GPIO configuration failed.") ZH_ERROR_CHECK(err == ESP_OK, err, zh_vector_free(&_vector), "GPIO configuration failed.")
err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED); err = gpio_install_isr_service(ESP_INTR_FLAG_LOWMED);
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector), "Failed install isr service.") ZH_ERROR_CHECK(err == ESP_OK || err == ESP_ERR_INVALID_STATE, err, gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "Failed install isr service.")
err = gpio_isr_handler_add(config->interrupt_gpio, _zh_pcf8574_isr_handler, NULL); if (err == ESP_ERR_INVALID_STATE)
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_uninstall_isr_service(); gpio_reset_pin(config->interrupt_gpio); zh_vector_free(&_vector), "Failed add isr handler.") {
_is_prev_gpio_isr_service = true;
}
err = gpio_isr_handler_add((gpio_num_t)config->interrupt_gpio, _zh_pcf8574_isr_handler, NULL);
if (_is_prev_gpio_isr_service == true)
{
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "Failed add isr handler.")
}
else
{
ZH_ERROR_CHECK(err == ESP_OK, err, gpio_uninstall_isr_service(); gpio_reset_pin((gpio_num_t)config->interrupt_gpio); zh_vector_free(&_vector), "Failed add isr handler.")
}
_interrupt_gpio = config->interrupt_gpio; _interrupt_gpio = config->interrupt_gpio;
return ESP_OK; return ESP_OK;
} }
@@ -175,7 +256,7 @@ static esp_err_t _zh_pcf8574_i2c_init(const zh_pcf8574_init_config_t *config, zh
}; };
i2c_master_dev_handle_t _dev_handle = NULL; i2c_master_dev_handle_t _dev_handle = NULL;
esp_err_t err = i2c_master_bus_add_device(config->i2c_handle, &pcf8574_config, &_dev_handle); esp_err_t err = i2c_master_bus_add_device(config->i2c_handle, &pcf8574_config, &_dev_handle);
ZH_ERROR_CHECK(err == ESP_OK, err, NULL;, "Failed to add I2C device."); ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "Failed to add I2C device.");
err = i2c_master_probe(config->i2c_handle, config->i2c_address, 1000 / portTICK_PERIOD_MS); err = i2c_master_probe(config->i2c_handle, config->i2c_address, 1000 / portTICK_PERIOD_MS);
ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(_dev_handle), "Expander not connected or not responding."); ZH_ERROR_CHECK(err == ESP_OK, err, i2c_master_bus_rm_device(_dev_handle), "Expander not connected or not responding.");
handle->dev_handle = _dev_handle; handle->dev_handle = _dev_handle;
@@ -196,7 +277,7 @@ static esp_err_t _zh_pcf8574_resources_init(const zh_pcf8574_init_config_t *conf
static esp_err_t _zh_pcf8574_task_init(const zh_pcf8574_init_config_t *config) static esp_err_t _zh_pcf8574_task_init(const zh_pcf8574_init_config_t *config)
{ {
BaseType_t err = xTaskCreatePinnedToCore(&_zh_pcf8574_isr_processing_task, "zh_pcf8574_isr_processing_task", config->stack_size, NULL, config->task_priority, NULL, tskNO_AFFINITY); BaseType_t err = xTaskCreatePinnedToCore(&_zh_pcf8574_isr_processing_task, "zh_pcf8574_isr_processing_task", config->stack_size, NULL, config->task_priority, &zh_pcf8574, tskNO_AFFINITY);
ZH_ERROR_CHECK(err == pdPASS, err, NULL, "Failed to create isr processing task.") ZH_ERROR_CHECK(err == pdPASS, err, NULL, "Failed to create isr processing task.")
return ESP_OK; return ESP_OK;
} }
@@ -204,7 +285,10 @@ static esp_err_t _zh_pcf8574_task_init(const zh_pcf8574_init_config_t *config)
static void IRAM_ATTR _zh_pcf8574_isr_handler(void *arg) static void IRAM_ATTR _zh_pcf8574_isr_handler(void *arg)
{ {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(_interrupt_semaphore, &xHigherPriorityTaskWoken); if (xSemaphoreGiveFromISR(_interrupt_semaphore, &xHigherPriorityTaskWoken) != pdTRUE)
{
++_stats.queue_overflow_error;
}
if (xHigherPriorityTaskWoken == pdTRUE) if (xHigherPriorityTaskWoken == pdTRUE)
{ {
portYIELD_FROM_ISR(); portYIELD_FROM_ISR();
@@ -221,6 +305,7 @@ static void IRAM_ATTR _zh_pcf8574_isr_processing_task(void *pvParameter)
zh_pcf8574_handle_t *handle = zh_vector_get_item(&_vector, i); zh_pcf8574_handle_t *handle = zh_vector_get_item(&_vector, i);
if (handle == NULL) if (handle == NULL)
{ {
++_stats.vector_error;
ZH_LOGE("PCF8574 isr processing failed. Failed to get vector item data.", ESP_FAIL); ZH_LOGE("PCF8574 isr processing failed. Failed to get vector item data.", ESP_FAIL);
continue; continue;
} }
@@ -251,11 +336,13 @@ static void IRAM_ATTR _zh_pcf8574_isr_processing_task(void *pvParameter)
err = esp_event_post(ZH_PCF8574, 0, &event, sizeof(event), 1000 / portTICK_PERIOD_MS); err = esp_event_post(ZH_PCF8574, 0, &event, sizeof(event), 1000 / portTICK_PERIOD_MS);
if (err != ESP_OK) if (err != ESP_OK)
{ {
++_stats.event_post_error;
ZH_LOGE("PCF8574 isr processing failed. Failed to post interrupt event.", err); ZH_LOGE("PCF8574 isr processing failed. Failed to post interrupt event.", err);
continue; continue;
} }
} }
} }
_stats.min_stack_size = (uint32_t)uxTaskGetStackHighWaterMark(NULL);
} }
vTaskDelete(NULL); vTaskDelete(NULL);
} }
@@ -263,7 +350,7 @@ static void IRAM_ATTR _zh_pcf8574_isr_processing_task(void *pvParameter)
static esp_err_t _zh_pcf8574_read_register(zh_pcf8574_handle_t *handle, uint8_t *reg) static esp_err_t _zh_pcf8574_read_register(zh_pcf8574_handle_t *handle, uint8_t *reg)
{ {
esp_err_t err = i2c_master_receive(handle->dev_handle, &handle->gpio_status, sizeof(handle->gpio_status), 1000 / portTICK_PERIOD_MS); esp_err_t err = i2c_master_receive(handle->dev_handle, &handle->gpio_status, sizeof(handle->gpio_status), 1000 / portTICK_PERIOD_MS);
ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "I2C driver error."); ZH_ERROR_CHECK(err == ESP_OK, err, ++_stats.i2c_driver_error, "I2C driver error.");
*reg = handle->gpio_status; *reg = handle->gpio_status;
return ESP_OK; return ESP_OK;
} }
@@ -271,7 +358,7 @@ static esp_err_t _zh_pcf8574_read_register(zh_pcf8574_handle_t *handle, uint8_t
static esp_err_t _zh_pcf8574_write_register(zh_pcf8574_handle_t *handle, uint8_t reg) static esp_err_t _zh_pcf8574_write_register(zh_pcf8574_handle_t *handle, uint8_t reg)
{ {
esp_err_t err = i2c_master_transmit(handle->dev_handle, &reg, sizeof(reg), 1000 / portTICK_PERIOD_MS); esp_err_t err = i2c_master_transmit(handle->dev_handle, &reg, sizeof(reg), 1000 / portTICK_PERIOD_MS);
ZH_ERROR_CHECK(err == ESP_OK, err, NULL, "I2C driver error."); ZH_ERROR_CHECK(err == ESP_OK, err, ++_stats.i2c_driver_error, "I2C driver error.");
handle->gpio_status = reg; handle->gpio_status = reg;
return ESP_OK; return ESP_OK;
} }