// Functions that directly control the hardware

#include "CM_LIB.h"
#include "CM_I2C.h"
#include "CM_I2C_L.h"
#include <unistd.h>
#include <stdio.h>
#include "linux/fcntl.h"
#include "driver.h"
#include <string.h>
// Delay
void cm_Delay(uint8_t ucDelay)
{
	// uint32_t ucTimer;
	// uint8_t a = 1,b = 2;  
 //    while(ucDelay) {
 //    	ucTimer = 3000; //2000;
 //        while(ucTimer) 
 //        {
 //            ucTimer--;
 //            a = a*b;
 //        }
 //    	ucDelay--;
 //    }	
    usleep(ucDelay);
}

#if 0
// 1/2 Clock Cycle transition to HIGH
//
void cm_Clockhigh(void)
{
    cm_Delay(1);
    CM_CLK_HI;
    cm_Delay(1);
}

// 1/2 Clock Cycle transition to LOW
//
void cm_Clocklow(void)
{
    cm_Delay(1);
    CM_CLK_LO;
    cm_Delay(1);
}

// Do one full clock cycle
//
// Changed 1/19/05 to eliminate one level of return stack requirements
//
void cm_ClockCycle(void)
{
    cm_Clocklow();
    cm_Clockhigh();
}

// Do a number of clock cycles
//
void cm_ClockCycles(uint8_t ucCount)
{
    uint8_t i;
    
    for (i = 0; i < ucCount; ++i) cm_ClockCycle();
}

// Send a start sequence
//
// Modified 7-21-04 to correctly set SDA to be an output
// 
void cm_Start(void)
{
	cm_Delay(50);//by jgw for delay to avoid i2c dead because of too fast
	  CM_DATA_OUT;                         // Data line must be an output to send a start sequence
	  //cm_Clocklow();
	  CM_DATA_HI;
	  cm_Delay(4);
	  cm_Clockhigh();
	  cm_Delay(40);    //4
	  CM_DATA_LO;
	  cm_Delay(8);
	  cm_Clocklow();
	  cm_Delay(8);
}

// Send a stop sequence
//
// Modified 7-21-04 to correctly set SDA to be an output
// 
void cm_Stop(void)
{
	cm_Delay(10);//by jgw for delay to avoid i2c dead because of too fast
	cm_Clocklow();
    CM_DATA_OUT;                         // Data line must be an output to send a stop sequence
	CM_DATA_LO;
	cm_Delay(4); 
	cm_Clockhigh();
	cm_Delay(80);  //8
	CM_DATA_HI;
	cm_Delay(4);
}

// Write a byte
//
// Returns 0 if write successed, 1 if write fails failure
//
// Modified 7-21-04 to correctly control SDA
// 
uint8_t cm_Write(uint8_t ucData)
{
    uint8_t i;

	cm_Delay(10);//by jgw for delay to avoid i2c dead because of too fast
    CM_DATA_OUT;                         // Set data line to be an output
    for(i=0; i<8; i++) {                 // Send 8 bits of data
        cm_Clocklow();
        if (ucData&0x80) CM_DATA_HI;
        else             CM_DATA_LO;
        cm_Clockhigh();
        ucData = ucData<<1;
    }
    cm_Clocklow();

    // wait for the ack
    CM_DATA_IN;                      // Set data line to be an input
    cm_Delay(8);
    cm_Clockhigh();
    while(i>1) {                    // loop waiting for ack (loop above left i == 8)
        cm_Delay(2);
        if (CM_DATA_RD) i--;        // if SDA is high level decrement retry counter
        else i = 0;
    }      
    cm_Clocklow();
    CM_DATA_OUT;                     // Set data line to be an output
    return i;
}

// Send a ACK or NAK or to the device
void cm_AckNak(uint8_t ucAck)
{
	cm_Delay(10);//by jgw for delay to avoid i2c dead because of too fast
	CM_DATA_OUT;                         // Data line must be an output to send an ACK
	cm_Clocklow();
	if (ucAck) CM_DATA_LO;               // Low on data line indicates an ACK
	else       CM_DATA_HI;               // High on data line indicates an NACK
	cm_Delay(2);
	cm_Clockhigh();
	cm_Delay(8);
	cm_Clocklow();
}

//     Read a byte from device, MSB
//
// Modified 7-21-04 to correctly control SDA
// 
uint8_t cm_Read(void)
{
	uint8_t i;
	uint8_t rByte = 0;	
	CM_DATA_IN;                          // Set data line to be an input
	CM_DATA_HI;
	for(i=0x80; i; i=i>>1)
	{
		cm_ClockCycle();
		if (CM_DATA_RD) rByte |= i;
		cm_Clocklow();
	}
	CM_DATA_OUT;                         // Set data line to be an output
	return rByte;
}
#endif

void cm_WaitClock(uint8_t loop)
{
	int ret;
	
    crypto_t crypto_arg;
    crypto_arg.loop = loop;

    int fd = open("/dev/crypto", O_RDWR);
    if(fd <= 0)
    {
        printf("Open /dev/crypto error!\n");
        return;
    }

    ret = ioctl(fd, CRYPTO_WAIT_CLOCK, &crypto_arg);
    if(ret != 0)
    {
        printf("cm_WaitClock error!\n");
    }
    close(fd);

	// CM_DATA_LO;
	// for(j=0; j<loop; j++) {
	// 	cm_Start();
	// 	for(i = 0; i<15; i++) cm_ClockCycle();
	// 	cm_Stop();
	// }
}

