// option handler function definitions
#include "stdafx.h"
#include "HAMConsole.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <errno.h>
#include <string>
#include <string.h>
#include <AtlBase.h>
#include <AtlConv.h>

using namespace std;

std::wstring s2ws(const std::string& s)
{
    int len;
    int slength = (int)s.length() + 1;
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len];
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);
    delete[] buf;
    return r;
}

// HAMConsole constructor
HAMConsole::HAMConsole() {
}

// offloads device's data writing to text file
void HAMConsole::offload_data(void) {

// Detect com port device is recognized on
// Allow user to input the path to which the output file will be written
	
	// run script to create text file containing COM port assignment for HAMonitor
	/*"chgport | findstr \"VCP0\" > C:\\Users\\cterndru\\Desktop\\com_assignment.txt"*/
	char error_buffer[128];
	char *path_tokens[MAX_PATH];
	char *backslash_path_tokens[MAX_PATH];
	int k = 0;
	string raw_path, line;

	// Read in the user's desired file path
	cout << "Enter path to output text file containing activity data:" << endl;
	cin.ignore(255,'\n');
	getline(cin,raw_path);
	//cout << raw_path << endl;

	// copy file path into buffer and append null character
	char *copy_buffer = (char *)malloc((raw_path.length()+1)*sizeof(char));
	raw_path.copy(copy_buffer,raw_path.length(),0);
	copy_buffer[raw_path.length()] = '\0';
	//cout << copy_buffer << endl;
	
	char *next_token1;
	// tokenize string by ...
	path_tokens[k] = strtok_s(copy_buffer,"\\",&next_token1);
	while (path_tokens[k] != NULL) {
		//cout << path_tokens[k] << endl;
		++k;
		path_tokens[k] = strtok_s(NULL,"\\",&next_token1);
	}

	if (path_tokens[0] == NULL) return;

	// insert backslash escapes between tokens
	string backslash = "\\\\";
	string path_with_backslashes(path_tokens[0]);
	k = 1;
	while (path_tokens[k] != NULL) {
		path_with_backslashes.append(backslash);
		path_with_backslashes.append(path_tokens[k]);
		++k;
	}

	free(copy_buffer);

	char *copy_buffer2 = (char *)malloc((path_with_backslashes.length()+1)*sizeof(char));
	path_with_backslashes.copy(copy_buffer2,path_with_backslashes.length(),0);
	copy_buffer2[path_with_backslashes.length()] = '\0';
	
	// tokenize string by spaces
	char *next_token2;
	k = 0;
	backslash_path_tokens[k] = strtok_s(copy_buffer2," ",&next_token2);
	while (backslash_path_tokens[k] != NULL) {
		//cout << backslash_path_tokens[l] << endl;
		++k;
		backslash_path_tokens[k] = strtok_s(NULL," ",&next_token2);
	}
	
	// insert space characters between tokens
	string space_char = "\x20";
	string path(backslash_path_tokens[0]);
	k = 1;
	while (backslash_path_tokens[k] != NULL) {
		path.append(space_char);
		path.append(backslash_path_tokens[k]);
		++k;
	}

	//cout << path << endl;

	// break up string and later append to correctly interpret whitespace
	string command = "MODE.COM | findstr COM > ";
	//string command2 = "\"E:/Senior Design/com_assignment.txt\"";
	string command_path = "\"";
	command_path.append(path);
	command_path.append("\"");
	command.append(command_path);
	if (system(command.c_str()) < 0){
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// text file containing COM port assignment
	FILE *com_file;
	// break up string and later append to correctly interpret whitespace
	//string path1 = "E:/Senior\x20";
	//string path2 = "Design/com_assignment.txt";
	//path1.append(path2);
	if (fopen_s(&com_file,path.c_str(),"r") != 0) {
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1);
	}

	// Read text file
	// Get second line of text, first line contains COM1 which is reserved
	char COM_string[60];
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// close text file 
	if (fclose(com_file) != 0){
		std::cout << "error in closing com_file\n";
		return;
		//exit(1); // unsuccesful process termination
	}

	// tokenize string to obtain COM port
	char *com_port_string;
	char *next_string;
	com_port_string = strtok_s(COM_string," :\t\n",&next_string);
	int m;
	for (m=0; m<4; m++){
		com_port_string = strtok_s(NULL, " :M\t\n",&next_string);
	}

	// Check if COM number is greater than 10
	// Modify string accordingly
	string com_temp = com_port_string;
	if (stoi(com_port_string,nullptr,10) > 9){
		com_temp = com_temp.insert(0,"\\\\.\\COM");
	}
	else {
		com_temp = com_temp.insert(0,"COM");
	}

	// convert string to appriate type to be passed to CreateFile()
	wstring stemp = s2ws(com_temp);
	LPCWSTR com_name = stemp.c_str();
	wcout << "Device is on " << com_name << endl;

	// open the com port the device is connected to
	HANDLE com_port = CreateFile(L"\\\\.\\COM12",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (com_port == INVALID_HANDLE_VALUE){
		std::cout << "error: invalid handle value\n";
		return;
		//exit(1); // unsuccessful process termination 
	}

	// create text file to write data from device to
	FILE *output_file;
	if (fopen_s(&output_file,path.c_str(),"w+") != 0){
		std::cout << strerror_s(error_buffer,60,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	//  Initialize the DCB structure.
   DCB dcb;
   BOOL fSuccess;
   SecureZeroMemory(&dcb, sizeof(DCB));
   dcb.DCBlength = sizeof(DCB);

   //  Build on the current configuration by first retrieving all current
   //  settings.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

   //  Fill in some DCB values and set the com state: 
   //  57,600 bps, 8 data bits, no parity, and 1 stop bit.
   dcb.BaudRate = CBR_9600;     //  baud rate
   dcb.ByteSize = 8;             //  data size, xmit and rcv
   dcb.Parity   = NOPARITY;      //  parity bit
   dcb.StopBits = ONESTOPBIT;    //  stop bit 

   fSuccess = SetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(3);
   }

   //  Get the comm config again.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

	// set comm timeouts
	LPCOMMTIMEOUTS comm_timeouts = (LPCOMMTIMEOUTS)malloc(sizeof(DWORD)*5);
	comm_timeouts->ReadIntervalTimeout = 1000; // 1 second
	comm_timeouts->ReadTotalTimeoutConstant = 0;
	comm_timeouts->ReadTotalTimeoutMultiplier = 10;
	comm_timeouts->WriteTotalTimeoutConstant = 0;
	comm_timeouts->WriteTotalTimeoutMultiplier = 10;
	if (SetCommTimeouts(com_port,comm_timeouts) == 0){
		std::cout << "error: setting timeouts failed\n";
		return;
		//exit(1);
	}
	
	// amount of data sent by the microcontroller per request
	// can change to multiple of 11
	int bytes_per_read = 1023;

	// Read buffer
	// buffer size should be multiple of 11 plus 1
	char buffer[1024];
	LPDWORD bytes_read;
	bytes_read = (LPDWORD)malloc(sizeof(long));
	BOOL readFileVal;
	BOOL writeFileVal;

	char writeBuffer[1024];
	writeBuffer[0] = 'B';
	LPDWORD bytes_written = (LPDWORD)malloc(sizeof(long));

	// Send microcontroller 'B' to initiate communication to tell 
	// microcontroller how many bytes to send at a time
	// writeFileVal = WriteFile(com_port,writeBuffer,1,bytes_written,NULL);
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		exit(1); // unsuccessful process termination
	}
	// Wait until an 'B' is received from the microcontroller 
	do {
		if (ReadFile(com_port,buffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'B'" << endl;
	} while(buffer[0] != 'B'); // 'B' for next

	// Send microcontroller the number of bytes to read at a time
	writeBuffer[0] = bytes_per_read;
	writeFileVal = WriteFile(com_port,writeBuffer,1,bytes_written,NULL);
	if (writeFileVal == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until 'S' received from microcontroller
	do {
		if (ReadFile(com_port,buffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'S'" << endl;
	} while(buffer[0] != 'S'); // 'S' for start

	// Send 'W' to tell microcontroller it may begin sending data
	writeBuffer[0] = 'W';
	writeFileVal = WriteFile(com_port,writeBuffer,1,bytes_written,NULL);
	if (writeFileVal == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	
	// Receiving data over COM port
	int total_bytes_sent = 4096;
	int total_bytes_read = 0;
	int loop_limit;
	if (total_bytes_sent % bytes_per_read != 0){ 
		loop_limit = (total_bytes_sent/bytes_per_read)+1;
	} 
	else {
		loop_limit = total_bytes_sent/bytes_per_read;
	}

	int i;
	for(i = 0; i < loop_limit; i++){
		do{
			readFileVal = ReadFile(com_port,buffer,bytes_per_read,bytes_read,NULL);
			total_bytes_read += *bytes_read;
			if (readFileVal == 0){
				std::cout << "error: ReadFile() failed\n";
				return;
				//exit(1); // unsuccessful process termination
			}
			else {
				int i = 0;
				while (i < *bytes_read){
					// print new line and carriage return if current byte is multiple of 11
					// (11 bytes are recorded for each sample)
					if ((total_bytes_read - *bytes_read + i) % 11 == 0){
						fprintf(output_file,"\n\r");
						cout << endl;
					}
					// omits comma if last character to be printed on a line
					/*else if ((total_bytes_read - *bytes_read + i + 1) % 11 == 0){
						printf("%d",buffer[i]);
						cout << ',';
						fprintf(output_file,"%d",buffer[i]);
					}
					else {
						printf("%d",buffer[i]);
						cout << ',';
						fprintf(output_file,"%d, ",buffer[i]);
					}*/
					if ((total_bytes_read - *bytes_read + i) % 11 == 5) {
						char xl = buffer[i];
						char xh = buffer[i+1];
						int x = (buffer[i+1] << 4) | buffer[i];
						printf("%f",x*0.0078);
						std::cout << ',';
						fprintf(output_file,"%f, ",x*0.0078);
						++i; ++i;
					}
					else if ((total_bytes_read - *bytes_read + i) % 11 == 7) {
						char yl = buffer[i];
						char yh = buffer[i+1];
						int y = (buffer[i+1] << 4) | buffer[i];
						printf("%f",y*0.0078);
						std::cout << ',';
						fprintf(output_file,"%f, ",y*0.0078);
						++i; ++i;
					}
					else if ((total_bytes_read - *bytes_read + i) % 11 == 9){
						char zl = buffer[i];
						char zh = buffer[i+1];
						int z = (buffer[i+1] << 4) | buffer[i];
						printf("%f",z*0.0078);
						std::cout << ',';
						fprintf(output_file,"%f, ",z*0.0078);
						++i; ++i;
					}
					else {
						// change back to %d
						printf("%d",buffer[i]);
						std::cout << ',';
						fprintf(output_file,"%d, ",buffer[i]);
						++i;
					}
				}
			}
			if (bytes_per_read+total_bytes_read > total_bytes_sent){
				bytes_per_read = total_bytes_sent - total_bytes_read;
			}
		} while(*bytes_read <= 0);
		// acknowledge to MCU byte received
		writeFileVal = WriteFile(com_port,writeBuffer,1,bytes_written,NULL);
	}

	std::cout << endl;
	std::cout << "Total bytes received: " << total_bytes_read << endl;

	std::free(bytes_read);
	std::free(bytes_written);

	if (CloseHandle(com_port) == 0){
		std::cout << "error in closing the com_port\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	else {
		std::cout << "com_port closed successfully\n";
	}

	if (fclose(output_file) != 0){
		std::cout << "error in closing the output file\n";
		return;
		//exit(1); // unsuccesful process termination
	}
	else {
		std::cout << "output file closed successfully\n";
	}

	std::cout << endl;
	return;
}




// set device's internal time
void HAMConsole::set_device_time(void){
	
	// get path for TEMP environment variable
	LPCTSTR envar = L"TEMP";
	LPTSTR temp_buffer = (LPTSTR)malloc(sizeof(long)*32767);
	DWORD chars_written = GetEnvironmentVariable(envar,temp_buffer,32767);

	string temp = CW2A(temp_buffer);
	temp.append("\\com_assignment.txt");

	// break up string and later append to correctly interpret whitespace
	string command = "MODE.COM | findstr COM > ";
	//string command2 = "\"E:/Senior Design/com_assignment.txt\"";
	string command_path = "\"";
	command_path.append(temp.c_str());
	command_path.append("\"");
	command.append(command_path.c_str());

	// find com port device is connected on
	char error_buffer[128];
	if (system(command.c_str()) < 0){
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// text file containing COM port assignment
	FILE *com_file;
	// break up string and later append to correctly interpret whitespace
	//string path1 = "E:/Senior\x20";
	//string path2 = "Design/com_assignment.txt";
	//path1.append(path2);
	if (fopen_s(&com_file,temp.c_str(),"r") != 0) {
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1);
	}

	// Read text file
	// Get second line of text, first line contains COM1 which is reserved
	char COM_string[60];
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// close text file 
	if (fclose(com_file) != 0){
		std::cout << "error in closing com_file\n";
		return;
		//exit(1); // unsuccesful process termination
	}

	// tokenize string to obtain COM port
	char *com_port_string;
	char *next_string;
	com_port_string = strtok_s(COM_string," :\t\n",&next_string);
	int m;
	for (m=0; m<4; m++){
		com_port_string = strtok_s(NULL, " :M\t\n",&next_string);
	}

	// Check if COM number is greater than 10
	// Modify string accordingly
	string com_temp = com_port_string;
	if (stoi(com_port_string,nullptr,10) > 9){
		com_temp = com_temp.insert(0,"\\\\.\\COM");
	}
	else {
		com_temp = com_temp.insert(0,"COM");
	}

	// convert string to appriate type to be passed to CreateFile()
	wstring stemp = s2ws(com_temp);
	LPCWSTR com_name = stemp.c_str();
	wcout << "Device is on " << com_name << endl;

	// open the com port the device is connected to
	HANDLE com_port = CreateFile(com_name,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (com_port == INVALID_HANDLE_VALUE){
		std::cout << "error: invalid handle value\n";
		return;
		//exit(1); // unsuccessful process termination 
	}

	//  Initialize the DCB structure.
   DCB dcb;
   BOOL fSuccess;
   SecureZeroMemory(&dcb, sizeof(DCB));
   dcb.DCBlength = sizeof(DCB);

   //  Build on the current configuration by first retrieving all current
   //  settings.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

   //  Fill in some DCB values and set the com state: 
   //  57,600 bps, 8 data bits, no parity, and 1 stop bit.
   dcb.BaudRate = CBR_9600;     //  baud rate
   dcb.ByteSize = 8;             //  data size, xmit and rcv
   dcb.Parity   = NOPARITY;      //  parity bit
   dcb.StopBits = ONESTOPBIT;    //  stop bit 

   fSuccess = SetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(3);
   }

   //  Get the comm config again.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

	// set comm timeouts
	LPCOMMTIMEOUTS comm_timeouts = (LPCOMMTIMEOUTS)malloc(sizeof(DWORD)*5);
	comm_timeouts->ReadIntervalTimeout = 1000; // 1 second
	comm_timeouts->ReadTotalTimeoutConstant = 0;
	comm_timeouts->ReadTotalTimeoutMultiplier = 10;
	comm_timeouts->WriteTotalTimeoutConstant = 0;
	comm_timeouts->WriteTotalTimeoutMultiplier = 10;
	if (SetCommTimeouts(com_port,comm_timeouts) == 0){
		std::cout << "error: setting timeouts failed\n";
		return;
		//exit(1);
	}

	cin.clear();
	cin.ignore(255,'\n');
	
	int hours, minutes, seconds;

	// accept time from user
	while(1){
		string time_line;
		cout << "Enter time (hh:mm:ss) to set device's real-time clock" << endl;
		cout << "(if no time entered, system time will be used): ";
		getline(cin,time_line);

		// tokenize time into hours, minutes, seconds
		char *token_buffer[3];
		char *next;
		int i = 0;

		char *copy_buffer = (char *)malloc((time_line.length()+1)*sizeof(char));
		time_line.copy(copy_buffer,time_line.length(),0);
		copy_buffer[time_line.length()] = '\0';

		token_buffer[i] = strtok_s(copy_buffer,":",&next);
		//if (token_buffer[i] == NULL) continue;
		for (i=1; i < 3 /*&& token_buffer[i] !=NULL*/; i++) {
			token_buffer[i] = strtok_s(NULL,":",&next);
		}
		
		try {
			hours = stoi(token_buffer[0],nullptr,10);
			minutes = stoi(token_buffer[1],nullptr,10);
			seconds = stoi(token_buffer[2],nullptr,10);
		}
		catch (...) {
			//char error_string[256];
			//strerror_s(error_string,256,error);
			cout << "Enter integers for hours, minutes, seconds" << endl;
			free(copy_buffer);
			continue;
		}

		if ((hours >= 0 && hours <= 23) && (minutes >= 0 && minutes <= 59) && (seconds >= 0 && seconds <= 59)) {
			cout << "Hours: " << hours << " Minutes: " << minutes << " Seconds: " << seconds << endl;
			free(copy_buffer);
			break;
		}

		cout << "Enter a valid time" << endl;
		free(copy_buffer);

	}

	// send 'T' to initiate memory clear
	char writeBuffer[8];
	char readBuffer[8];
	LPDWORD bytes_written = (LPDWORD)malloc(sizeof(long));;
	LPDWORD bytes_read = (LPDWORD)malloc(sizeof(long));;
	writeBuffer[0] = 'T';
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until an 'T' is received from the microcontroller 
	do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'T'" << endl;
	} while(readBuffer[0] != 'T'); // 'T' for next

	
	// send time to microcontroller
	writeBuffer[0] = hours;
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until an 'T' is received from the microcontroller 
	do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'T'" << endl;
	} while(readBuffer[0] != 'S'); // 'T' for next

	writeBuffer[0] = minutes;
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until an 'T' is received from the microcontroller 
	do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'T'" << endl;
	} while(readBuffer[0] != 'S'); // 'T' for next

	writeBuffer[0] = seconds;
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until an 'T' is received from the microcontroller 
	do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'T'" << endl;
	} while(readBuffer[0] != 'S'); // 'T' for next


	//TEST
	/*do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'T'" << endl;
	} while(readBuffer[0] != 'X'); // 'T' for next*/


	if (CloseHandle(com_port) == 0){
		std::cout << "error in closing the com_port\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	else {
		std::cout << "com_port closed successfully\n";
	}

	std::cout << endl;
	return;

}

// set device's id
void HAMConsole::set_device_id(void){

	// get path for TEMP environment variable
	LPCTSTR envar = L"TEMP";
	LPTSTR temp_buffer = (LPTSTR)malloc(sizeof(long)*32767);
	DWORD chars_written = GetEnvironmentVariable(envar,temp_buffer,32767);

	string temp = CW2A(temp_buffer);
	temp.append("\\com_assignment.txt");

	// break up string and later append to correctly interpret whitespace
	string command = "MODE.COM | findstr COM > ";
	//string command2 = "\"E:/Senior Design/com_assignment.txt\"";
	string command_path = "\"";
	command_path.append(temp.c_str());
	command_path.append("\"");
	command.append(command_path.c_str());

	// find com port device is connected on
	char error_buffer[128];
	if (system(command.c_str()) < 0){
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// text file containing COM port assignment
	FILE *com_file;
	// break up string and later append to correctly interpret whitespace
	//string path1 = "E:/Senior\x20";
	//string path2 = "Design/com_assignment.txt";
	//path1.append(path2);
	if (fopen_s(&com_file,temp.c_str(),"r") != 0) {
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1);
	}

	// Read text file
	// Get second line of text, first line contains COM1 which is reserved
	char COM_string[60];
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// close text file 
	if (fclose(com_file) != 0){
		std::cout << "error in closing com_file\n";
		return;
		//exit(1); // unsuccesful process termination
	}

	// tokenize string to obtain COM port
	char *com_port_string;
	char *next_string;
	com_port_string = strtok_s(COM_string," :\t\n",&next_string);
	int m;
	for (m=0; m<4; m++){
		com_port_string = strtok_s(NULL, " :M\t\n",&next_string);
	}

	// Check if COM number is greater than 10
	// Modify string accordingly
	string com_temp = com_port_string;
	if (stoi(com_port_string,nullptr,10) > 9){
		com_temp = com_temp.insert(0,"\\\\.\\COM");
	}
	else {
		com_temp = com_temp.insert(0,"COM");
	}

	// convert string to appriate type to be passed to CreateFile()
	wstring stemp = s2ws(com_temp);
	LPCWSTR com_name = stemp.c_str();
	wcout << "Device is on " << com_name << endl;

	// open the com port the device is connected to
	HANDLE com_port = CreateFile(com_name,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (com_port == INVALID_HANDLE_VALUE){
		std::cout << "error: invalid handle value\n";
		return;
		//exit(1); // unsuccessful process termination 
	}

	//  Initialize the DCB structure.
   DCB dcb;
   BOOL fSuccess;
   SecureZeroMemory(&dcb, sizeof(DCB));
   dcb.DCBlength = sizeof(DCB);

   //  Build on the current configuration by first retrieving all current
   //  settings.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

   //  Fill in some DCB values and set the com state: 
   //  57,600 bps, 8 data bits, no parity, and 1 stop bit.
   dcb.BaudRate = CBR_9600;     //  baud rate
   dcb.ByteSize = 8;             //  data size, xmit and rcv
   dcb.Parity   = NOPARITY;      //  parity bit
   dcb.StopBits = ONESTOPBIT;    //  stop bit 

   fSuccess = SetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(3);
   }

   //  Get the comm config again.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

	// set comm timeouts
	LPCOMMTIMEOUTS comm_timeouts = (LPCOMMTIMEOUTS)malloc(sizeof(DWORD)*5);
	comm_timeouts->ReadIntervalTimeout = 1000; // 1 second
	comm_timeouts->ReadTotalTimeoutConstant = 0;
	comm_timeouts->ReadTotalTimeoutMultiplier = 10;
	comm_timeouts->WriteTotalTimeoutConstant = 0;
	comm_timeouts->WriteTotalTimeoutMultiplier = 10;
	if (SetCommTimeouts(com_port,comm_timeouts) == 0){
		std::cout << "error: setting timeouts failed\n";
		return;
		//exit(1);
	}

	// send 'D' to initiate memory clear
	char writeBuffer[8];
	char readBuffer[8];
	LPDWORD bytes_written = (LPDWORD)malloc(sizeof(long));;
	LPDWORD bytes_read = (LPDWORD)malloc(sizeof(long));;
	writeBuffer[0] = 'D';
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until an 'D' is received from the microcontroller 
	do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'D'" << endl;
	} while(readBuffer[0] != 'D'); // 'D ' for next

	// send device ID
	string line;
	unsigned int dev_ID;
	do {
		cout << "Enter a device ID to associate with the connected device (0 to 255): ";
		cin >> dev_ID;
		cout << endl;
	} while (dev_ID < 0 || dev_ID > 255);

	writeBuffer[0] = dev_ID;
	
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until an 'S' is received from the microcontroller 
	do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'S'" << endl;
	} while(readBuffer[0] != 'S'); // 'S' for next

	// close open files, ports, etc.
	// free dynamically allocated memory
	free(bytes_read);
	free(bytes_written);

	if (CloseHandle(com_port) == 0){
		std::cout << "error in closing the com_port\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	else {
		std::cout << "com_port closed successfully\n";
	}

	std::cout << endl;

	return;
}

// erase device's flash memory contents
void HAMConsole::clear_memory(void){

	// get path for TEMP environment variable
	LPCTSTR envar = L"TEMP";
	LPTSTR temp_buffer = (LPTSTR)malloc(sizeof(long)*32767);
	DWORD chars_written = GetEnvironmentVariable(envar,temp_buffer,32767);

	string temp = CW2A(temp_buffer);
	temp.append("\\com_assignment.txt");

	// break up string and later append to correctly interpret whitespace
	string command = "MODE.COM | findstr COM > ";
	//string command2 = "\"E:/Senior Design/com_assignment.txt\"";
	string command_path = "\"";
	command_path.append(temp.c_str());
	command_path.append("\"");
	command.append(command_path.c_str());

	// find com port device is connected on
	char error_buffer[128];
	if (system(command.c_str()) < 0){
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// text file containing COM port assignment
	FILE *com_file;
	// break up string and later append to correctly interpret whitespace
	//string path1 = "E:/Senior\x20";
	//string path2 = "Design/com_assignment.txt";
	//path1.append(path2);
	if (fopen_s(&com_file,temp.c_str(),"r") != 0) {
		strerror_s(error_buffer,128,errno);
		std::cout << error_buffer << endl;
		return;
		//exit(1);
	}

	// Read text file
	// Get second line of text, first line contains COM1 which is reserved
	char COM_string[60];
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}
	if (fgets(COM_string,60,com_file) == NULL){
		std::cout << strerror_s(error_buffer,128,errno) << endl;
		return;
		//exit(1); // unsuccessful process termination
	}

	// close text file 
	if (fclose(com_file) != 0){
		std::cout << "error in closing com_file\n";
		return;
		//exit(1); // unsuccesful process termination
	}

	// tokenize string to obtain COM port
	char *com_port_string;
	char *next_string;
	com_port_string = strtok_s(COM_string," :\t\n",&next_string);
	int m;
	for (m=0; m<4; m++){
		com_port_string = strtok_s(NULL, " :M\t\n",&next_string);
	}

	// Check if COM number is greater than 10
	// Modify string accordingly
	string com_temp = com_port_string;
	if (stoi(com_port_string,nullptr,10) > 9){
		com_temp = com_temp.insert(0,"\\\\.\\COM");
	}
	else {
		com_temp = com_temp.insert(0,"COM");
	}

	// convert string to appriate type to be passed to CreateFile()
	wstring stemp = s2ws(com_temp);
	LPCWSTR com_name = stemp.c_str();
	wcout << "Device is on " << com_name << endl;

	// open the com port the device is connected to
	HANDLE com_port = CreateFile(com_name,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (com_port == INVALID_HANDLE_VALUE){
		std::cout << "error: invalid handle value\n";
		return;
		//exit(1); // unsuccessful process termination 
	}

	//  Initialize the DCB structure.
   DCB dcb;
   BOOL fSuccess;
   SecureZeroMemory(&dcb, sizeof(DCB));
   dcb.DCBlength = sizeof(DCB);

   //  Build on the current configuration by first retrieving all current
   //  settings.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

   //  Fill in some DCB values and set the com state: 
   //  57,600 bps, 8 data bits, no parity, and 1 stop bit.
   dcb.BaudRate = CBR_9600;     //  baud rate
   dcb.ByteSize = 8;             //  data size, xmit and rcv
   dcb.Parity   = NOPARITY;      //  parity bit
   dcb.StopBits = ONESTOPBIT;    //  stop bit 

   fSuccess = SetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("SetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(3);
   }

   //  Get the comm config again.
   fSuccess = GetCommState(com_port, &dcb);

   if (!fSuccess) 
   {
      //  Handle the error.
      printf ("GetCommState failed with error %d.\n", GetLastError());
      return;
	  //exit(2);
   }

	// set comm timeouts
	LPCOMMTIMEOUTS comm_timeouts = (LPCOMMTIMEOUTS)malloc(sizeof(DWORD)*5);
	comm_timeouts->ReadIntervalTimeout = 1000; // 1 second
	comm_timeouts->ReadTotalTimeoutConstant = 0;
	comm_timeouts->ReadTotalTimeoutMultiplier = 10;
	comm_timeouts->WriteTotalTimeoutConstant = 0;
	comm_timeouts->WriteTotalTimeoutMultiplier = 10;
	if (SetCommTimeouts(com_port,comm_timeouts) == 0){
		std::cout << "error: setting timeouts failed\n";
		return;
		//exit(1);
	}

	// send 'C' to initiate memory clear
	char writeBuffer[8];
	char readBuffer[8];
	LPDWORD bytes_written = (LPDWORD)malloc(sizeof(long));;
	LPDWORD bytes_read = (LPDWORD)malloc(sizeof(long));;
	writeBuffer[0] = 'C';
	if (WriteFile(com_port,writeBuffer,1,bytes_written,NULL) == 0){
		std::cout << "error: WriteFile() failed\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	// Wait until an 'C' is received from the microcontroller 
	do {
		if (ReadFile(com_port,readBuffer,1,bytes_read,NULL) == 0){
			std::cout << "error: ReadFile() failed\n";
			return;
			//exit(1); // unsuccessful process termination
		}	
		//cout << "waiting for 'C'" << endl;
	} while(readBuffer[0] != 'C'); // 'C' for next

	// close open files, ports, etc.
	// free dynamically allocated memory
	free(bytes_read);
	free(bytes_written);

	if (CloseHandle(com_port) == 0){
		std::cout << "error in closing the com_port\n";
		return;
		//exit(1); // unsuccessful process termination
	}
	else {
		std::cout << "com_port closed successfully\n";
	}

	std::cout << endl;

	return;
}

// prints instructions for using each option
void HAMConsole::help(void) {
	
	std::cout << "DESCRIPTION OF OPTIONS" << endl;
	std::cout << "1. Offload data from device memory" << endl;
	std::cout << '\t' << "offload's activity data from device's flash memory and writes to text file" << endl;
	std::cout << '\t' << "Be sure to enter valid file path when prompted" << endl;
	std::cout << "2. Set device time" << endl;
	std::cout << '\t' << "set's the device's internal time using real-time clock" << endl;
	std::cout << '\t' << "time format: hh:mm:ss (e.g. 17:15:01)" << endl;
	std::cout << '\t' << "default time is computer system time" << endl;
	std::cout << "3. Enter device ID" << endl;
	std::cout << '\t' << "sets device id to differentiate between many devices" << endl;
	std::cout << "4. Clear memory contents" << endl;
	std::cout << '\t' << "erases device's flash memory" << endl;
	std::cout << "5. Help" << endl;
	std::cout << "6. Exit" << endl;
	std::cout << '\t' << "terminates ACTIVITY MONITOR DATA OFFLOAD PROGRAM" << endl;
	std::cout << endl;

}