#include <stdlib.h>
#include <stdio.h>
#include "atca_compiler.h"
#include "kit_phy.h"
#include "kit_protocol.h"
#include "basic/atca_helpers.h"
#define KIT_MAX_SCAN_COUNT 4
#define KIT_MAX_TX_BUF 32
#ifndef strnchr
char * strnchr(const char * s, size_t count, int c)
{
size_t i;
for (i = 0; i < count; i++)
{
if (s[i] == c)
{
return (char*)&s[i];
}
}
return NULL;
}
#endif
const char * kit_id_from_devtype(ATCADeviceType devtype)
{
switch (devtype)
{
case ATSHA204A:
return "SHA204A";
case ATECC108A:
return "ECC108A";
case ATECC508A:
return "ECC508A";
case ATECC608A:
return "ECC608A";
case ATSHA206A:
return "SHA206A";
default:
return "unknown";
}
}
const char * kit_interface_from_kittype(ATCAKitType kittype)
{
switch (kittype)
{
case ATCA_KIT_I2C_IFACE:
return "TWI";
case ATCA_KIT_SWI_IFACE:
return "SWI";
default:
return "unknown";
}
}
ATCA_STATUS kit_init(ATCAIface iface)
{
ATCA_STATUS status = ATCA_SUCCESS;
const char kit_device[] = "board:device(%02X)\n";
const char kit_device_select[] = "%c:physical:select(%02X)\n";
char txbuf[KIT_MAX_TX_BUF];
int txlen;
char rxbuf[KIT_RX_WRAP_SIZE + 4];
int rxlen;
char* device_match, *interface_match;
char *dev_type, *dev_interface;
char delim[] = " ";
char *token;
int i;
int address;
device_match = kit_id_from_devtype(iface->mIfaceCFG->devtype);
interface_match = kit_interface_from_kittype(iface->mIfaceCFG->atcahid.dev_interface);
for (i = 0; i < KIT_MAX_SCAN_COUNT; i++)
{
txlen = snprintf(txbuf, sizeof(txbuf) - 2, kit_device, i);
txbuf[sizeof(txbuf) - 1] = '\0';
if (txlen < 0)
{
status = ATCA_INVALID_SIZE;
break;
}
if (ATCA_SUCCESS != (status = kit_phy_send(iface, txbuf, txlen)))
{
break;
}
rxlen = sizeof(rxbuf);
memset(rxbuf, 0, rxlen);
if (ATCA_SUCCESS != (status = kit_phy_receive(iface, rxbuf, &rxlen)))
{
break;
}
token = rxbuf;
dev_type = strtok_r(NULL, delim, &token);
dev_interface = strtok_r(NULL, delim, &token);
char * addr = strnchr(rxbuf, rxlen, '(');
address = 0;
if (!addr)
{
status = ATCA_GEN_FAIL;
break;
}
if (1 != sscanf(addr, "(%02X)", &address))
{
status = ATCA_GEN_FAIL;
break;
}
if (iface->mIfaceCFG->atcahid.dev_interface == ATCA_KIT_AUTO_IFACE && iface->mIfaceCFG->atcahid.dev_identity == 0 && (strcmp(device_match, dev_type) == 0))
{
txlen = snprintf(txbuf, sizeof(txbuf) - 1, kit_device_select, device_match[0], address);
txbuf[sizeof(txbuf) - 1] = '\0';
if (txlen < 0)
{
status = ATCA_INVALID_SIZE;
break;
}
if (ATCA_SUCCESS != (status = kit_phy_send(iface, txbuf, txlen)))
{
break;
}
rxlen = sizeof(rxbuf);
status = kit_phy_receive(iface, rxbuf, &rxlen);
break;
}
else
{
if ((strcmp(device_match, dev_type) == 0) && (iface->mIfaceCFG->atcahid.dev_identity == address) && (strcmp(interface_match, dev_interface) == 0))
{
txlen = snprintf(txbuf, sizeof(txbuf) - 1, kit_device_select, device_match[0], address);
txbuf[sizeof(txbuf) - 1] = '\0';
if (txlen < 0)
{
status = ATCA_INVALID_SIZE;
break;
}
if (ATCA_SUCCESS != (status = kit_phy_send(iface, txbuf, txlen)))
{
break;
}
rxlen = sizeof(rxbuf);
status = kit_phy_receive(iface, rxbuf, &rxlen);
break;
}
}
}
if ((KIT_MAX_SCAN_COUNT == i) && !status)
{
status = ATCA_NO_DEVICES;
}
return status;
}
ATCA_STATUS kit_send(ATCAIface iface, const uint8_t* txdata, int txlength)
{
ATCA_STATUS status = ATCA_SUCCESS;
int nkitbuf = txlength * 2 + KIT_TX_WRAP_SIZE;
char* pkitbuf = NULL;
char *target;
if (txdata == NULL)
{
return ATCA_BAD_PARAM;
}
pkitbuf = malloc(nkitbuf);
memset(pkitbuf, 0, nkitbuf);
target = kit_id_from_devtype(iface->mIfaceCFG->devtype);
status = kit_wrap_cmd(&txdata[1], txlength, pkitbuf, &nkitbuf, target[0]);
if (status != ATCA_SUCCESS)
{
free(pkitbuf);
return ATCA_GEN_FAIL;
}
status = kit_phy_send(iface, pkitbuf, nkitbuf);
#ifdef KIT_DEBUG
printf("\nKit Write: %s", pkitbuf);
#endif
free(pkitbuf);
return status;
}
ATCA_STATUS kit_receive(ATCAIface iface, uint8_t* rxdata, uint16_t* rxsize)
{
ATCA_STATUS status = ATCA_SUCCESS;
uint8_t kitstatus = 0;
int nkitbuf = 0;
int dataSize;
char pkitbuf[256 * 2 + KIT_RX_WRAP_SIZE];
if ((rxdata == NULL) || (rxsize == NULL))
{
return ATCA_BAD_PARAM;
}
dataSize = *rxsize;
*rxsize = 0;
memset(pkitbuf, 0, sizeof(pkitbuf));
nkitbuf = sizeof(pkitbuf);
status = kit_phy_receive(iface, pkitbuf, &nkitbuf);
if (status != ATCA_SUCCESS)
{
return ATCA_GEN_FAIL;
}
#ifdef KIT_DEBUG
printf("Kit Read: %s\r", pkitbuf);
#endif
status = kit_parse_rsp(pkitbuf, nkitbuf, &kitstatus, rxdata, &dataSize);
if (status != ATCA_SUCCESS)
{
return status;
}
*rxsize = (uint16_t)dataSize;
return ATCA_SUCCESS;
}
ATCA_STATUS kit_wake(ATCAIface iface)
{
ATCA_STATUS status = ATCA_SUCCESS;
uint8_t kitstatus = 0;
char wake[] = "d:w()\n";
int wakesize = sizeof(wake);
char reply[KIT_RX_WRAP_SIZE + 4];
int replysize = sizeof(reply);
uint8_t rxdata[10];
int rxsize = sizeof(rxdata);
char *target;
target = kit_id_from_devtype(iface->mIfaceCFG->devtype);
wake[0] = target[0];
status = kit_phy_send(iface, wake, wakesize);
#ifdef KIT_DEBUG
printf("\nKit Write: %s", wake);
#endif
memset(reply, 0, replysize);
status = kit_phy_receive(iface, reply, &replysize);
if (status != ATCA_SUCCESS)
{
return ATCA_GEN_FAIL;
}
#ifdef KIT_DEBUG
printf("Kit Read: %s\n", reply);
#endif
memset(rxdata, 0, rxsize);
status = kit_parse_rsp(reply, replysize, &kitstatus, rxdata, &rxsize);
return hal_check_wake(rxdata, rxsize);
}
ATCA_STATUS kit_idle(ATCAIface iface)
{
ATCA_STATUS status = ATCA_SUCCESS;
uint8_t kitstatus = 0;
char idle[] = "d:i()\n";
int idlesize = sizeof(idle);
char reply[KIT_RX_WRAP_SIZE];
int replysize = sizeof(reply);
uint8_t rxdata[10];
int rxsize = sizeof(rxdata);
char *target;
target = kit_id_from_devtype(iface->mIfaceCFG->devtype);
idle[0] = target[0];
status = kit_phy_send(iface, idle, idlesize);
#ifdef KIT_DEBUG
printf("\nKit Write: %s", idle);
#endif
memset(reply, 0, replysize);
status = kit_phy_receive(iface, reply, &replysize);
if (status != ATCA_SUCCESS)
{
return ATCA_GEN_FAIL;
}
#ifdef KIT_DEBUG
printf("Kit Read: %s\r", reply);
#endif
memset(rxdata, 0, rxsize);
status = kit_parse_rsp(reply, replysize, &kitstatus, rxdata, &rxsize);
return status;
}
ATCA_STATUS kit_sleep(ATCAIface iface)
{
ATCA_STATUS status = ATCA_SUCCESS;
uint8_t kitstatus = 0;
char sleep[] = "d:s()\n";
int sleepsize = sizeof(sleep);
char reply[KIT_RX_WRAP_SIZE];
int replysize = sizeof(reply);
uint8_t rxdata[10];
int rxsize = sizeof(rxdata);
char* target;
target = kit_id_from_devtype(iface->mIfaceCFG->devtype);
sleep[0] = target[0];
status = kit_phy_send(iface, sleep, sleepsize);
#ifdef KIT_DEBUG
printf("\nKit Write: %s", sleep);
#endif
memset(reply, 0, replysize);
status = kit_phy_receive(iface, reply, &replysize);
if (status != ATCA_SUCCESS)
{
return ATCA_GEN_FAIL;
}
#ifdef KIT_DEBUG
printf("Kit Read: %s\r", reply);
#endif
memset(rxdata, 0, rxsize);
status = kit_parse_rsp(reply, replysize, &kitstatus, rxdata, &rxsize);
return status;
}
ATCA_STATUS kit_wrap_cmd(const uint8_t* txdata, int txlen, char* pkitcmd, int* nkitcmd, char target)
{
ATCA_STATUS status = ATCA_SUCCESS;
char cmdpre[] = "d:t(";
char cmdpost[] = ")\n";
size_t cmdAsciiLen = txlen * 2;
size_t cmdlen = txlen * 2 + sizeof(cmdpre) + sizeof(cmdpost) - 1;
size_t cpylen = 0;
size_t cpyindex = 0;
if (txdata == NULL || pkitcmd == NULL || nkitcmd == NULL)
{
return ATCA_BAD_PARAM;
}
if (*nkitcmd < (int)cmdlen)
{
return ATCA_SMALL_BUFFER;
}
memset(pkitcmd, 0, *nkitcmd);
cpylen = strlen(cmdpre);
memcpy(&pkitcmd[cpyindex], cmdpre, cpylen);
cpyindex += cpylen;
pkitcmd[0] = target;
status = atcab_bin2hex_(txdata, txlen, &pkitcmd[cpyindex], &cmdAsciiLen, false, false, true);
if (status != ATCA_SUCCESS)
{
return status;
}
cpyindex += cmdAsciiLen;
cpylen = strlen(cmdpost);
memcpy(&pkitcmd[cpyindex], cmdpost, cpylen);
cpyindex += cpylen;
*nkitcmd = (int)cpyindex;
return status;
}
ATCA_STATUS kit_parse_rsp(const char* pkitbuf, int nkitbuf, uint8_t* kitstatus, uint8_t* rxdata, int* datasize)
{
ATCA_STATUS status = ATCA_SUCCESS;
int statusId = 0;
int dataId = 3;
size_t binSize = 1;
size_t asciiDataSize = 0;
size_t datasizeTemp = *datasize;
char* endDataPtr = 0;
status = atcab_hex2bin(&pkitbuf[statusId], 2, kitstatus, &binSize);
if (status != ATCA_SUCCESS)
{
return status;
}
endDataPtr = strnchr((char*)pkitbuf, nkitbuf, ')');
if (endDataPtr < (&pkitbuf[dataId]))
{
return ATCA_GEN_FAIL;
}
asciiDataSize = endDataPtr - (&pkitbuf[dataId]);
status = atcab_hex2bin(&pkitbuf[dataId], asciiDataSize, rxdata, &datasizeTemp);
*datasize = (int)datasizeTemp;
if (status != ATCA_SUCCESS)
{
return status;
}
return ATCA_SUCCESS;
}