// Send a command
//
uint8_t cm_SendCommand(uint8_t * pucInsBuff)
{
    
	
    //uint8_t i, ucCmd;
    //i = CM_START_TRIES;
    //ucCmd = (pucInsBuff[0]&0x0F)|CM_PORT_CFG.ucChipSelect;
    // while (i) {
    //     cm_Start();
    //     printf("cm_SendCommand ucCmd=%#x\n", ucCmd);
    //     if (cm_Write(ucCmd) == 0) break;
    //     if (--i == 0) {printf("---> cm_SendCommand log1\n"); return FAIL_CMDSTART;}
    // }
	
    // for(i = 1; i< 4; i++) 
    // {
    //     cm_Delay(1);
    //     printf("cm_SendCommand i=%d, data=%#x\n", i, pucInsBuff[i]);
    //     if (cm_Write(pucInsBuff[i]) != 0) 
    //     {
    //         printf("---> cm_SendCommand log2, i = %d\n", i); 
    //         return FAIL_CMDSEND;
    //     }
    // }
    int ret;
    crypto_t crypto_arg;
    int fd = open("/dev/crypto", O_RDWR);
    if(fd <= 0)
    {
        printf("Open /dev/crypto error!\n");
        return FAIL_CMDSEND;
    }

    crypto_arg.data[0] =  (pucInsBuff[0]&0x0F)|CM_PORT_CFG.ucChipSelect;
    crypto_arg.data[1] = pucInsBuff[1];
    crypto_arg.data[2] = pucInsBuff[2];
    crypto_arg.data[3] = pucInsBuff[3];
    crypto_arg.size = 4;
    ret = ioctl(fd, CRYPTO_SEND_COMMAND, &crypto_arg);
    if(ret != 0)
    {
        printf("cm_SendCommand failed!\n");
        close(fd);
        return FAIL_CMDSEND;
    }
    close(fd);
    return SUCCESS;
}

uint8_t cm_ReceiveData(uint8_t * pucRecBuf, uint8_t ucLen)
{
    // int i;

    // for(i = 0; i < (ucLen-1); i++) {
    //     pucRecBuf[i] = cm_Read();
    //     cm_AckNak(TRUE);
    // }
    // pucRecBuf[i] = cm_Read();
    // cm_AckNak(FALSE);
    // cm_Stop();
    int ret;
    crypto_t crypto_arg;
    int fd = open("/dev/crypto", O_RDWR);
    if(fd <= 0)
    {
        printf("Open /dev/crypto error!\n");
        return -1;
    }
    crypto_arg.size = ucLen;
    ret = ioctl(fd, CRYPTO_RECEIVE_DATA, &crypto_arg);
    if(ret != 0)
    {
        printf("cm_ReceiveData failed!\n");
        close(fd);
        return -1;
    }
    close(fd);

    memcpy(pucRecBuf, crypto_arg.data, ucLen);
    return SUCCESS;
}

uint8_t cm_SendData(uint8_t * pucSendBuf, uint8_t ucLen)
{
	// int i;
	// for(i = 0; i< ucLen; i++) {
	// 	if (cm_Write(pucSendBuf[i])==1) {printf("---> cm_SendData log1, i=%d\n", i); return FAIL_WRDATA;}
	// }
	// cm_Stop();

    int ret;
    crypto_t crypto_arg;
    int fd = open("/dev/crypto", O_RDWR);
    if(fd <= 0)
    {
        printf("Open /dev/crypto error!\n");
        return FAIL_WRDATA;
    }

    memcpy(crypto_arg.data, pucSendBuf, ucLen);
    crypto_arg.size = ucLen;
    ret = ioctl(fd, CRYPTO_SEND_DATA, &crypto_arg);
    if(ret != 0)
    {
        printf("cm_SendData failed!\n");
        close(fd);
        return FAIL_WRDATA;
    }
    close(fd);
	
	return SUCCESS;
}


// Send a command byte
//
uint8_t cm_SendCmdByte(uint8_t ucCommand)
{
    // uint8_t i, ucCmd;
	
    // i = CM_START_TRIES;

    // ucCmd = (ucCommand&0x0F)|CM_PORT_CFG.ucChipSelect;
    // while (i) {
    //   cm_Start();
	   //  if (cm_Write(ucCmd) == 0) break;
	   //  if (--i == 0) return FAIL_CMDSTART;
    // }

    int ret;
    crypto_t crypto_arg;
    int fd = open("/dev/crypto", O_RDWR);
    if(fd <= 0)
    {
        printf("Open /dev/crypto error!\n");
        return FAIL_CMDSTART;
    }

    crypto_arg.data[0] = (ucCommand&0x0F)|CM_PORT_CFG.ucChipSelect;
    
    ret = ioctl(fd, CRYPTO_SEND_CMD_BYTE, &crypto_arg);
    if(ret != 0)
    {
        printf("cm_SendCmdByte failed!\n");
        close(fd);
        return FAIL_CMDSTART;
    }
    close(fd);

    return SUCCESS;
}
