#include <linux/i2c-dev.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "atca_hal.h"
#include "hal_linux_i2c_userspace.h"
ATCA_STATUS hal_i2c_discover_buses(int i2c_buses[], int max_buses)
{
return ATCA_UNIMPLEMENTED;
}
ATCA_STATUS hal_i2c_discover_devices(int bus_num, ATCAIfaceCfg cfg[], int *found)
{
return ATCA_UNIMPLEMENTED;
}
ATCA_STATUS hal_i2c_init(void* hal, ATCAIfaceCfg* cfg)
{
ATCAHAL_t *pHal = (ATCAHAL_t*)hal;
ATCA_STATUS ret = ATCA_BAD_PARAM;
if (!pHal || !cfg)
{
return ret;
}
if (pHal->hal_data)
{
ATCAI2CMaster_t * hal_data = (ATCAI2CMaster_t*)pHal->hal_data;
hal_data->ref_ct++;
ret = ATCA_SUCCESS;
}
else
{
ATCAI2CMaster_t * hal_data = malloc(sizeof(ATCAI2CMaster_t));
int bus = cfg->atcai2c.bus;
if (hal_data)
{
hal_data->ref_ct = 1;
(void)snprintf(hal_data->i2c_file, sizeof(hal_data->i2c_file) - 1, "/dev/i2c-%d", bus);
pHal->hal_data = hal_data;
ret = ATCA_SUCCESS;
}
else
{
ret = ATCA_ALLOC_FAILURE;
}
}
return ret;
}
ATCA_STATUS hal_i2c_post_init(ATCAIface iface)
{
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_send(ATCAIface iface, uint8_t *txdata, int txlength)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
ATCAI2CMaster_t * hal_data = (ATCAI2CMaster_t*)atgetifacehaldat(iface);
int f_i2c;
txdata[0] = 0x03; txlength++;
if ( (f_i2c = open(hal_data->i2c_file, O_RDWR)) < 0)
{
return ATCA_COMM_FAIL;
}
if (ioctl(f_i2c, I2C_SLAVE, cfg->atcai2c.slave_address >> 1) < 0)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
if (write(f_i2c, txdata, txlength) != txlength)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
close(f_i2c);
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
ATCAI2CMaster_t * hal_data = (ATCAI2CMaster_t*)atgetifacehaldat(iface);
int f_i2c; uint16_t count;
uint16_t rxdata_max_size = *rxlength;
*rxlength = 0;
if (rxdata_max_size < 1)
{
return ATCA_SMALL_BUFFER;
}
if ( (f_i2c = open(hal_data->i2c_file, O_RDWR)) < 0)
{
return ATCA_COMM_FAIL;
}
if (ioctl(f_i2c, I2C_SLAVE, cfg->atcai2c.slave_address >> 1) < 0)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
count = 1;
if (read(f_i2c, rxdata, count) != count)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
if (rxdata[0] < ATCA_RSP_SIZE_MIN)
{
return ATCA_INVALID_SIZE;
}
if (rxdata[0] > rxdata_max_size)
{
return ATCA_SMALL_BUFFER;
}
count = rxdata[0] - 1;
if (read(f_i2c, &rxdata[1], count) != count)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
*rxlength = rxdata[0];
close(f_i2c);
return ATCA_SUCCESS;
}
void change_i2c_speed(ATCAIface iface, uint32_t speed)
{
}
ATCA_STATUS hal_i2c_wake(ATCAIface iface)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
ATCAI2CMaster_t * hal_data = (ATCAI2CMaster_t*)atgetifacehaldat(iface);
int f_i2c; uint8_t data[4];
uint8_t dummy_byte = 0x00;
if ( (f_i2c = open(hal_data->i2c_file, O_RDWR)) < 0)
{
return ATCA_COMM_FAIL;
}
if (ioctl(f_i2c, I2C_SLAVE, 0x00) < 0)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
if (write(f_i2c, &dummy_byte, 1) < 0)
{
}
atca_delay_us(cfg->wake_delay);
if (ioctl(f_i2c, I2C_SLAVE, cfg->atcai2c.slave_address >> 1) < 0)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
if (read(f_i2c, data, 4) != 4)
{
close(f_i2c);
return ATCA_RX_NO_RESPONSE;
}
close(f_i2c);
return hal_check_wake(data, 4);
}
ATCA_STATUS hal_i2c_idle(ATCAIface iface)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
ATCAI2CMaster_t * hal_data = (ATCAI2CMaster_t*)atgetifacehaldat(iface);
uint8_t data = 0x02; int f_i2c;
if ( (f_i2c = open(hal_data->i2c_file, O_RDWR) ) < 0)
{
return ATCA_COMM_FAIL;
}
if (ioctl(f_i2c, I2C_SLAVE, cfg->atcai2c.slave_address >> 1) < 0)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
if (write(f_i2c, &data, 1) != 1)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
close(f_i2c);
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_sleep(ATCAIface iface)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
ATCAI2CMaster_t * hal_data = (ATCAI2CMaster_t*)atgetifacehaldat(iface);
uint8_t data = 0x01; int f_i2c;
if ( (f_i2c = open(hal_data->i2c_file, O_RDWR)) < 0)
{
return ATCA_COMM_FAIL;
}
if (ioctl(f_i2c, I2C_SLAVE, cfg->atcai2c.slave_address >> 1) < 0)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
if (write(f_i2c, &data, 1) != 1)
{
close(f_i2c);
return ATCA_COMM_FAIL;
}
close(f_i2c);
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_release(void *hal_data)
{
ATCAI2CMaster_t *hal = (ATCAI2CMaster_t*)hal_data;
if (hal && --(hal->ref_ct) <= 0)
{
free(hal);
}
return ATCA_SUCCESS;
}