//###########################################################################
// FILE:   f021_DownloadImage.cpp
// TITLE:  Download Image function required for CAN flash programmer.
//
// This function is used to communicate and download with the device.  Code 
// will be broken up into words (16-bit messages) and sent using the PEAK CAN
// API for writing messages.
//###########################################################################
// $TI Release: $
// $Release Date: $
//###########################################################################

#include "../include/f021_DownloadImage.h"

#include "stdafx.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#pragma once
#include <conio.h>
#include <windows.h>
#include <dos.h>

// Headers required for PCAN API
#include "../include/PCANBasic.h"

//
// Defines
// 
#define kernel
#define appln
//#define bitboost
//#define bitboost2
TPCANBitrateFD bitrate2;
extern int sleep_time;
bool CAN_Speed_Increase = false;

//*****************************************************************************
//
// Helpful macros for generating output depending upon verbose and quiet flags.
//
//*****************************************************************************
#define VERBOSEPRINT(...) if(g_bVerbose) { _tprintf(__VA_ARGS__); }
#define QUIETPRINT(...) if(!g_bQuiet) { _tprintf(__VA_ARGS__); }

//*****************************************************************************
//
// Globals whose values are set or overridden via command line parameters.
//
//*****************************************************************************
extern bool g_bVerbose;
extern bool g_bQuiet;
extern bool g_bWaitOnExit;
extern wchar_t* g_pszAppFile;
extern wchar_t* g_pszKernelFile;
extern wchar_t* g_pszDeviceName;

