/*
 *
 * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
 *
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include "stdafx.h"

#define DEFAULT_TIMEOUT 7000

int g_devId;
char ucErrorMessage[BUFFER_SIZE];
HANDLE g_hComPort;

void _trace_msg(UINT16 level, char * pcMessage)
{
	if(level <= TRACE_LEVEL)
	{
		printf("\n%s\n", pcMessage);
	}
}
//*****************************************************************************
//
//! OpenUART() opens the UART port.
//!
//! \param pszComPort is the text representation of the COM port to be
//!     opened. "COM1" is the valid string to use to open COM port 1 on the
//!     host.
//! \param ulBaudRate is the baud rate to configure the UART to use.
//!
//! This function is used to open the host UART with the given baud rate.  The
//! rest of the settings are fixed at No Parity, 8 data bits and 1 stop bit.
//!
//! \return The function returns zero to indicated success while any non-zero
//!     value indicates a failure.
//
//*****************************************************************************

int OpenUART(unsigned char ucComPort, unsigned long ulBaudRate)
{
	DCB sDCB;
    COMMTIMEOUTS sCommTimeouts;
	char sComPort [64];

	if(ucComPort >= 1 && ucComPort <= 9)
	{
		sprintf(sComPort, "COM%d",ucComPort);
	}
	else
	{
	// this is for handling port numbers >= 10.
		sprintf(sComPort, "\\\\.\\COM%d",ucComPort);
	}

    g_hComPort = CreateFileA(sComPort, GENERIC_READ | GENERIC_WRITE,
	0,              // exclusive access
       NULL,           // no security
       OPEN_EXISTING,
       0,              // no overlapped I/O
       NULL);          // null template

    if (g_hComPort == INVALID_HANDLE_VALUE)
    {
        return(1);
    }

    if (0 == GetCommState(g_hComPort, &sDCB))
    {
        return(1);
    }

    sDCB.BaudRate = ulBaudRate;
    sDCB.ByteSize = 8;
    sDCB.Parity = NOPARITY;
    sDCB.StopBits = ONESTOPBIT;
    sDCB.fAbortOnError = TRUE;
    sDCB.fOutxCtsFlow = FALSE;
    sDCB.fOutxDsrFlow = FALSE;
    sDCB.fDtrControl = DTR_CONTROL_ENABLE;
    if (0 == SetCommState(g_hComPort, &sDCB))
    {
        return(1);
    }

    if (0 == GetCommTimeouts(g_hComPort, &sCommTimeouts))
    {
        return(1);
    }

    
	sCommTimeouts.ReadIntervalTimeout = 0;
    sCommTimeouts.ReadTotalTimeoutConstant = DEFAULT_TIMEOUT;
    sCommTimeouts.ReadTotalTimeoutMultiplier = 1;
    sCommTimeouts.WriteTotalTimeoutConstant = 2000;
    sCommTimeouts.WriteTotalTimeoutMultiplier = 1;
	
	if (0 == SetCommTimeouts(g_hComPort, &sCommTimeouts))
    {
        return(1);
    }
    return(0);
}

//*****************************************************************************
//
//! CloseUART() closes the UART port.
//!
//! This function closes the UART port that was opened by a call to OpenUART().
//!
//! \returns This function returns zero to indicate success while any non-zero
//! value indicates a failure.
//
//*****************************************************************************
int CloseUART(void)
{
	return(CloseHandle(g_hComPort));
}

//*****************************************************************************
//
//! UARTSendData() sends data over a UART port.
//!
//! \param pucData
//!     The buffer to write out to the UART port.
//! \param ucSize
//!     The number of bytes provided in pucData buffer that should be written
//!     out to the port.
//!
//! This function sends ucSize bytes of data from the buffer pointed to by
//! pucData via the UART port that was opened by a call to OpenUART().
//!
//! \return This function returns zero to indicate success while any non-zero
//! value indicates a failure.
//
//*****************************************************************************
int UARTSendData(unsigned char const *pucData, unsigned long ucSize)
{
    unsigned long ulNumBytes;

    //
    // Send the Ack back to the device.
    //
	if (0 == WriteFile(g_hComPort, pucData, ucSize, &ulNumBytes, NULL))
    {
        return(1);
    }
    if (ulNumBytes != ucSize)
    {
        return(1);
    }
    return(0);
}


//*****************************************************************************
//
//! UARTReceiveData() receives data over a UART port.
//!
//! \param pucData is the buffer to read data into from the UART port.
//! \param ucSize is the number of bytes provided in pucData buffer that should
//!     be written with data from the UART port.
//!
//! This function reads back ucSize bytes of data from the UART port, that was
//! opened by a call to OpenUART(), into the buffer that is pointed to by
//! pucData.
//!
//! \return This function returns zero to indicate success while any non-zero
//!     value indicates a failure.
//
//*****************************************************************************
int UARTReceiveData(unsigned char *pucData, unsigned long ucSize)
{
    DWORD ulNumBytes;
	DWORD  retValue;
	DWORD  retValue1;

	retValue = GetLastError();

	if (0 == ReadFile(g_hComPort, pucData, ucSize, &ulNumBytes, NULL))
    {
        _trace_msg(TRACE_LEVEL_ERROR, "UART Receive Data Failed ");
		//sprintf_s(csErrorMessage, ERROR_BUFFER_SIZE, "**ERROR**: Failed to get download command! Return code: %04X", ucStatus); 
		return(1);
    }


    if (ulNumBytes != ucSize)
    {
		sprintf_s(ucErrorMessage, ERROR_BUFFER_SIZE, "UART Receive Data Length %d ",ulNumBytes);
		 _trace_msg(TRACE_LEVEL_DEBUG, ucErrorMessage);
		retValue1 = GetLastError();
		return(1);
    }
    return(0);
}


//*****************************************************************************
//
//! SendPacket() sends a data packet.
//!
//! \param pucData is the location of the data to be sent to the device.
//! \param ucSize is the number of bytes to send from puData.
//!
//! This function sends a packet of data to the device.
//!
//! \returns The function returns zero to indicated success while any non-zero
//!     value indicates a failure.
//
//*****************************************************************************
int SendPacket(unsigned char *pucData, unsigned long ucSize)
{
    unsigned char ucCheckSum;
    unsigned char ucAck;
	unsigned char sizeBuff[2];


    ucCheckSum = CheckSum(pucData, ucSize);

    //
    // Make sure that we add the bytes for the size and checksum to the total.
    //
    ucSize += 2;

    //
    // Send the Size in bytes.
    //
	sizeBuff[0] = (unsigned char)((ucSize & 0xFF00) >> 8);  /* Change for support size > 255 */
	sizeBuff[1] = (unsigned char)(ucSize &  0x00FF);


    if (UARTSendData(&sizeBuff[0], 2))
    {
        return(1);
    }

    //
    // Send the CheckSum
    //
    if (UARTSendData(&ucCheckSum, 1))
    {
        return(1);
    }

    //
    // Now send the remaining bytes out.
    //
    ucSize -= 2;

    //
    // Send the Data
    //
    if (UARTSendData(pucData, ucSize))
    {
        return(1);
    }

    //
    // Wait for the acknowledge from the device.
    //
	ucAck = 0;
	unsigned char ucResponse[5] = {0,0,0,0,0};
	do
    {
        if(UARTReceiveData(ucResponse, 5))
        {
            _trace_msg(TRACE_LEVEL_ERROR,"**Error**: UART ACK receive failed");
			return(1);
        }
		ucAck = ucResponse[0];
    } while(ucAck == 0);

	/* get Error Code from ACK repsonse */
	ucAck = ucResponse[4];
	if(ucResponse[4] != OK_CODE)
	{
		sprintf_s(ucErrorMessage, ERROR_BUFFER_SIZE, "**Error**: ACK response with Error code  %02X", ucResponse[4]); 
        _trace_msg(TRACE_LEVEL_ERROR,ucErrorMessage);
		return(1);
	}
    return(0);
}

