Files
zh_pcf8574/include/zh_pcf8574.h
T
2026-08-16 06:29:16 +03:00

277 lines
11 KiB
C
Executable File

/**
* @file zh_pcf8574.h
*
* @brief Header file for PCF8574 I2C GPIO expander driver.
*
* This module provides a driver for the PCF8574 8-bit I2C GPIO
* expander, supporting both input and output operations, interrupt
* handling, and configuration of individual pin directions.
*
* Key features:
* - I2C communication via esp-idf i2c_master driver
* - Configurable GPIO direction for each pin (P0-P7)
* - Interrupt handling with GPIO level detection
* - Event-based architecture using esp_event framework
* - Statistics tracking for debugging and monitoring
*
* @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.
*/
#pragma once
#include "esp_log.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#include "driver/i2c_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_event.h"
#include "zh_vector.h"
#define ZH_PCF8574_GPIO_OUTPUT false /*!< Configures GPIO pin as output */
#define ZH_PCF8574_GPIO_INPUT true /*!< Configures GPIO pin as input */
#define ZH_PCF8574_GPIO_LOW false /*!< Logical low level */
#define ZH_PCF8574_GPIO_HIGH true /*!< Logical high level */
#define ZH_PCF8574_INIT_CONFIG_DEFAULT() \
{ \
.task_priority = 1, \
.stack_size = configMINIMAL_STACK_SIZE, \
.i2c_address = 0xFF, \
.i2c_frequency = 100000, \
.p0_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.p1_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.p2_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.p3_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.p4_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.p5_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.p6_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.p7_gpio_work_mode = ZH_PCF8574_GPIO_OUTPUT, \
.interrupt_gpio = GPIO_NUM_MAX}
#ifdef __cplusplus
extern "C"
{
#endif
extern TaskHandle_t zh_pcf8574; /*!< Handle of the internal PCF8574 processing task. */
/**
* @brief Opaque handle for PCF8574 device instance.
*
* Forward declaration of the internal device handle structure.
* Used by all public API functions to reference a specific
* PCF8574 device instance.
*/
typedef struct _zh_pcf8574_handle_t zh_pcf8574_handle_t;
/**
* @brief PCF8574 GPIO pin numbering enumeration.
*
* Defines the pin numbering scheme for accessing individual
* GPIO pins (P0-P7) of the PCF8574 device.
*/
typedef enum
{
ZH_PCF8574_GPIO_NUM_P0 = 0, /*!< GPIO pin P0 */
ZH_PCF8574_GPIO_NUM_P1, /*!< GPIO pin P1 */
ZH_PCF8574_GPIO_NUM_P2, /*!< GPIO pin P2 */
ZH_PCF8574_GPIO_NUM_P3, /*!< GPIO pin P3 */
ZH_PCF8574_GPIO_NUM_P4, /*!< GPIO pin P4 */
ZH_PCF8574_GPIO_NUM_P5, /*!< GPIO pin P5 */
ZH_PCF8574_GPIO_NUM_P6, /*!< GPIO pin P6 */
ZH_PCF8574_GPIO_NUM_P7, /*!< GPIO pin P7 */
ZH_PCF8574_GPIO_NUM_MAX /*!< Maximum number of GPIO pins */
} zh_pcf8574_gpio_num_t;
/**
* @brief Initialization configuration structure for PCF8574 device.
*
* Defines all parameters required to initialize and configure
* the PCF8574 I2C GPIO expander, including I2C settings,
* individual GPIO direction modes, and interrupt configuration.
*
* @note The I2C bus must be initialized before calling zh_pcf8574_init().
*/
typedef struct
{
i2c_master_bus_handle_t i2c_handle; /*!< I2C bus handle for communication */
uint32_t i2c_frequency; /*!< I2C clock frequency in Hz */
uint32_t stack_size; /*!< Stack size for the internal task */
uint8_t task_priority; /*!< Priority of the internal task */
uint8_t i2c_address; /*!< 7-bit I2C address of the PCF8574 device */
bool p0_gpio_work_mode; /*!< Operating mode for GPIO P0 (input/output) */
bool p1_gpio_work_mode; /*!< Operating mode for GPIO P1 (input/output) */
bool p2_gpio_work_mode; /*!< Operating mode for GPIO P2 (input/output) */
bool p3_gpio_work_mode; /*!< Operating mode for GPIO P3 (input/output) */
bool p4_gpio_work_mode; /*!< Operating mode for GPIO P4 (input/output) */
bool p5_gpio_work_mode; /*!< Operating mode for GPIO P5 (input/output) */
bool p6_gpio_work_mode; /*!< Operating mode for GPIO P6 (input/output) */
bool p7_gpio_work_mode; /*!< Operating mode for GPIO P7 (input/output) */
gpio_num_t interrupt_gpio; /*!< GPIO pin for interrupt detection (GPIO_NUM_MAX if not used) */
} zh_pcf8574_init_config_t;
/**
* @brief Statistics structure for error tracking and diagnostics.
*
* Maintains counters for various error types and monitoring data
* to assist with debugging and system health monitoring.
*/
typedef struct
{
uint32_t i2c_driver_error; /*!< Counter of I2C driver errors */
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 */
} zh_pcf8574_stats_t;
ESP_EVENT_DECLARE_BASE(ZH_PCF8574);
/**
* @brief Event structure for GPIO interrupt events.
*
* Passed as event data when a GPIO level change is detected
* on any input pin of the PCF8574 device.
*/
typedef struct
{
uint64_t interrupt_time; /*!< Timestamp of the interrupt occurrence */
zh_pcf8574_gpio_num_t gpio_number; /*!< GPIO pin that triggered the interrupt */
uint8_t i2c_address; /*!< I2C address of the device that generated the interrupt */
bool gpio_level; /*!< Current level of the GPIO pin */
} zh_pcf8574_event_on_isr_t;
/**
* @brief Initialize PCF8574 device.
*
* Creates an internal task for interrupt processing and configures
* the I2C communication with the PCF8574 device according to the
* 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)
*
* @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_NO_MEM if memory allocation fails
* @return ESP_FAIL if configuration validation, I2C communication, or task creation fails
*/
esp_err_t zh_pcf8574_init(const zh_pcf8574_init_config_t *config, zh_pcf8574_handle_t **handle);
/**
* @brief Deinitialize PCF8574 device.
*
* 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)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle 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
*/
esp_err_t zh_pcf8574_deinit(zh_pcf8574_handle_t **handle);
/**
* @brief Read data from PCF8574 device.
*
* 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[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_NOT_FOUND if handle does not correspond to a valid device instance
* @return ESP_FAIL if I2C communication or vector operations fail
*/
esp_err_t zh_pcf8574_read(zh_pcf8574_handle_t **handle, uint8_t *reg);
/**
* @brief Write data to PCF8574 device.
*
* 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] 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_NOT_FOUND if handle does not correspond to a valid device instance
* @return ESP_FAIL if I2C communication or vector operations fail
*/
esp_err_t zh_pcf8574_write(zh_pcf8574_handle_t **handle, uint8_t reg);
/**
* @brief Reset PCF8574 device.
*
* Resets all outputs to their default input configuration
* and updates the internal device state.
*
* @param[in] handle Pointer to the device handle (must not be NULL)
*
* @return ESP_OK on success
* @return ESP_ERR_INVALID_ARG if handle 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
*/
esp_err_t zh_pcf8574_reset(zh_pcf8574_handle_t **handle);
/**
* @brief Read the state of a specific GPIO pin.
*
* Reads the current logical level of a specified GPIO pin.
*
* @param[in] handle Pointer to the device handle (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
*/
esp_err_t zh_pcf8574_read_gpio(zh_pcf8574_handle_t **handle, zh_pcf8574_gpio_num_t gpio, bool *status);
/**
* @brief Write state to a specific GPIO pin.
*
* 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] 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
*/
esp_err_t zh_pcf8574_write_gpio(zh_pcf8574_handle_t **handle, zh_pcf8574_gpio_num_t gpio, bool status);
/**
* @brief Get device statistics.
*
* Returns a pointer to the structure containing error counters
* and monitoring data for debugging and diagnostics.
*
* @return Pointer to the statistics structure (valid until reset)
*/
const zh_pcf8574_stats_t *zh_pcf8574_get_stats(void);
/**
* @brief Reset device statistics.
*
* Clears all error counters and monitoring data.
*/
void zh_pcf8574_reset_stats(void);
#ifdef __cplusplus
}
#endif