# I2C Wrapper Module

## Overview

The I2C wrapper module provides a C++ object-oriented interface for ESP-IDF I2C functionality. This module encapsulates the ESP-IDF I2C driver functions and provides a clean, easy-to-use API for I2C communication with peripheral devices.

## Features

- **Multi-Port Support**: Support for I2C0 and I2C1
- **Master/Slave Mode**: Configurable as master or slave device
- **Register Operations**: Convenient register read/write functions
- **Bus Scanning**: Automatic device discovery on I2C bus
- **Timeout Support**: Configurable timeouts for all operations
- **Pull-up Configuration**: Internal pull-up resistor control
- **Error Handling**: Comprehensive error checking and logging

## Architecture

### Class Diagram

```
┌─────────────────────────────────────┐
│              I2c                    │
├─────────────────────────────────────┤
│ - m_isInitialized_[2]: bool         │
├─────────────────────────────────────┤
│ + I2c()                             │
│ + ~I2c()                            │
│ + initialize(port, config): bool    │
│ + deinitialize(port): bool          │
│ + write(...): int32_t               │
│ + read(...): int32_t                │
│ + writeRead(...): int32_t           │
│ + writeRegister(...): bool          │
│ + readRegister(...): int32_t        │
│ + scanBus(...): int32_t             │
│ + isInitialized(port): bool         │
│ + getDefaultConfig(): I2cConfig     │
│ - convertPort(port): i2c_port_t     │
│ - convertConfig(cfg): i2c_config_t  │
└─────────────────────────────────────┘
```

### Enumerations

#### I2cPort
- `PORT_0`: I2C port 0
- `PORT_1`: I2C port 1

#### I2cMode
- `MASTER`: Master mode
- `SLAVE`: Slave mode

### Configuration Structure

```cpp
struct I2cConfig {
    I2cMode mode;              // I2C mode (master/slave)
    uint32_t sdaPin;           // SDA pin number
    uint32_t sclPin;           // SCL pin number
    uint32_t clkSpeedHz;       // Clock speed in Hz (for master mode)
    bool sdaPullupEnable;      // Enable SDA pull-up resistor
    bool sclPullupEnable;      // Enable SCL pull-up resistor
    uint8_t slaveAddress;      // Slave address (for slave mode)
    uint32_t rxBufferLen;      // RX buffer length (for slave mode)
    uint32_t txBufferLen;      // TX buffer length (for slave mode)
};
```

## Usage Examples

### Basic I2C Master Communication

```cpp
#include "i2c.hpp"

// Create I2C instance
I2c i2c;

// Get default configuration
I2cConfig config = I2c::getDefaultConfig();
config.sdaPin = 21;
config.sclPin = 22;
config.clkSpeedHz = 400000;  // 400kHz

// Initialize I2C
i2c.initialize(I2cPort::PORT_0, config);

// Write data to device
uint8_t data[] = {0x01, 0x02, 0x03};
i2c.write(I2cPort::PORT_0, 0x48, data, sizeof(data));

// Read data from device
uint8_t buffer[10];
int32_t bytesRead = i2c.read(I2cPort::PORT_0, 0x48, buffer, sizeof(buffer));
```

### Register Operations

```cpp
// Write to register
i2c.writeRegister(I2cPort::PORT_0, 0x48, 0x10, 0xFF);

// Read from register
int32_t regValue = i2c.readRegister(I2cPort::PORT_0, 0x48, 0x10);

// Write register address and read multiple bytes
uint8_t regData[4];
i2c.writeRead(I2cPort::PORT_0, 0x48, 0x10, regData, sizeof(regData));
```

### Bus Scanning

```cpp
// Scan for devices on the bus
uint8_t devices[20];
int32_t deviceCount = i2c.scanBus(I2cPort::PORT_0, devices, sizeof(devices));

printf("Found %ld devices:\n", deviceCount);
for (int i = 0; i < deviceCount; i++) {
    printf("Device at address: 0x%02X\n", devices[i]);
}
```

### Slave Mode Configuration

```cpp
I2cConfig slaveConfig = {};
slaveConfig.mode = I2cMode::SLAVE;
slaveConfig.sdaPin = 21;
slaveConfig.sclPin = 22;
slaveConfig.slaveAddress = 0x28;
slaveConfig.rxBufferLen = 256;
slaveConfig.txBufferLen = 256;
slaveConfig.sdaPullupEnable = true;
slaveConfig.sclPullupEnable = true;

i2c.initialize(I2cPort::PORT_1, slaveConfig);
```

## API Reference

### Constructor/Destructor

- **I2c()**: Initialize I2C wrapper instance
- **~I2c()**: Clean up resources and deinitialize all ports

### Configuration Methods

- **initialize(port, config)**: Initialize I2C port with configuration
- **deinitialize(port)**: Deinitialize I2C port
- **isInitialized(port)**: Check if port is initialized
- **getDefaultConfig()**: Get default configuration structure

### Communication Methods

- **write(port, address, data, length, timeout)**: Write data to device
- **read(port, address, buffer, length, timeout)**: Read data from device
- **writeRead(port, address, regAddr, buffer, length, timeout)**: Write register address and read data

### Register Operations

- **writeRegister(port, address, regAddr, value, timeout)**: Write single register
- **readRegister(port, address, regAddr, timeout)**: Read single register

### Utility Methods

- **scanBus(port, devices, maxDevices)**: Scan bus for connected devices

## Error Handling

The module provides comprehensive error handling:
- Port validation and initialization checks
- Device address validation (0x08-0x77 range)
- ESP-IDF error codes are caught and logged
- Return values indicate success/failure for all operations
- Detailed logging for debugging and troubleshooting

## Dependencies

- ESP-IDF I2C driver (`driver/i2c.h`)
- ESP-IDF error handling (`esp_err.h`)
- ESP-IDF logging (`esp_log.h`)
- FreeRTOS (`freertos/FreeRTOS.h`, `freertos/task.h`)

## Thread Safety

The I2C wrapper uses ESP-IDF's thread-safe I2C driver. Multiple tasks can safely use different I2C ports simultaneously, but access to the same port should be synchronized.

## Memory Usage

- Fixed memory footprint per instance
- Configurable buffer sizes for slave mode
- No dynamic memory allocation in wrapper layer

## Performance Considerations

- Direct ESP-IDF function calls for optimal performance
- Minimal overhead over raw ESP-IDF calls
- Configurable clock speeds (100kHz, 400kHz, 1MHz)
- Bus scanning can be time-consuming for large address ranges

## Common I2C Speeds

- **Standard Mode**: 100 kHz
- **Fast Mode**: 400 kHz
- **Fast Mode Plus**: 1 MHz

## Troubleshooting

### Common Issues

1. **Pull-up Resistors**: Ensure proper pull-up resistors on SDA/SCL lines
2. **Address Conflicts**: Check for address conflicts when using multiple devices
3. **Clock Stretching**: Some devices require clock stretching support
4. **Bus Capacitance**: Long wires or many devices can affect signal integrity