// CAN Functions.cpp
// This file contians the functions relating to CAN transmision
#include "main.h"
#include <fstream> //used to read from files
#include "CAN Functions.h"
#include "LFAE CAN Functions.h"
#include <conio.h> //needed for getchar
#include "VCanDrv.h"
#include <time.h> // needed for sleep function and timer
using namespace std;  //needed by <fstream>


//*******************************************
// function to transmit S-Record via CAN
// Primary Bootloader Version
//*******************************************
int CAN_interface(void)
{
	CVCanDrv CAN; //create instance of CVCanDrv 
	if (CAN.OpenDriver()) //ensure channel can be opened
	{
		VCAN_EVENT recData;//structure in which to store received packets
		
		char line[1000]; //max 1000 chars per line
		int pckt_position = 0; //current data field in packet
		int checkSumTotal = 0;
		unsigned char canData[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //data segment of packet
		
		if (CAN.OpenPort("CANAX_TEST",CANPort,100)) 
		{
			if (!CAN.SetBitrate(ChannelBitrate))
			{
				printf("Error: Unable to set bitrate\n");
				printf("Press any key to exit...\n");
				getch(); //pause until key is pressed
				return 1;
			}
			
			
			CAN.SetChannelMode(0,0); //do NOT generate receipts
			CAN.SetReceiveMode(1,1); //suppressing error frames
			CAN.SetChannelAcceptance(0x600,0x7FF);//accept all packets
			if (!CAN.ActivateChannel())
			{
				printf("Error: Unable to set activate channel\n");
				printf("Press any key to exit...\n");
				getch();
				return 1;
			}
			
			//Setting up start address
			canData[0] = StartAddressMSB;
			canData[1] = StartAddressLSB;
			
			// Send Address
			if (!CAN.Transmit(0x020, canData, 8, 0))
			{
				printf("Error: Unable to transmit\n");
				printf("Press any key to exit...\n");
				getch(); //pause until key is pressed
				return 1;
			}
			checkSumTotal += (StartAddressMSB+StartAddressLSB);
			//opening the s-record
			ifstream s_record;
			s_record.open(SRecordFilename, ios::in); //open file for input purposes
			if (s_record.is_open())
			{	
				while (! s_record.eof() ) //while not the end of the file	
				{
					s_record.getline(line,1000);//max 1000 chars per line
					CAN_s_line_process(line, &CAN, &checkSumTotal);//process the captured s-line
				}


				s_record.close();
				
				//sending check sum
				canData[0] = checkSumTotal;
				canData[1] = 0x00; //assumes all other fields are 0x00
				if (!CAN.Transmit(0x080, canData, 8, 0))
				{
					printf("Error: Unable to transmit\n");
					printf("Press any key to exit...\n");
					getch(); //pause until key is pressed
					return 1;
				}

				//receiving checksum status message
				time_t seconds = time(NULL); //start time in seconds
				
				printf("Waiting for checksum packet to arrive...\n");
				while ((CAN.Receive(&recData,1)!=1)&&(time(NULL)<(seconds+6))) {} //wait for packet to arrive, or timeout
				
				if(time(NULL)>(seconds+5))
				{
					printf("Error: Did not receive checksum packet, check bus is connected correctly\n");
					printf("Press any key to exit...\n");
					getch(); //pause until key is pressed
					return 1;
				}
				
				if (recData.tagData.msg.data[0] != 0x80)
				{
					printf("Error: Checksum does not match\n");
					printf("Press any key to exit...\n");
					getch(); //pause until key is pressed
					return 1;
				}

				//sending execute address
				canData[0] = StartAddressMSB;
				canData[1] = StartAddressLSB;
				if(!CAN.Transmit(0x010, canData, 8, 0))
				{
					printf("Error: Unable to transmit\n");
					printf("Press any key to exit...\n");
					getch(); //pause until key is pressed
					return 1;
				}
			}
		
			else
			{
				printf("Error: Unable to open s-record, ensure file is in 'bin' directory\n");
				printf("and that the s_record_filename is correct\n");
				getch(); //pause until key is pressed
				return 1;
			}


		}
		else
		{
				printf("Error: Cannot open CAN Port\n");
				printf("Press any key to exit...\n");
				getch(); //pause until key is pressed
				return 1;
		}	
	}
	else
	{
				printf("Error: Cannot open CAN Driver, ensure CANalyzer is installed\n");
				printf("Press any key to exit...\n");
				getch(); //pause until key is pressed
				return 1;
	}	
	printf("Primary S-Recored loaded successfully!\n");
	_sleep(1000); //need to wait for packet to arrive and LFAE to execute before closing the CAN port
	CAN.ClosePort();
	LFAE_CAN_interface(); //fuction to interface with the secondary bootloader
	return 0; //load successful
}

//*******************************************
// function to analyse an s-line and transmit via CAN
// Primary Bootloader Version
//*******************************************
void CAN_s_line_process(char *line, CVCanDrv *CAN, int *checkSumTotal)
{
	//local variables
	int lineLength = 0;
	int loop;
	static unsigned char can_data[8]; //array for data

	// main code
	switch (line[1]) 
	{
		case '0':
			// S0 - header - ignore
			break;
		case '1':
			// 2 byte addressing
			lineLength = hex2dec(line,2) - 3; //get line length, remove address bytes and checksum
			for(loop=8; loop <= (2*lineLength + 7) ; loop = loop+2)
			{
				can_data[DataField] = hex2dec(line,loop);
				*checkSumTotal = (*checkSumTotal + can_data[DataField]) % 256;
				if (DataField == 7)
				{	
					//packet full, send:
					CAN->Transmit(0x040, can_data, 8, 0);
					DataField = 0; //reset to first field of new packet
				}
				else
					DataField++;
			}
			break;
		case '9':
			// end of data - ensure final (possibly unfinished) packet is sent
			// after all unwritten fields are nulled
			
			if(DataField != 0)
			{
				while (DataField < 8)
				{
					can_data[DataField] = 255;
					*checkSumTotal = (*checkSumTotal + 255)%256;
					DataField++;
				}
			
				CAN->Transmit(0x040, can_data , 8, 0);
				DataField = 0; //reseting DataField
			}
			break;

		default:
			//error! line not recognised
			printf("Line not recognised/n");
			break;
	}
}
