// TODO 1.01
    SYS_CMD_PRINT("Hello world\r\n");


// TODO 2.01
    SYS_TIME_HANDLE timer = SYS_TIME_HANDLE_INVALID;
    SYS_TIME_DelayMS( 1000, &timer );


// TODO 2.02
        if( SYS_TIME_DelayIsComplete(timer) )
        {
            LED_Toggle();
            SYS_TIME_DelayMS( 1000, &timer );
        }


// TODO 3.01
void CommandHello(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    SYS_CMD_PRINT("\r\n- Hello Command!\r\n");
}


// TODO 3.02
static const SYS_CMD_DESCRIPTOR CryptoCmdTbl[]=
{
    { "hello", CommandHello, ": Hello!" },
};


// TODO 3.03
SYS_CMD_ADDGRP(
    CryptoCmdTbl,
    sizeof(CryptoCmdTbl)/sizeof(SYS_CMD_DESCRIPTOR),
    "CRYPTOCMD",
    ": Crypto Commands" );


// TODO 3.04
if( argc>1 )
{
    for( int i=1 ; i<argc ; i++ )
    {
      SYS_CMD_PRINT(" > Param %d :%s\r\n", i, argv[i] );
    }
}


// TODO 4.01
#include "cryptoauthlib.h"

extern ATCAIfaceCfg atecc608_0_init_data;
ATCA_STATUS status;


// TODO 4.02
#define CHECK_STATUS( status )\
{\
    if(status != ATCA_SUCCESS )\
    {\
        SYS_CMD_PRINT("Error: Line %d in %s\r\n", __LINE__, __FILE__);\
    }\
}\


// TODO 4.03
void CommandInit(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    if( argc>1 )
    {
        unsigned char SlaveAddr;
        SlaveAddr = (unsigned char)strtol(argv[1], NULL, 16)<<1;
        atecc608_0_init_data.atcai2c.address = SlaveAddr;
        SYS_CMD_PRINT("\r\nInitial CryptoAuthLib:\r\n");
        SYS_CMD_PRINT("- i2caddr Byte = %X\r\n", SlaveAddr);
        status = atcab_init(&atecc608_0_init_data);
        CHECK_STATUS(status);
    }
    else
        SYS_CMD_PRINT("\r\nNo target I2C addess of device !!\r\n");
}


// TODO 4.04
    { "init",  CommandInit, ": Initial CryptoAuthLib" },


// TODO 5.01
uint8_t ecc_version[ATCA_WORD_SIZE];
uint8_t serial_number[ATCA_SERIAL_NUM_SIZE];


// TODO 5.02
void OutputData(char* label, uint8_t* buffer, size_t len)
{
    SYS_CMD_PRINT("%s", label);
    for( int i=0 ; i<len ; i++ )
    {
        SYS_CMD_PRINT("%02X ", buffer[i]);
        if( (i+1)%16==0 )
        {
            SYS_CMD_PRINT("\r\n");
        }
    }
    SYS_CMD_PRINT("\r\n");
    while( SYS_CONSOLE_WriteCountGet(SYS_CONSOLE_DEFAULT_INSTANCE) );
}


// TODO 5.03
void CommandReadSN(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    status = atcab_info((uint8_t*)&ecc_version);
    CHECK_STATUS(status);
    OutputData( "\r\nECC version:\r\n", ecc_version, ATCA_WORD_SIZE);

    status = atcab_read_serial_number((uint8_t*)&serial_number);
    CHECK_STATUS(status);
    OutputData( "\r\nSerial Number:\r\n", serial_number, ATCA_SERIAL_NUM_SIZE);
}


// TODO 5.04
    { "readsn", CommandReadSN, ": READ Version and S/N number" },


// TODO 6.01
#include "host/atca_host.h"


// TODO 6.02
uint8_t rand_out[32];
atca_nonce_in_out_t host_nonce;
atca_temp_key_t host_tempkey;
const uint8_t num_in[] = {
    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, \
    0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20 };


// TODO 6.03
void CommandRandom(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
	status = atcab_random(rand_out);
	CHECK_STATUS(status);
	SYS_CMD_PRINT("\r\nRANDOM Command:\r\n");
	OutputData("- Random number out:\r\n", rand_out, 32);
}


