// LFAE CAN Functions.cpp
// This file contians the functions relating to CAN transmision of data
// for the secondary LFAE bootloader
#include "main.h"
#include <fstream> //used to read from files
#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
//*******************************************
int LFAE_CAN_interface(void)
{
	CVCanDrv CAN; //create instance of CVCanDrv 
	time_t seconds = time(NULL); //start time in seconds
	if (CAN.OpenDriver()) //ensure channel can be opened
	{
		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");
				return 1;
			}
			
			//opening the s-record
			ifstream s_record;
			s_record.open(SecondarySRecordFilename, 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
					if (LFAE_CAN_s_line_process(line, &CAN)) //process the captured s-line
					{
						return 1; //error
					}
				}


				s_record.close();
			}
			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("Secondary S-Recored transmitted successfully!\n");
	printf("Elapsed Time: %i seconds\n",(time(NULL) - seconds));
	printf("Press any key to exit...\n");
	getch();
	return 0; //load successful
}

//*******************************************
// function to analyse an s-line and transmit via CAN
//*******************************************
int LFAE_CAN_s_line_process(char *line, CVCanDrv *CAN)
{
	//local variables
	int lineLength = 0;
	int loop;
	bool checkSumCorrect = FALSE;
	VCAN_EVENT recData;//structure in which to store received packets
	unsigned char can_data[8]; //array for data
	for(loop = 7; loop >=0; loop--)
		can_data[loop] = 0x00;
	// main code
	switch (line[1]) 
	{
		case '0':
			// S0 - header - ignore
			return 0;
			break;
		case '2':
			// 3 byte addressing
			while (checkSumCorrect == FALSE)
			{
			
				lineLength = hex2dec(line,2); //get line length, 
				
				// send start address
				for(loop=4; loop <= 9; loop = loop+2)
				{
					can_data[DataField] = hex2dec(line,loop);
					DataField++;
				}
				CAN->Transmit(0x020, can_data, 3, 0);
				DataField = 0;

				for(loop=10; loop <= (2*lineLength); loop = loop+2)
				{
					can_data[DataField] = hex2dec(line,loop);
					if (DataField == 7)
					{	
						//packet full, send:
						CAN->Transmit(0x040, can_data, 8, 0);
						_sleep(1);
						DataField = 0; //reset to first field of new packet
					}
					else if(loop == 2*lineLength)
					{
						//end of data, send packet
						CAN->Transmit(0x040, can_data, DataField+1, 0);
						DataField = 0; //reset to first field of new packet
					}
					else
						DataField++;
				}
				// transmit checksum
				can_data[DataField] = hex2dec(line,loop);
									// removing linelength from checksum as this was not transmitted
				can_data[DataField] = can_data[DataField] + lineLength;
				CAN->Transmit(0x080, can_data, 1, 0);
				
				//ensure checksum is correct
				//receiving checksum status message
				time_t seconds = time(NULL); //start time in seconds
				
				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, resending...\n");
				}
				else
					checkSumCorrect = TRUE;
					_sleep(25); //pause to allow data to be written to flash
			}
			return 0;
			break;
		case '9':
			// end of data - send execution packet
				CAN->Transmit(0x010, can_data , 8, 0);
				DataField = 0; //reseting DataField
				return 0;
			break;

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