//*****************************************************************************
//
// Download an image to the the device identified by the passed handle.  The
// image to be downloaded and other parameters related to the operation are
// controlled by command line parameters via global variables.
//
// Returns 0 on success or a positive error return code on failure.
//
//*****************************************************************************
int
f021_CANFD_DownloadImage(void)
{
	FILE* Kfh;
	FILE* Afh;

	unsigned int rcvData = 0;
	unsigned int rcvDataH = 0;
	int txCount = 0;

	unsigned int fileStatus;
	DWORD dwRead;
	errno_t error;
	DWORD dwWritten;

	//extra space so that the stack around the aray does not get corrupted
	unsigned char sendData[70];  

	QUIETPRINT(_T("Downloading %s to device...\n"), g_pszAppFile);

	//
	// Does the input file exist?
	//
	// Opens the Flash Kernel File

	error = _wfopen_s(&Kfh, g_pszKernelFile, _T("rb"));
	if (!Kfh)
	{
		QUIETPRINT(_T("Unable to open Kernel file %s. Does it exist?\n"),
			       g_pszKernelFile);
		return(10);
	}

	//Opens the application file

	error = _wfopen_s(&Afh, g_pszAppFile, L"rb");
	if (!Afh)
	{
		QUIETPRINT(_T("Unable to open Application file %s. Does it exist?\n"),
			       g_pszAppFile);
		return(10);
	}

	//Both Kernel, Application and USB/CAN dongle are ready

	// Set up CAN message buffer to transmit 2 bytes at a time 
	TPCANStatus gStatus;
	tagTPCANMsg MessageBuffer;
	MessageBuffer.MSGTYPE = PCAN_MESSAGE_STANDARD;
	MessageBuffer.ID = 0x1;
	MessageBuffer.LEN = 0x2; //2 bytes, relative to bootROM capability

	// Count variables
	int counter;
	int i = 0;
	int bitbooster = 0;

#ifdef kernel
	//Find the start of the kernel data
	getc(Kfh);
	getc(Kfh);
	getc(Kfh);

	//copy kernel from file to buffer
	
	for (counter = 0; counter < 2; counter++)
	{
		fileStatus = fscanf_s(Kfh, "%x", &sendData[counter]);
		if (fileStatus != 1) break;
	}
	
	while (fileStatus == 1)
	{
		i++;

		//Copy buffer into CAN frame
		for (counter = 0; counter < 2; counter++)
		{
			MessageBuffer.DATA[counter] = sendData[counter];
		}

		//Send CAN frame to target
		gStatus = CAN_Write(PCAN_USBBUS1, &MessageBuffer);

		//print bytes to console
		for (counter = 0; counter < 2; counter++)
		{
			QUIETPRINT(_T("\n%lx"), sendData[counter]);
		}
		
		if (gStatus != PCAN_ERROR_OK)
		{
			QUIETPRINT(_T("Error sending CAN frame?\n"), g_pszAppFile);
		}

		// Check if user wants to increase bootloader speed within kernel file
#ifdef bitboost
		bitbooster++;
		if ((bitbooster == 2) && (MessageBuffer.DATA[0] != 0) 
			&& (MessageBuffer.DATA[1] != 0)) {
			// Bootloader time increased
			CAN_Speed_Increase = true;
		}

		if ((bitbooster == 9) && (CAN_Speed_Increase == true)) {
			// Re-initialize communication at a higher bitrate
			VERBOSEPRINT(_T("\nRe-Initializing CAN USB-C1 with with nominal Bit rate set to to 1 MBit/s\n"));
			//bitrate2 = "f_clock_mhz = 80, nom_brp = 40, nom_tseg1 = 16, nom_tseg2 = 3, nom_sjw = 2"; // alt 100kbps
			//bitrate2 = "f_clock_mhz = 80, nom_brp = 10, nom_tseg1 = 12, nom_tseg2 = 3, nom_sjw = 3"; // alt 500kbps
			bitrate2 = "f_clock_mhz = 80, nom_brp = 10, nom_tseg1 = 5, nom_tseg2 = 2, nom_sjw = 1"; // 1Mbps
			gStatus = CAN_Uninitialize(PCAN_USBBUS1);
			gStatus = CAN_Initialize(PCAN_USBBUS1, PCAN_BAUD_1M);
			if (gStatus != PCAN_ERROR_OK)
			{
				VERBOSEPRINT(_T("\nError initializing CAN USB-C1, check connection\n"));
			}
		}
#endif		

		//copy next 2 bytes into buffer 
		for (counter = 0; counter < 2; counter++)
		{
			fileStatus = fscanf_s(Kfh, "%x", &sendData[counter]);
			if (fileStatus != 1) break;
		}
	}

	//send final CAN frame
	if (fileStatus != 1 && counter > 0)
	{
		//copy remaining part of kernel into the CAN frame
		int counter2;
		for (counter2 = 0; counter2 < counter; counter2++)
		{
			MessageBuffer.DATA[counter2] = sendData[counter2];
		}
		//pad the rest of the buffer with 0
		for (counter2 = counter; counter2 < 2; counter2++)
		{
			MessageBuffer.DATA[counter2] = 0;
		}
		//send CAN frame
		gStatus = CAN_Write(PCAN_USBBUS1, &MessageBuffer);
		//print bytes to screen
		for (counter2 = 0; counter2 < counter; counter2++)
		{
			QUIETPRINT(_T("\n%lx"), sendData[counter2]);
		}
		if (gStatus != PCAN_ERROR_OK)
		{
			QUIETPRINT(_T("Error sending CAN frame?\n"), g_pszAppFile);
		}

	}
	VERBOSEPRINT(_T("\nKernel Loaded"));

	Sleep(5000);

	VERBOSEPRINT(_T("\nDone Waiting for kernel boot..."));

#endif

#ifdef bitboost2
	// Optional: Re-initialize communication at a higher bitrate
	VERBOSEPRINT(_T("\nInitializing CAN USB-C1 with with nominal Bit rate set to to 1 MBit/s\n"));
	//bitrate2 = "f_clock_mhz = 80, nom_brp = 40, nom_tseg1 = 16, nom_tseg2 = 3, nom_sjw = 2"; // alt 100kbps
	//bitrate2 = "f_clock_mhz = 80, nom_brp = 10, nom_tseg1 = 12, nom_tseg2 = 3, nom_sjw = 3"; // alt 500kbps
	bitrate2 = "f_clock_mhz = 80, nom_brp = 10, nom_tseg1 = 5, nom_tseg2 = 2, nom_sjw = 1"; // 1Mbps
	gStatus = CAN_Uninitialize(PCAN_USBBUS1);
	gStatus = CAN_InitializeFD(PCAN_USBBUS1, bitrate2);
	if (gStatus != PCAN_ERROR_OK)
	{
		VERBOSEPRINT(_T("\nError initializing CAN USB-C1, check connection\n"));
	}
#endif

#ifdef appln
	// Setup Can message buffer to transmit 8 bytes at a time
	MessageBuffer.LEN = 0x8;

	//Find the start of the application data
	txCount = 0;
	getc(Afh);
	getc(Afh);
	getc(Afh);

	//copy 8 bytes of the image into a buffer
	for (counter = 0; counter < 8; counter++)
	{
		fileStatus = fscanf_s(Afh, "%x", &sendData[counter]);
		if (fileStatus != 1) break;
	}

	i = 0;
	while (fileStatus == 1)
	{
		i++;

		//Copy buffer into CAN frame
		for (counter = 0; counter < 8; counter++)
		{
			MessageBuffer.DATA[counter] = sendData[counter];
		}
		// send the CAN frame 
		gStatus = CAN_Write(PCAN_USBBUS1, &MessageBuffer);

		//write bytes onto the console 
		for (counter = 0; counter < 8; counter++)
		{
			QUIETPRINT(_T("\n%lx"), sendData[counter]);
		}
		if (gStatus != PCAN_ERROR_OK)
		{
			QUIETPRINT(_T("Error sending CAN frame?\n"), g_pszAppFile);
		}
		//break;
		//copy next 8 bytes into buffer 
		for (counter = 0; counter < 8; counter++)
		{
			fileStatus = fscanf_s(Afh, "%x", &sendData[counter]);
			if (fileStatus != 1) break;
		}

		Sleep(sleep_time); // Flash API needs time to program application
	}
	
	// send final CAN frame
	if (fileStatus != 1 && counter > 0)
	{
		int counter2;
		for (counter2 = 0; counter2 < counter; counter2++)
		{
			MessageBuffer.DATA[counter2] = sendData[counter2];
		}
		for (counter2 = counter; counter2 < 8; counter2++)
		{
			MessageBuffer.DATA[counter2] = 0;
		}
		gStatus = CAN_Write(PCAN_USBBUS1, &MessageBuffer);
		for (counter2 = 0; counter2 < counter; counter2++)
		{
			QUIETPRINT(_T("\n%lx"), sendData[counter2]);
		}
		if (gStatus != PCAN_ERROR_OK)
		{
			QUIETPRINT(_T("Error sending CAN frame?\n"), g_pszAppFile);
		}

	}
	
	VERBOSEPRINT(_T("\nApplication Load Completed"));
#endif

	return 0;
}