// TODO 6.04
void CommandNonce(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
	status = atcab_nonce_base(NONCE_MODE_SEED_UPDATE, 0, num_in, rand_out);
	CHECK_STATUS(status);
	SYS_CMD_PRINT("\r\nNONCE Command:\r\n");
	OutputData("- Random number response:\r\n", rand_out, 32);

	host_nonce.mode = NONCE_MODE_SEED_UPDATE;
	host_nonce.zero = 0;
	host_nonce.num_in = num_in;
	host_nonce.rand_out = rand_out;
	host_nonce.temp_key = &host_tempkey;
	status = atcah_nonce(&host_nonce);
	CHECK_STATUS(status);
	OutputData("- Host Tempkey:\r\n", host_tempkey.value, 32);
}


// TODO 6.05
    { "random", CommandRandom, ": RANDOM command" },
    { "nonce", CommandNonce, ": NONCE command" },


// TODO 7.01
uint8_t test_ecc608_configdata[ATCA_ECC_CONFIG_SIZE] = {
    0x01, 0x23, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x04, 0x05, 0x06, 0x07, 0xEE, 0x01, 0x01, 0x00,
    0xC0, 0x00, 0xA1, 0x00, 0xAF, 0x2F, 0xC4, 0x44, 0x87, 0x20, 0xC4, 0xF4, 0x8F, 0x0F, 0x0F, 0x0F,
    0x9F, 0x8F, 0x83, 0x64, 0xC4, 0x44, 0xC4, 0x64, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
    0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
    0x00, 0x00, 0x00, 0x00, 0xFF, 0x84, 0x03, 0xBC, 0x09, 0x69, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0E, 0x40, 0x00, 0x00, 0x00, 0x00,
    0x33, 0x00, 0x1C, 0x00, 0x13, 0x00, 0x1C, 0x00, 0x3C, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x33, 0x00,
    0x1C, 0x00, 0x1C, 0x00, 0x38, 0x10, 0x30, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0x32, 0x00, 0x30, 0x00
};
const uint8_t g_slot4_key[] = {
    0x37, 0x80, 0xe6, 0x3d, 0x49, 0x68, 0xad, 0xe5,
    0xd8, 0x22, 0xc0, 0x13, 0xfc, 0xc3, 0x23, 0x84,
    0x5d, 0x1b, 0x56, 0x9f, 0xe7, 0x05, 0xb6, 0x00,
    0x06, 0xfe, 0xec, 0x14, 0x5a, 0x0d, 0xb1, 0xe3
};


// TODO 7.02
void CommandProvision(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    status = atcab_write_config_zone(test_ecc608_configdata);
    CHECK_STATUS(status);

    status = atcab_lock_config_zone();
    CHECK_STATUS(status);

    status = atcab_write_zone(ATCA_ZONE_DATA, 4, 0, 0, g_slot4_key, 32 );
    CHECK_STATUS(status);

    status = atcab_lock_data_zone();
    CHECK_STATUS(status);

    SYS_CMD_PRINT("\r\nProvision done!!\r\n");
}


// TODO 7.03
    { "provision", CommandProvision, ": Provision new chip" },


// TODO 8.01
atca_mac_in_out_t host_mac;
uint16_t key_id;
uint8_t digest[32];
uint8_t response[32];


// TODO 8.02
void CommandMac(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    if( argc>1 )
    {
        key_id  = (unsigned char)strtol(argv[1], NULL, 16);
        status = atcab_mac(MAC_MODE_BLOCK2_TEMPKEY|MAC_MODE_INCLUDE_SN, key_id, NULL, digest);
        CHECK_STATUS(status);
        OutputData("\r\nMAC Command:\r\n- Digest out :\r\n", digest, 32);
        host_mac.mode = MAC_MODE_BLOCK2_TEMPKEY|MAC_MODE_INCLUDE_SN;
        host_mac.key_id = key_id;
        host_mac.challenge = NULL;
        host_mac.key = g_slot4_key;
        host_mac.otp = NULL;
        host_mac.sn = serial_number;
        host_mac.response = response;
        host_mac.temp_key = &host_tempkey;
        status = atcah_mac(&host_mac);
        CHECK_STATUS(status);
        OutputData("- Digest out (Host claculated) :\r\n", response, 32);
    }
    else
    {
        SYS_CMD_PRINT("\r\nNo target key slot !!\r\n");
    }
}