//*****************************************************************************
//
//! GetPacket() receives a data packet.
//!
//! \param pucData is the location to store the data received from the device.
//! \param pucSize is the number of bytes returned in the pucData buffer that
//!     was provided.
//!
//! This function receives a packet of data from UART port.
//!
//! \returns The function returns zero to indicated success while any non-zero
//!     value indicates a failure.
//
//*****************************************************************************
int GetPacket(unsigned char *pucData, unsigned long *pucSize)
{
    unsigned char ucCheckSum;
    unsigned long ucSize = 0;
	unsigned char sizeBuff[2] = {0,0};



    //
    // Get the size what and the checksum.
    //
    do
    {
        if(UARTReceiveData(sizeBuff, 2))
        {
            return(1);
        }
		ucSize = sizeBuff[0] << 8;   /* Change for support size > 255 */
		ucSize |= sizeBuff[1];
	} while(ucSize == 0);

    if(UARTReceiveData(&ucCheckSum, 1))
    {
        return(1);
    }

    *pucSize = ucSize - 2;

    if (UARTReceiveData(pucData, *pucSize))
    {
        *pucSize = 0;
        return(1);
    }

    //
    // Calculate the checksum from the data.
    //
#if 0 /* 
        * For speed Loader CheckSum was removed. For Ram Memory the Check Sum is not nessary.
        * For Flash need to open the CheckSum and change for support size of two bytes instead 0ne
        */ 
    if (ucCheckSum != CheckSum(pucData, *pucSize))
    {
        *pucSize = 0;
        return(NakPacket());
    }

#endif

    //return(AckPacket());
	return 0;
}

//*****************************************************************************
//
//! CheckSum() Calculates an 8 bit checksum
//!
//! \param pucData is a pointer to an array of 8 bit data of size ucSize.
//! \param ucSize is the size of the array that will run through the checksum
//!     algorithm.
//!
//! This function simply calculates an 8 bit checksum on the data passed in.
//!
//! \return The function returns the calculated checksum.
//
//*****************************************************************************
unsigned char CheckSum(unsigned char *pucData, unsigned long ucSize)
{
    unsigned long i;
    unsigned char ucCheckSum;

    ucCheckSum = 0;

    for(i = 0; i < ucSize; ++i)
    {
        ucCheckSum += pucData[i];
    }

    return(ucCheckSum);
}








