Files
se050-wireguard/src/se050_i2c_hal.c
T
km 11bcc5e0c3 Remove dynamic memory allocation (malloc/calloc/free)
- Add static memory pool implementation (se050_mem_pool.c/h)
- Replace all malloc/calloc with pool allocations
- Replace all free with pool deallocations
- Remove strdup usage (use fixed-size buffer instead)
- Update I2C HAL to use fixed-size dev_path array
- All 24 tests pass with static memory only

Suitable for embedded environments (u-boot, ESP32) without heap.
2026-03-29 19:07:57 +09:00

240 lines
4.9 KiB
C

/**
* @file se050_i2c_hal.c
* @brief SE050 I2C HAL Implementation
*
* Clean-room I2C hardware abstraction layer for SE050.
*
* License: MIT (Clean-room implementation)
*/
#define _POSIX_C_SOURCE 200809L
#include "se050_i2c_hal.h"
#include "se050_wireguard.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#include <time.h>
#ifdef __linux__
/* Linux-specific I2C IOCTL definitions */
#ifndef I2C_SLAVE
#define I2C_SLAVE 0x0703
#endif
#ifndef I2C_SMBUS
#define I2C_SMBUS 0x0720
#endif
#endif
/* SE050 default I2C address (7-bit) */
#define SE050_I2C_ADDR_DEFAULT 0x48
/* I2C timeout in milliseconds */
#define SE050_I2C_TIMEOUT_MS 1000
/* Maximum retry count for I2C operations */
#define SE050_I2C_MAX_RETRY 3
/* SE050 wakeup delay in milliseconds */
#define SE050_WAKEUP_DELAY_MS 5
/**
* @brief Sleep for specified milliseconds
*/
static void se050_sleep_ms(unsigned int ms)
{
#ifdef __linux__
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000L;
nanosleep(&ts, NULL);
#else
/* Fallback for non-Linux platforms */
volatile int i;
for (i = 0; i < ms * 1000; i++);
#endif
}
/**
* @brief Open I2C device
*/
static void *i2c_open(const char *dev_path)
{
int fd;
if (!dev_path) {
return NULL;
}
fd = open(dev_path, O_RDWR);
if (fd < 0) {
perror("I2C open failed");
return NULL;
}
return (void *)(intptr_t)fd;
}
/**
* @brief Close I2C device
*/
static void i2c_close(void *handle)
{
int fd = (int)(intptr_t)handle;
if (fd >= 0) {
close(fd);
}
}
/**
* @brief Set I2C slave address
*/
static se050_status_t i2c_set_slave_addr(void *handle, uint8_t addr)
{
int fd = (int)(intptr_t)handle;
int ret;
/* addr is already 7-bit address */
ret = ioctl(fd, I2C_SLAVE, addr);
if (ret < 0) {
perror("I2C set slave address failed");
return SE050_ERR_I2C;
}
return SE050_OK;
}
/* ============================================================================
* Public API Implementation
* ============================================================================ */
se050_status_t se050_i2c_init(se050_i2c_hal_t *hal, const char *dev_path, uint8_t slave_addr)
{
void *handle;
if (!hal || !dev_path) {
return SE050_ERR_INVALID_ARG;
}
memset(hal, 0, sizeof(*hal));
/* Open I2C device */
handle = i2c_open(dev_path);
if (!handle) {
return SE050_ERR_I2C;
}
/* Set slave address */
if (i2c_set_slave_addr(handle, slave_addr) != SE050_OK) {
i2c_close(handle);
return SE050_ERR_I2C;
}
hal->handle = handle;
hal->slave_addr = slave_addr;
strncpy(hal->dev_path, dev_path, SE050_I2C_DEV_PATH_MAX - 1);
hal->dev_path[SE050_I2C_DEV_PATH_MAX - 1] = '\0';
return SE050_OK;
}
void se050_i2c_close(se050_i2c_hal_t *hal)
{
if (!hal) {
return;
}
if (hal->handle) {
i2c_close(hal->handle);
hal->handle = NULL;
}
hal->dev_path[0] = '\0';
hal->slave_addr = 0;
}
int se050_i2c_read(se050_i2c_hal_t *hal, uint8_t *buffer, int length)
{
int fd;
int retry;
int bytes_read;
if (!hal || !buffer || length <= 0) {
return -1;
}
fd = (int)(intptr_t)hal->handle;
for (retry = 0; retry < SE050_I2C_MAX_RETRY; retry++) {
bytes_read = read(fd, buffer, length);
if (bytes_read > 0) {
return bytes_read;
}
if (errno != EAGAIN && errno != ETIMEDOUT) {
/* Permanent error */
break;
}
/* Retry with delay */
se050_sleep_ms(SE050_WAKEUP_DELAY_MS);
}
return -1;
}
int se050_i2c_write(se050_i2c_hal_t *hal, const uint8_t *buffer, int length)
{
int fd;
int retry;
int bytes_written;
if (!hal || !buffer || length <= 0) {
return -1;
}
fd = (int)(intptr_t)hal->handle;
for (retry = 0; retry < SE050_I2C_MAX_RETRY; retry++) {
bytes_written = write(fd, buffer, length);
if (bytes_written > 0) {
return bytes_written;
}
if (errno != EAGAIN && errno != ETIMEDOUT) {
/* Permanent error */
break;
}
/* Retry with delay */
se050_sleep_ms(SE050_WAKEUP_DELAY_MS);
}
return -1;
}
se050_status_t se050_i2c_wakeup(se050_i2c_hal_t *hal)
{
uint8_t wakeup_cmd = 0x00;
int ret;
if (!hal) {
return SE050_ERR_INVALID_ARG;
}
/* Send wakeup command (dummy write) */
ret = se050_i2c_write(hal, &wakeup_cmd, 1);
if (ret < 0) {
return SE050_ERR_I2C;
}
/* Wait for SE050 to respond */
se050_sleep_ms(SE050_WAKEUP_DELAY_MS);
return SE050_OK;
}