// TODO 8.03
    { "mac", CommandMac, ": MAC command" },


// TODO 9.01
uint8_t pubkey[64];


// TODO 9.02
void CommandGenkey(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    if( argc>1 )
    {
        memset( pubkey, 0, sizeof(pubkey) );
        key_id  = (unsigned char)strtol(argv[1], NULL, 16);
        status = atcab_genkey(key_id, pubkey);
        CHECK_STATUS(status);
        SYS_CMD_PRINT("\r\nGENKEY Command (Create Key pair):\r\n");
        OutputData("- Public key out :\r\n", pubkey, 64);
    }
    else
    {
        SYS_CMD_PRINT("\r\nNo target ECC Privet key slot !!\r\n");
    }
}


// TODO 9.03
    { "genkey", CommandGenkey, ": GENKEY command" },	


// TODO 10.01
uint8_t signature[64];


// TODO 10.02
void CommandSign(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    if( argc>1 )
    {
        key_id  = (unsigned char)strtol(argv[1], NULL, 16);
        status = atcab_sign(key_id, digest, signature);
        CHECK_STATUS(status);
        OutputData("\r\nSIGN Command:\r\n- Msg for Sign :\r\n", digest, 32);
        OutputData("- Signature out :\r\n", signature, 64);
    }
    else
    {
        SYS_CMD_PRINT("\r\nNo target ECC Privet key slot !!\r\n");
    }
}


// TODO 10.03
    { "sign", CommandSign, ": SIGN command" },	


// TODO 11.01
bool verifyReslut = false;


// TODO 11.02
void CommandVerify(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    SYS_CMD_PRINT("\r\nVERIFY Command (Extern Mode):\r\n");
    OutputData("- Msg for Verify :\r\n", digest, 32);
    OutputData("- Signature :\r\n", signature, 64);
    OutputData("- Public key :\r\n", pubkey, 64);
    status = atcab_verify_extern(digest, signature, pubkey, &verifyReslut);
    CHECK_STATUS(status);

    if( verifyReslut == true )
        SYS_CMD_PRINT("- VERIFY Success\r\n");
    else
        SYS_CMD_PRINT("- VERIFY Failure\r\n");
}


// TODO 11.03
    { "verify", CommandVerify, ": VERIFY command" },


// TODO 12.01
uint8_t RawCommandData[192];


// TODO 12.02
void CommandRawCmd(SYS_CMD_DEVICE_NODE* pCmdIO, int argc, char** argv)
{
    if( argc>1 )
    {
        uint8_t opcode, param1, *data, datalen;
        uint16_t param2;

        opcode = (uint8_t)strtol(argv[1], NULL, 16);
        param1 = (uint8_t)strtol(argv[2], NULL, 16);
        param2 = (uint16_t)(strtol(argv[4], NULL, 16)<<8 | strtol(argv[3], NULL, 16));
        if( argc>5 )
        {
            datalen = atoi(argv[6]);
            memcpy( RawCommandData, argv[5], datalen);
            data = RawCommandData;
        }
        status = atcab_rawcmd(opcode, param1, param2, data, &datalen);
        CHECK_STATUS(status);
        OutputData( "\r\nRaw Command Response:\r\n", data, datalen);
    }
}


// TODO 12.03
ATCA_STATUS atcab_rawcmd(uint8_t opcode, uint8_t param1, uint16_t param2, uint8_t *data, uint8_t *len)
{
    ATCAPacket packet;

    packet.opcode = opcode;
    packet.param1 = param1;
    packet.param2 = param2;
    memcpy(&packet.data[*len], data, *len);
    packet.txsize = 7 + *len;
    atCalcCrc(&packet);
    status = atca_execute_command(&packet, _gDevice);
    *len = packet.data[0]-3;
    memcpy(data, &packet.data[1], *len);

    return status;
}


// TODO 12.04
    { "rawcmd", CommandRawCmd, ": Raw command bytes" },
