#include <asf.h>
#include <string.h>
#include <stdio.h>
#include "atca_hal.h"
#include "hal_samd21_i2c_asf.h"
#include "atca_device.h"
#include "atca_execution.h"
#include "atca_status.h"
static ATCAI2CMaster_t i2c_hal_data[MAX_I2C_BUSES]; static struct i2c_master_config config_i2c_master;
ATCA_STATUS hal_i2c_discover_buses(int i2c_buses[], int max_buses)
{
#ifdef __SAMR21G18A__
i2c_buses[0] = 1; #else
i2c_buses[0] = 2; #endif
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_discover_devices(int bus_num, ATCAIfaceCfg cfg[], int *found)
{
ATCAIfaceCfg *head = cfg;
uint8_t slaveAddress = 0x01;
ATCADevice device;
#ifdef ATCA_NO_HEAP
struct atca_device disc_device;
struct atca_command disc_command;
struct atca_iface disc_iface;
#endif
ATCAPacket packet;
ATCA_STATUS status;
uint8_t revs608[][4] = { { 0x00, 0x00, 0x60, 0x01 }, { 0x00, 0x00, 0x60, 0x02 } };
uint8_t revs508[][4] = { { 0x00, 0x00, 0x50, 0x00 } };
uint8_t revs108[][4] = { { 0x80, 0x00, 0x10, 0x01 } };
uint8_t revs204[][4] = { { 0x00, 0x02, 0x00, 0x08 }, { 0x00, 0x02, 0x00, 0x09 }, { 0x00, 0x04, 0x05, 0x00 } };
int i;
ATCAIfaceCfg discoverCfg = {
.iface_type = ATCA_I2C_IFACE,
.devtype = ATECC508A,
.atcai2c.slave_address = 0x07,
.atcai2c.bus = bus_num,
.atcai2c.baud = 400000,
.wake_delay = 800,
.rx_retries = 3
};
if (bus_num < 0)
{
return ATCA_COMM_FAIL;
}
#ifdef ATCA_NO_HEAP
disc_device.mCommands = &disc_command;
disc_device.mIface = &disc_iface;
status = initATCADevice(&discoverCfg, &disc_device);
if (status != ATCA_SUCCESS)
{
return status;
}
device = &disc_device;
#else
device = newATCADevice(&discoverCfg);
if (device == NULL)
{
return ATCA_COMM_FAIL;
}
#endif
for (slaveAddress = 0x07; slaveAddress <= 0x78; slaveAddress++)
{
discoverCfg.atcai2c.slave_address = slaveAddress << 1;
memset(&packet, 0x00, sizeof(packet));
packet.param1 = INFO_MODE_REVISION;
packet.param2 = 0;
atInfo(device->mCommands, &packet);
if ((status = atca_execute_command(&packet, device)) != ATCA_SUCCESS)
{
continue;
}
discoverCfg.devtype = ATCA_DEV_UNKNOWN;
for (i = 0; i < (int)sizeof(revs608) / 4; i++)
{
if (memcmp(&packet.data[1], &revs608[i], 4) == 0)
{
discoverCfg.devtype = ATECC608A;
break;
}
}
for (i = 0; i < (int)sizeof(revs508) / 4; i++)
{
if (memcmp(&packet.data[1], &revs508[i], 4) == 0)
{
discoverCfg.devtype = ATECC508A;
break;
}
}
for (i = 0; i < (int)sizeof(revs204) / 4; i++)
{
if (memcmp(&packet.data[1], &revs204[i], 4) == 0)
{
discoverCfg.devtype = ATSHA204A;
break;
}
}
for (i = 0; i < (int)sizeof(revs108) / 4; i++)
{
if (memcmp(&packet.data[1], &revs108[i], 4) == 0)
{
discoverCfg.devtype = ATECC108A;
break;
}
}
if (discoverCfg.devtype != ATCA_DEV_UNKNOWN)
{
(*found)++;
memcpy( (uint8_t*)head, (uint8_t*)&discoverCfg, sizeof(ATCAIfaceCfg));
head->devtype = discoverCfg.devtype;
head++;
}
atca_delay_ms(15);
}
#ifdef ATCA_NO_HEAP
releaseATCADevice(device);
#else
deleteATCADevice(&device);
#endif
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_init(void *hal, ATCAIfaceCfg *cfg)
{
if (cfg->atcai2c.bus >= MAX_I2C_BUSES)
{
return ATCA_COMM_FAIL;
}
ATCAI2CMaster_t* data = &i2c_hal_data[cfg->atcai2c.bus];
if (data->ref_ct <= 0)
{
i2c_master_get_config_defaults(&config_i2c_master);
config_i2c_master.unknown_bus_state_timeout = 500;
config_i2c_master.baud_rate = cfg->atcai2c.baud / 1000;
switch (cfg->atcai2c.bus)
{
case 0:
data->i2c_sercom = SERCOM0;
#ifdef __SAMD21G18A__
config_i2c_master.pinmux_pad0 = PINMUX_PA08C_SERCOM0_PAD0;
config_i2c_master.pinmux_pad1 = PINMUX_PA09C_SERCOM0_PAD1;
#endif
break;
case 1:
data->i2c_sercom = SERCOM1;
#ifdef __SAMR21G18A__
config_i2c_master.pinmux_pad0 = PINMUX_PA16C_SERCOM1_PAD0;
config_i2c_master.pinmux_pad1 = PINMUX_PA17C_SERCOM1_PAD1;
#endif
break;
case 2:
data->i2c_sercom = SERCOM2;
break;
case 3:
data->i2c_sercom = SERCOM3;
break;
case 4:
data->i2c_sercom = SERCOM4;
break;
case 5:
data->i2c_sercom = SERCOM5;
break;
default:
return ATCA_COMM_FAIL;
}
i2c_master_init(&data->i2c_master_instance, data->i2c_sercom, &config_i2c_master);
i2c_master_enable(&data->i2c_master_instance);
data->bus_index = cfg->atcai2c.bus;
data->ref_ct = 1;
}
else
{
data->ref_ct++;
}
((ATCAHAL_t*)hal)->hal_data = data;
return ATCA_SUCCESS;
}
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);
struct i2c_master_packet packet = {
.address = cfg->atcai2c.slave_address >> 1,
.data_length = txlength,
.data = txdata,
.ten_bit_address = false,
.high_speed = false,
.hs_master_code = 0x0,
};
txdata[0] = 0x03; txlength++; packet.data_length = txlength;
if (i2c_master_write_packet_wait(&i2c_hal_data[cfg->atcai2c.bus].i2c_master_instance, &packet) != STATUS_OK)
{
return ATCA_COMM_FAIL;
}
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_receive(ATCAIface iface, uint8_t *rxdata, uint16_t *rxlength)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
int retries = cfg->rx_retries;
int status = !ATCA_SUCCESS;
uint16_t rxdata_max_size = *rxlength;
struct i2c_master_packet packet = {
.address = cfg->atcai2c.slave_address >> 1,
.data_length = 1,
.data = rxdata,
.ten_bit_address = false,
.high_speed = false,
.hs_master_code = 0x0,
};
*rxlength = 0;
if (rxdata_max_size < 1)
{
return ATCA_SMALL_BUFFER;
}
while (retries-- > 0 && status != ATCA_SUCCESS)
{
if (i2c_master_read_packet_wait(&i2c_hal_data[cfg->atcai2c.bus].i2c_master_instance, &packet) != STATUS_OK)
{
status = ATCA_COMM_FAIL;
}
else
{
status = ATCA_SUCCESS;
}
}
if (status != ATCA_SUCCESS)
{
return status;
}
if (rxdata[0] < ATCA_RSP_SIZE_MIN)
{
return ATCA_INVALID_SIZE;
}
if (rxdata[0] > rxdata_max_size)
{
return ATCA_SMALL_BUFFER;
}
packet.data_length = rxdata[0] - 1;
packet.data = &rxdata[1];
if (i2c_master_read_packet_wait(&i2c_hal_data[cfg->atcai2c.bus].i2c_master_instance, &packet) != STATUS_OK)
{
status = ATCA_COMM_FAIL;
}
else
{
status = ATCA_SUCCESS;
}
if (status != ATCA_SUCCESS)
{
return status;
}
*rxlength = rxdata[0];
return ATCA_SUCCESS;
}
void change_i2c_speed(ATCAIface iface, uint32_t speed)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
ATCAI2CMaster_t* data = &i2c_hal_data[cfg->atcai2c.bus];
i2c_master_disable(&data->i2c_master_instance);
config_i2c_master.buffer_timeout = 10000;
config_i2c_master.baud_rate = speed / 1000;
i2c_master_init(&data->i2c_master_instance, data->i2c_sercom, &config_i2c_master);
i2c_master_enable(&data->i2c_master_instance);
}
ATCA_STATUS hal_i2c_wake(ATCAIface iface)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
int retries = cfg->rx_retries;
uint32_t bdrt = cfg->atcai2c.baud;
int status = !STATUS_OK;
uint8_t data[4];
if (bdrt != 100000) {
change_i2c_speed(iface, 100000);
}
struct i2c_master_packet packet = {
.address = 0x00,
.data_length = 0,
.data = &data[0],
.ten_bit_address = false,
.high_speed = false,
.hs_master_code = 0x0,
};
i2c_master_write_packet_wait(&i2c_hal_data[cfg->atcai2c.bus].i2c_master_instance, &packet);
atca_delay_us(cfg->wake_delay);
packet.address = cfg->atcai2c.slave_address >> 1;
packet.data_length = 4;
packet.data = data;
while (retries-- > 0 && status != STATUS_OK)
{
status = i2c_master_read_packet_wait(&i2c_hal_data[cfg->atcai2c.bus].i2c_master_instance, &packet);
}
if (bdrt != 100000)
{
change_i2c_speed(iface, bdrt);
}
if (status != STATUS_OK)
{
return ATCA_COMM_FAIL;
}
return hal_check_wake(data, 4);
}
ATCA_STATUS hal_i2c_idle(ATCAIface iface)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
uint8_t data[4];
struct i2c_master_packet packet = {
.address = cfg->atcai2c.slave_address >> 1,
.data_length = 1,
.data = &data[0],
.ten_bit_address = false,
.high_speed = false,
.hs_master_code = 0x0,
};
data[0] = 0x02; if (i2c_master_write_packet_wait(&i2c_hal_data[cfg->atcai2c.bus].i2c_master_instance, &packet) != STATUS_OK)
{
return ATCA_COMM_FAIL;
}
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_sleep(ATCAIface iface)
{
ATCAIfaceCfg *cfg = atgetifacecfg(iface);
uint8_t data[4];
struct i2c_master_packet packet = {
.address = cfg->atcai2c.slave_address >> 1,
.data_length = 1,
.data = &data[0],
.ten_bit_address = false,
.high_speed = false,
.hs_master_code = 0x0,
};
data[0] = 0x01; if (i2c_master_write_packet_wait(&i2c_hal_data[cfg->atcai2c.bus].i2c_master_instance, &packet) != STATUS_OK)
{
return ATCA_COMM_FAIL;
}
return ATCA_SUCCESS;
}
ATCA_STATUS hal_i2c_release(void *hal_data)
{
ATCAI2CMaster_t *hal = (ATCAI2CMaster_t*)hal_data;
if (hal && --(hal->ref_ct) <= 0)
{
i2c_master_reset(&(hal->i2c_master_instance));
hal->ref_ct = 0;
}
return ATCA_SUCCESS;
}