//-------------------------------------------------------------------------------------------------
// <copyright file="FltPyldComms.c" company="LiquidRobotics">
//  Copyright (c) Liquid Robotics Corporation, confidential and proprietary.  All rights reserved. 
// </copyright>
//
// <summary>
// 	This is the source for managing communication between the PIB, Float, and 
//  other payloads daisychained off the PIB
// </summary>
// </summary>
//
// <owners>Jim Kirklin and Rob Tow</owner>
//-------------------------------------------------------------------------------------------------

/*
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#include "common.h"
*/

#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>
#include "common.h"
#include <string.h>
#include <pthread.h>


#define SHOW_SENDS_AND_RECEIVES



#pragma pack(push,1)
typedef struct _PIB_ID_RESPONSE_
{
	LRI_COMM_WRAPPER 		headers;
	LRI_GENERIC_ACK			ackInfo;
	LRI_ACK_COUNT_WRAPPER	idCount;
	LRI_ID_PACKET			idPacket;
	uint16_t				crc;
}PIB_ID_RESPONSE, *PPIB_ID_RESPONSE;
#pragma pack(pop)

#pragma pack(push,1)
typedef struct _PIB_STATUS_RESPONSE_
{
	LRI_COMM_WRAPPER 		headers;
	LRI_GENERIC_ACK			ackInfo;
	LRI_ACK_COUNT_WRAPPER	pibCount;
	LRI_PIB_STATUS			pibPacket;
	uint16_t				crc;
}PIB_STATUS_RESPONSE, *PPIB_STATUS_RESPONSE;
#pragma pack(pop)


#pragma pack(push,1)
typedef struct _PIB_IRIDIUM_DATA_XMIT_
{
	LRI_COMM_WRAPPER 						headers;
	LRI_GENERIC_ACK							ackInfo;
	LRI_IRIDIUM_DATA_REQUEST_ACK_WRAPPER	iridiumInfo;
}PIB_IRIDIUM_DATA_XMIT, *PPIB_IRIDIUM_DATA_XMIT;
#pragma pack(pop)

#pragma pack(push,1)
typedef struct _PIB_POWER_RESPONSE_
{
	LRI_COMM_WRAPPER 					headers;
	LRI_GENERIC_ACK						ackInfo;
	LRI_ACK_COUNT_WRAPPER				powerCount;
	ACK_PYLD_POWER_NOTIFICATION_RECORD	powerState;
	uint16_t							crc;
}PIB_POWER_RESPONSE, *PPIB_POWER_RESPONSE;
#pragma pack(pop)

PIB_ID_RESPONSE 	pibIDResponse;	
PIB_STATUS_RESPONSE	pibStatusResponse;	
PIB_POWER_RESPONSE  pibPowerResponse;

FILE_ACKS		pyldFileAcks;
FILE_NAKS		pyldFileNaks;

FILE_WRITE_IN_PROGRESS	writingFile;
char rxFloatData[HDLC_MAX_LENGTH];	



void send_error_return(char *error_str, int transaction_id);
void TxHDLC(uint8_t* pTxHDLCBuf, uint16_t activeTxLen);
uint16_t RxHDLC(char *pHDLCBuf);

uint8_t ValidateCRC16(uint8_t* pBuffer, uint16_t size, uint16_t initValue);
uint16_t CalculateCRC16(uint8_t* pBuffer, uint16_t size, uint16_t initValue);

void PIBToFloatSendID(uint16_t command, uint16_t msgSeq, uint16_t destination);
void PIBToFloatSendPIBStatus(uint16_t command, uint16_t msgSeq, uint16_t destination);
void PIBToFloatSendWaitingData(uint16_t command, uint16_t msgSeq, uint16_t destination);
void PIBToFloatSendNAK(uint16_t command, uint16_t msgSeq, uint16_t destination);
void PIBToFloatSendPowerReply(PLRI_COMM_WRAPPER pBuffer);

void PIBRcvdFloatCmd(PPYLD_MGR_FILE_RX_BUFFER pHeaders);
void CancelWriteInProgress();

void FileInitializeWrite(PPYLD_MGR_FILE_RX_BUFFER pHeaders);
void FileWriteBlock(PPYLD_MGR_FILE_RX_BUFFER pHeaders);
void FileDelete(PPYLD_MGR_FILE_RX_BUFFER pHeaders);
void FileReadBlock(PPYLD_MGR_FILE_RX_BUFFER pHeaders);
void FileReadComplete(PPYLD_MGR_FILE_RX_BUFFER pHeaders);
void FileGetInfo(PPYLD_MGR_FILE_RX_BUFFER pHeaders);
void FileGetDetail(PPYLD_MGR_FILE_RX_BUFFER pHeaders);

uint16_t crc16_update(uint16_t crc, uint8_t a);

uint8_t	PadToDot(char* pad, char* dot);
uint8_t	DotToPad(char* pad, char* dot);

FLOAT_TX_BUFFER txFloatData[MAX_FLOAT_BUFFERS];	
uint8_t	headFloatTx = 0;
uint8_t tailFloatTx = 0;

uint16_t fileWriteCount = 0;

//#define MAIN_TASK_ADDRESS	0x1500

uint16_t mainTaskAddress = MAIN_TASK_ADDRESS;		//0x1500
uint8_t	mainBoardID = 0;

char	fixValid;

uint16_t	saved_msgID;





void *execute_file_thread(void *pParam);
char execute_file_thread_fileName[13] 		= {0};
char execute_file_thread_result_name[256] 	= {0};

//CPayloadSimulatorDlg* myDialog;

void Float_Comm_Init(void)
{

	memset(&txFloatData[0], 0, sizeof(FLOAT_TX_BUFFER) * MAX_FLOAT_BUFFERS);

	memset(&writingFile, 0, sizeof(FILE_WRITE_IN_PROGRESS));

	mainBoardID = (mainTaskAddress >> 8);		//0x15;

//	myDialog->OpenSerialPort();
	//OS Specific UART Init
	//OSuartInitPort(FLOAT_PORT, 115200, UART_MODE_EIGHT_DATA_BITS, UART_MODE_ONE_STOP_BIT, UART_MODE_NO_PARITY);

}


//Thread of some sort for this function
//DWORD FloatComms(LPVOID pParam)
void *FloatComms(void *pParam)
{
//	myDialog = (CPayloadSimulatorDlg*)pParam;

	PLRI_COMM_WRAPPER pHeaders = (PLRI_COMM_WRAPPER)(&rxFloatData[1]);
	PLRI_REQUEST_PIB_STATUS pStatus = (PLRI_REQUEST_PIB_STATUS)(&(rxFloatData[1]) + sizeof(LRI_COMM_WRAPPER));
//	uint8_t err = 0;

        printf("Entered FloatComms()\n");

	Float_Comm_Init();

	//Sleep(1000);
	//sleep(1000);

	/*  Need to adjust serial port function...
	SerialPortFlush(PURGE_TXCLEAR | PURGE_TXABORT |PURGE_RXCLEAR | PURGE_RXABORT );
	*/
	SerialPortFlush(NULL);


	while(runThreads == TRUE)
	{
		pHeaders= (PLRI_COMM_WRAPPER)(rxFloatData + 1);
		pStatus = (PLRI_REQUEST_PIB_STATUS)(rxFloatData + 1 + sizeof(LRI_COMM_WRAPPER));
		
		memset(rxFloatData, 0, HDLC_MAX_LENGTH);
		RxHDLC(rxFloatData);
		
		//myDialog->AddHexDataToWindow(INBOUND_WINDOW, (unsigned char*)pHeaders, (int)pHeaders->length);

		if(ValidateCRC16((uint8_t*)pHeaders, pHeaders->length, OTHER_CRC_START) == SUCCESS)
		{
			printf("***pHeaders->msgType = %0x\n", pHeaders->msgType);
			printf("***pHeaders->destination= %0x\n", pHeaders->destination);
			printf("***pHeaders->msgID= %0x\n", pHeaders->msgID);
			saved_msgID = pHeaders->msgID;
		        
		         

			fflush(stdout);
			fflush(stderr);

			if ((pHeaders->destination & 0xff00) != MAIN_TASK_ADDRESS)
			{
				printf("destination != MAIN_TASK_ADDRESS; continuing\n");
				continue;
			}

			switch(pHeaders->msgType)
			{
				case REQUEST_ID:
				{
					printf("Received ID Request\r\n");
					//PIBToFloatSendID(pHeaders->msgType, pHeaders->msgID, pHeaders->source);
					break;
				}
				case REQUEST_PIB_STATUS:
				{
					tm_pyld time;

					printf("Received Status Request\r\n");
					time.tm_sec = pStatus->timestamp.second;
					time.tm_min = pStatus->timestamp.minute;
					time.tm_hour = pStatus->timestamp.hour;
					time.tm_mday = pStatus->timestamp.day;
					time.tm_mon = pStatus->timestamp.month;
					time.tm_year = pStatus->timestamp.year;

					//settime_pyld(mktime_pyld(time));

					fixValid = pStatus->fixValid;

					if (fixValid == 'Y')
					{
					  char	date_command[256];

					  sprintf(date_command, "date -u %02d%02d%02d%02d%02d.%02d",
						time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_year, time.tm_sec);
					  system(date_command);
					  //printf("  date: %02d-%02d %02d:%02d:%02d %02d\n", 
						//time.tm_mon, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, time.tm_year);
					  printf("  integer formated location - latitude == %d  longitude == %d\n", pStatus->latitude, pStatus->longitude);
					}
					else
					{
					  printf("  No valid GPS data\n");
					}

					PIBToFloatSendPIBStatus(pHeaders->msgType, pHeaders->msgID, pHeaders->source);
					break;
				}
				case POWER_NOTIFICATION:
				{
					PIBToFloatSendPowerReply(pHeaders);
					break;
				}
				case SEND_FWD_ICD_CMD:
				{
					printf("Received File Request\r\n");
					PIBRcvdFloatCmd((PPYLD_MGR_FILE_RX_BUFFER)pHeaders);
					break;
				}
				case REQUEST_WAITING_PACKET:
				{
					printf("Received Data Request\r\n");
					if(headFloatTx != tailFloatTx)
					{
						printf("Entering 'PIBToFloatSendWaitingData()'...\n");
						PIBToFloatSendWaitingData(pHeaders->msgType, pHeaders->msgID, pHeaders->source);
						printf("returned from 'PIBToFloatSendWaitingData()'\n");
					}
					else
					{
						printf("entering 'PIBToFloatSendNAK()'...\n");
						PIBToFloatSendNAK(pHeaders->msgType, pHeaders->msgID, pHeaders->source);
						printf("returned from 'PIBToFloatSendNAK()'\n");
					}
					
					break;
				}
				default:
				{
					//Unknown packet
					break;
				}
			}
		}
	}
	return 0;
}



DWORD PIBFileWatcher(LPVOID pParam)
{
	PFS_REPORT pReport = NULL;
	char fileName[13] = {0};
	BOOL newFile = TRUE;
	struct stat statBuf;
	struct tm* dateTime;

	sprintf(fileName, "%s", (char*)pParam);
	printf("Queueing New File Available -- %s\r\n", fileName);

	//Some method of wathcing and flagging new files to report in the file system -- probably a thread of some sort

//	while (1)
//	{
		//If using a timer on writes and reads as wellas a thread for watching the file system, this might be a good place to check the timer
		//Make sure write is still progressing
		//if((writingFile.writeStatus == WRITE_IN_PROGRESS) && ((current tick count - writingFile.tickCount) > ???))
		//{
		//	CancelWriteInProgress();
		//}

		//Check Files -- if new ones, set newFile = TRUE and get fileName
		if(newFile == TRUE)
		{

			if(stat(fileName, &statBuf) == 0)
			{
				//OS Specific -- protecting Queue head and tail values
				//OSMutexPend(pMutexFloatQueue, INFINITE, &err);
				pReport = (PFS_REPORT)&(txFloatData[headFloatTx]);

				memset(pReport, 0, sizeof(FS_REPORT));

				pReport->headers.length  = sizeof(FS_REPORT) + CRC16_SIZE;
				pReport->headers.destination = FLOAT_FS_INTERFACE;
				pReport->type = NEW_FILE_AVAILABLE;

				//Need to fill in these values appropriately
				pReport->newFile.fileSize = statBuf.st_size;
				dateTime = gmtime(&statBuf.st_ctime);
				pReport->newFile.creationDate.day = dateTime->tm_mday;
				pReport->newFile.creationDate.hour = dateTime->tm_hour;
				pReport->newFile.creationDate.minute = dateTime->tm_min;
				pReport->newFile.creationDate.month = dateTime->tm_mon + 1;
				pReport->newFile.creationDate.second = dateTime->tm_sec;
				pReport->newFile.creationDate.year = (uint8_t)(dateTime->tm_year - 100);
				dateTime = gmtime(&statBuf.st_mtime);
				pReport->newFile.modifiedDate.day = dateTime->tm_mday;
				pReport->newFile.modifiedDate.hour = dateTime->tm_hour;
				pReport->newFile.modifiedDate.minute = dateTime->tm_min;
				pReport->newFile.modifiedDate.month = dateTime->tm_mon + 1;
				pReport->newFile.modifiedDate.second = dateTime->tm_sec;
				pReport->newFile.modifiedDate.year = (uint8_t)(dateTime->tm_year - 100);

				pReport->newFile.fileAttributes = 0;
				memset(&pReport->newFile.calculatedMD5, 0, sizeof(MD5));
				memset(&pReport->newFile.providedMD5, 0, sizeof(MD5));
				pReport->newFile.calculatedCRC = 0;
				pReport->newFile.providedCRC = 0;
				pReport->newFile.storageControllerAddress = mainTaskAddress;
				DotToPad(pReport->newFile.fileName, fileName);

				(headFloatTx < (MAX_FLOAT_BUFFERS - 1)) ? (headFloatTx++) : (headFloatTx = 0);
	
				if(headFloatTx == tailFloatTx)
				{
					(tailFloatTx < (MAX_FLOAT_BUFFERS - 1)) ? (tailFloatTx++) : (tailFloatTx = 0);
				}

			//OS Specific -- protecting Queue head and tail values
			//OSMutexPost(pMutexFloatQueue);

			}
		}
//		Sleep(10000);	//10 second sleep before checking again -- can be whatever is appropriate
//	}
	return 0;
}


void PIBToFloatSendID(uint16_t command, uint16_t msgSeq, uint16_t destination)
{

	pibIDResponse.headers.length = sizeof(PIB_ID_RESPONSE);
	pibIDResponse.headers.destination = destination;
	pibIDResponse.headers.source = mainTaskAddress;
	pibIDResponse.headers.msgID = msgSeq;
	pibIDResponse.headers.msgType = LRI_ACK;

	pibIDResponse.ackInfo.originalCmd = command;

	pibIDResponse.idCount.totalNumber = 1;
	pibIDResponse.idCount.numberOfReplies = 1;

	pibIDResponse.idPacket.version = 0x0001;
	pibIDResponse.idPacket.deviceType = 0x10;
	pibIDResponse.idPacket.address = mainTaskAddress;
	memcpy(&(pibIDResponse.idPacket.serialNum[0]), "123456", 6);
	pibIDResponse.idPacket.port = 0;
	pibIDResponse.idPacket.pollingRate = 20;
	pibIDResponse.idPacket.extraInfo = 0;
	pibIDResponse.idPacket.firmwareMajor = MAJOR;
	pibIDResponse.idPacket.firmwareMinor = MINOR;
	pibIDResponse.idPacket.firmwareRev = BUILD;
	memcpy(&(pibIDResponse.idPacket.description[0]), "Payload Simulator     ", 20);


	pibIDResponse.crc = CalculateCRC16((uint8_t*)&pibIDResponse, pibIDResponse.headers.length - CRC16_SIZE, OTHER_CRC_START);

	TxHDLC((uint8_t*)&pibIDResponse, pibIDResponse.headers.length);

	return;
}


void PIBToFloatSendPIBStatus(uint16_t command, uint16_t msgSeq, uint16_t destination)
{


	pibStatusResponse.headers.length = sizeof(PIB_STATUS_RESPONSE);
	pibStatusResponse.headers.destination = destination;
	pibStatusResponse.headers.source = mainTaskAddress;
	pibStatusResponse.headers.msgID = msgSeq;
	pibStatusResponse.headers.msgType = LRI_ACK;

	pibStatusResponse.ackInfo.originalCmd = command;

	pibStatusResponse.pibCount.totalNumber = 1;
	pibStatusResponse.pibCount.numberOfReplies = 1;

	pibStatusResponse.pibPacket.version = 1;
	if(headFloatTx != tailFloatTx)
	{
		pibStatusResponse.pibPacket.version |= 0x8000;
	}
	pibStatusResponse.pibPacket.address = mainTaskAddress;
	pibStatusResponse.pibPacket.alarms = 0;
	pibStatusResponse.pibPacket.leak1 = 0;
	pibStatusResponse.pibPacket.leak2 = 0;
	pibStatusResponse.pibPacket.humidTemp = 0;	//pibTempHum;
	pibStatusResponse.pibPacket.humidity = 0;	//pibHumidity;
	pibStatusResponse.pibPacket.presTemp = 0;	//pibPressure;
	pibStatusResponse.pibPacket.pressure = 0;	//pibTempPres;

	pibStatusResponse.crc = CalculateCRC16((uint8_t*)&pibStatusResponse, pibStatusResponse.headers.length - CRC16_SIZE, OTHER_CRC_START);
	
	TxHDLC((uint8_t*)&pibStatusResponse, pibStatusResponse.headers.length);


	return;
}

void PIBToFloatSendPowerReply(PLRI_COMM_WRAPPER pBuffer)
{
	printf("Received a Power Down notification\r\n");
	pibPowerResponse.headers.length = sizeof(PIB_POWER_RESPONSE);
	pibPowerResponse.headers.destination = pBuffer->source;
	pibPowerResponse.headers.source = mainTaskAddress;
	pibPowerResponse.headers.msgID = pBuffer->msgID;
	pibPowerResponse.headers.msgType = LRI_ACK;

	pibPowerResponse.ackInfo.originalCmd = pBuffer->msgType;

	pibPowerResponse.powerCount.totalNumber = 1;
	pibPowerResponse.powerCount.numberOfReplies = 1;

	pibPowerResponse.powerState.address = mainTaskAddress;
	pibPowerResponse.powerState.boardID = mainBoardID;
	pibPowerResponse.powerState.state = 1;
	pibPowerResponse.powerState.delayOff = 60;
	pibPowerResponse.powerState.delayOn = 0;

	pibPowerResponse.crc = CalculateCRC16((uint8_t*)&pibPowerResponse, pibPowerResponse.headers.length - CRC16_SIZE, OTHER_CRC_START);
	
	TxHDLC((uint8_t*)&pibPowerResponse, pibPowerResponse.headers.length);

	runThreads = FALSE;  // This will cause the main thread to issue a shutdown.

	return;
}



void PIBToFloatSendWaitingData(uint16_t command, uint16_t msgSeq, uint16_t destination)
{
	uint8_t tempTail = 0;
	uint16_t* pCRC = NULL;
	uint8_t* temp;
	uint8_t err = 0;
	PPIB_IRIDIUM_DATA_XMIT comms = NULL;
	//Wait State is OS Specific -- protecting Queue head and tail values
	//OSMutexPend(pMutexFloatQueue, INFINITE, &err);

	tempTail = tailFloatTx + 1;
	if(tempTail >= MAX_FLOAT_BUFFERS) tempTail = 0;

	temp = (uint8_t*)&(txFloatData[tailFloatTx]);

	comms = (PPIB_IRIDIUM_DATA_XMIT)&(txFloatData[tailFloatTx]);


	comms->headers.destination |= (destination & 0xFF00);		// | FLOAT_IRIDIUM_INTERFACE;
	comms->headers.source = mainTaskAddress;
	comms->headers.msgID = msgSeq;
	comms->headers.msgType = LRI_ACK;

	comms->ackInfo.originalCmd = command;
	if(tempTail != headFloatTx)
	{
		comms->ackInfo.originalCmd |= 0x8000;
	}
	
	temp += comms->headers.length;
	temp -= CRC16_SIZE;

	pCRC = (uint16_t*)temp;
	*pCRC = CalculateCRC16((uint8_t*)comms, comms->headers.length - CRC16_SIZE, OTHER_CRC_START);

	TxHDLC((uint8_t*)comms, comms->headers.length);

	(tailFloatTx < MAX_FLOAT_BUFFERS - 1) ? (tailFloatTx++) : (tailFloatTx = 0);

	//Wait State is OS Specific -- protecting Queue head and tail values
	//OSMutexPost(pMutexFloatQueue);

	return;
}


void CancelWriteInProgress()
{
	//Delete writingFile.tempFileName
	memset(&writingFile, 0, sizeof(FILE_WRITE_IN_PROGRESS));
	writingFile.writeStatus = NO_WRITE_IN_PROGRESS;

	return;
}

void PIBRcvdFloatCmd(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	switch(pHeaders->type.command)
	{
	case FILE_INIT_WRITE:
		{
			FileInitializeWrite(pHeaders);
			break;
		}
	case FILE_WRITE_BLOCK:
		{
			FileWriteBlock(pHeaders);
			break;
		}
	case FILE_DELETE:
		{
			FileDelete(pHeaders);
			break;
		}
	case FILE_READ_BLOCK:
		{
			FileReadBlock(pHeaders);
			break;
		}
	case FILE_GET_INFO:
		{
			FileGetInfo(pHeaders);
			break;
		}
	case FILE_GET_DETAIL:
		{
			FileGetDetail(pHeaders);
			break;
		}
	}	
	return;
}

void FileInitializeWrite(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	int fd;

	char fileName[13] = {0};
	BOOL proceed = TRUE;
	int nakType = 0;
	uint8_t retval = FAIL;
			
	memcpy(fileName, pHeaders->initFileWrite.fileName, 11);
	//printf("Write Init: File ID = %08X -- name = %s\r\n", pHeaders->initFileWrite.fileID, fileName);
        //  "lX" rather than "x"...
	printf("Write Init: File ID = %08lX -- name = %s\r\n", pHeaders->initFileWrite.fileID, fileName);

	memset(fileName, 0, 13);

	//Check for WGMS File ID in logs to see if it already exists for current files -- if so, then this new
	//one will delete the old one, even if different names

	if(writingFile.writeStatus == NO_WRITE_IN_PROGRESS)
	{
		retval = PadToDot(pHeaders->initFileWrite.fileName, fileName);
		if(retval == FAIL)
		{
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}
	}
	else
	{
		nakType = NAKDISP_TOO_MANY_COMMANDS;
		proceed = FALSE;
	}
			
	if(proceed)
	{
		memcpy(writingFile.finalFileName, fileName, 13);
		writingFile.contentCRC = pHeaders->initFileWrite.contentCRC;
		memcpy(&writingFile.contentMD5, &(pHeaders->initFileWrite.contentMD5), sizeof(MD5));
		memcpy(&writingFile.creationDate, &(pHeaders->initFileWrite.creationDate), sizeof(DATE_TIME));
		memcpy(&writingFile.modifiedDate, &(pHeaders->initFileWrite.modifiedDate), sizeof(DATE_TIME));
		writingFile.fileAttributes = pHeaders->initFileWrite.fileAttributes;
		writingFile.fileID = pHeaders->initFileWrite.fileID;
		memcpy(writingFile.fileName, pHeaders->initFileWrite.fileName, 11);
		PadToDot(pHeaders->initFileWrite.fileName, writingFile.tempFileName);
		writingFile.fileSize = pHeaders->initFileWrite.fileSize;
		writingFile.writeStatus = WRITE_IN_PROGRESS;
		// if want a time-out on file writes -- writingFile.tickCount = (current Tick value)

		//Log WGMS ID, file attributes, creation date, modified date, CRC, MD5 with file name for future reference
		//Need to at least save WGMS ID and File Name correlation -- others are nice but may not be necessary
		//or use writingFile structure with only 1 allowed write at a time
		if(pHeaders->initFileWrite.overwriteFile == 0)
		{
			//check for file
			//fd = _open(fileName, _O_RDONLY);  // Windows
			fd = open(fileName, O_RDONLY);  // Linux
			if(fd != -1)
			{
				//File Exists -- NAK
				nakType = NAKDISP_WOULD_OVERWRITE;
				//_close(fd);  //  Windows
				close(fd);  // Linux
				proceed = FALSE;
			}
		}

		if(proceed)
		{
			//fd = _open(fileName, _O_CREAT | _O_TRUNC | _O_BINARY | _O_WRONLY, _S_IREAD | _S_IWRITE);  // Windows
			fd = open(fileName, O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE);  // Linux
			if(fd != -1)
			{
				//_lseek(fd, pHeaders->initFileWrite.fileSize, SEEK_SET);  // Windows
				lseek(fd, pHeaders->initFileWrite.fileSize, SEEK_SET);  //  Linux
				//_close(fd);  //  Windows
				close(fd);  // Linux
				//Set File Attributes (read only/checked)
			}
			else
			{
				//Unable to create file
				nakType = NAKDISP_DATA;
			}
		}
	}
	if(nakType == 0)
	{
		pyldFileAcks.headers.destination = pHeaders->wrapper.source;
		pyldFileAcks.headers.source = pHeaders->wrapper.destination;
		pyldFileAcks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileAcks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER) + CRC16_SIZE;
		pyldFileAcks.headers.msgType = 0x05;
		pyldFileAcks.ackInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileAcks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileAcks.toShoreheader.size = 0;
		pyldFileAcks.toShoreheader.type = 0x13;
		pyldFileAcks.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER), OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	else
	{
		memset(&writingFile, 0, sizeof(FILE_WRITE_IN_PROGRESS));
		writingFile.writeStatus = NO_WRITE_IN_PROGRESS;
		pyldFileNaks.headers.destination = pHeaders->wrapper.source;
		pyldFileNaks.headers.source = pHeaders->wrapper.destination;
		pyldFileNaks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileNaks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE);
		pyldFileNaks.headers.msgType = 0x04;
		pyldFileNaks.nakInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileNaks.nakInfo.nakSummary = 0;
		pyldFileNaks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileNaks.toShoreheader.size = 3;
		pyldFileNaks.toShoreheader.type = 0x24;
		pyldFileNaks.nakFile.count = 1;
		pyldFileNaks.nakFile.result = nakType;
		pyldFileNaks.nakFile.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	return;
}


void FileWriteBlock(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	int fd = -1;
	char fileName[13] = {0};
	uint32_t hyperionID = 0;
	BOOL proceed = TRUE;
	int nakType = 0;
	int bytesWritten = 0;
	int numBytes = 0;
	char tempBuf[200] = {0};
	long startPos = 0;
	long currentPos = 0;
			
	hyperionID = pHeaders->writeFile.fileID;

	//printf("Write: File ID = %08X -- start = %d\r\n", hyperionID, pHeaders->writeFile.offset);
        //  "lX" rnd "ld" rather than "x" and "d"...
	printf("Write: File ID = %08lX -- start = %ld\r\n", hyperionID, pHeaders->writeFile.offset);

	//Get Filename from log file based on Hyperion ID or use writingFile structure with only 1 allowed write at a time
	//Get final File Size from Hyperion ID
	if((writingFile.writeStatus == WRITE_IN_PROGRESS) && (hyperionID == writingFile.fileID))
		memcpy(fileName, writingFile.tempFileName, 13);
	else
		fileName[0] = 0;

	if(fileName[0] == 0)
	{
		nakType = NAKDISP_DATA;
		proceed = FALSE;
	}

	if(proceed)
	{
		//fd = _open(fileName, _O_BINARY | _O_WRONLY, _S_IREAD | _S_IWRITE);  //  Windows
		fd = open(fileName, O_WRONLY, S_IREAD | S_IWRITE);
		if(fd != -1)
		{
			numBytes = pHeaders->writeFile.numDataBytes;
			/*
			startPos = _lseek(fd, pHeaders->writeFile.offset, SEEK_SET);
			bytesWritten = _write(fd, pHeaders->writeFile.data, numBytes);
			currentPos = _lseek(fd, 0, SEEK_CUR);
			_close(fd);
			*/
			startPos = lseek(fd, pHeaders->writeFile.offset, SEEK_SET);
			bytesWritten = write(fd, pHeaders->writeFile.data, numBytes);
			currentPos = lseek(fd, 0, SEEK_CUR);
			close(fd);

			if(bytesWritten != numBytes)
			{
				nakType = NAKDISP_STORAGE_IO_ERROR;
			}

			//printf("Wrote %d bytes at Position %d\r\n", bytesWritten, startPos);
			//  "ld" rather than "d"...
			printf("Wrote %d bytes at Position %ld\r\n", bytesWritten, startPos);

			//If using timer fo rwrite file time out -- writingFile.tickCount = (current Tick value)
			if((pHeaders->writeFile.offset + numBytes) >= writingFile.fileSize)
			{
				//Rename writingFile.tempFileName to writingFile.finalFileName
				//Log information in log file 
				//printf("Write: File ID = %08X Done!!!\r\n", hyperionID);
				// "lX" rather "X"...
				printf("Write: File ID = %08lX Done!!!\r\n", hyperionID);
				memset(&writingFile, 0, sizeof(FILE_WRITE_IN_PROGRESS));
				writingFile.writeStatus = NO_WRITE_IN_PROGRESS;

                                //  Now decide what to do with the file...
				printf("Finished writing file %s with Hyperion i.d. %08lx\n", 
				  fileName, hyperionID); 
				printf("---destination = %0x\n", pHeaders->wrapper.destination);
				printf("---'msgID' == 0x%x\n", pHeaders->wrapper.msgID);
			}	
		}
		else
		{
			nakType = NAKDISP_DATA;
		}
	}

	if(nakType == 0)
	{
		pyldFileAcks.headers.destination = pHeaders->wrapper.source;
		pyldFileAcks.headers.source = pHeaders->wrapper.destination;
		pyldFileAcks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileAcks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER) + CRC16_SIZE;
		pyldFileAcks.headers.msgType = 0x05;
		pyldFileAcks.ackInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileAcks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileAcks.toShoreheader.size = 0;
		pyldFileAcks.toShoreheader.type = 0x13;
		pyldFileAcks.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER), OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	else
	{
		memset(&writingFile, 0, sizeof(FILE_WRITE_IN_PROGRESS));
		writingFile.writeStatus = NO_WRITE_IN_PROGRESS;
		pyldFileNaks.headers.destination = pHeaders->wrapper.source;
		pyldFileNaks.headers.source = pHeaders->wrapper.destination;
		pyldFileNaks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileNaks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE);
		pyldFileNaks.headers.msgType = 0x04;
		pyldFileNaks.nakInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileNaks.nakInfo.nakSummary = 0;
		pyldFileNaks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileNaks.toShoreheader.size = 3;
		pyldFileNaks.toShoreheader.type = 0x24;
		pyldFileNaks.nakFile.count = 1;
		pyldFileNaks.nakFile.result = nakType;
		pyldFileNaks.nakFile.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
        if (proceed)
        {
		if (fd != -1)
		{
			if((pHeaders->writeFile.offset + numBytes) >= writingFile.fileSize)
			{
				switch(pHeaders->wrapper.destination & 0xff)
				{
					case 0x11:
					  	{
						  char	response_filename[256];
					          FILE	*response_file;
  
          					  sprintf(response_filename, "%08x.txt", hyperionID);
						  response_file = fopen(response_filename, "w");
						  printf("Upload complete\n");
						  fprintf(response_file, "Upload complete\n");
						  fclose(response_file);
						  PIBFileWatcher(response_filename);
						  break;
						}
					case 0x12:
						printf("Execute file %s\n", fileName);
						{
						  char		command[256];
						  FILE 		*fpipe;
						  FILE 		*result;
						  char 		line[256];
						  char 		err[256];
					          char		result_name[256];

						  int             thread_create_rtn;
					          pthread_t       thread_id;

						  sprintf(execute_file_thread_fileName, "%s", fileName);
						  sprintf(execute_file_thread_result_name, "%08x.txt", hyperionID);
						  thread_create_rtn = pthread_create(&thread_id, NULL, execute_file_thread, NULL);

        					  if (thread_create_rtn == 0)
          					    printf("execute_file_thread() thread created.\n");
        					  else
        					  {
          					    printf("Unable to create execute_file_thread() Thread\n");
          					    printf("Return value from pthread_create == %d\n", thread_create_rtn);
        					  }

						}
						break;
					case 0x13:
						printf("Send a named file back\n");
						{
						  char		file_to_send[256];
						  FILE		*downloaded_command_file;
						  int		i;
						  char		error_str[256];

						  downloaded_command_file = fopen(fileName, "r");
						  if (downloaded_command_file == NULL)
						  {
    						    sprintf(error_str, "Problem opening %s\n", fileName);
						    perror(error_str);
						    send_error_return(error_str, hyperionID);
						  }
						  fgets(file_to_send, sizeof file_to_send, downloaded_command_file);
						  printf("'file_to_send' before newline scan == %s\n", file_to_send);
						  //  The string may have a newline in it. Search for newline and replace it with a zero, or stop at a zero.
						  for (i = 0; i <255; i++)
						     if (file_to_send[i] == '\n') file_to_send[i] = 0; 
						  printf("'file_to_send' after newline scan == %s\n", file_to_send);


						  //  First check to see if the file exists!
						  if (access(file_to_send, F_OK) == -1)
						  {
						    char	error_str[256];

						    sprintf(error_str, "ERROR: file %s does not exist\n", file_to_send);
						    send_error_return(error_str, hyperionID);
						    break;
						  }

						  //  Link the file to a new/temp filename, with the transaction ID as part of the name.
						     char	tmp_name[256];
						     char	new_name[256];
						     int	transaction_id;
						     char	command[256];
						     char	*match;

						     //transaction_id = 42;
						     transaction_id = hyperionID;
          					     sprintf(new_name, "%08x", transaction_id);
						     new_name[8] = '.';
					             match = strstr (file_to_send, ".jpg");
					             if(match != NULL)
						     {
						       printf("sending jpg\n");
						       new_name[9] = 'j';
						       new_name[10] = 'p';
						       new_name[11] = 'g';
						       new_name[12] = 0;
						     }
					             else // Force everything else to a .txt extension
						     {
						       printf("sending txt\n");
						       new_name[9] = 't';
						       new_name[10] = 'x';
						       new_name[11] = 't';
						       new_name[12] = 0;
						     }
						  sprintf(command, "ln %s %s",  file_to_send, new_name);
						  system(command);
						  PIBFileWatcher(new_name);
						}
					        break;
					default:
						printf("Unknown task id = 0x%x\n", pHeaders->wrapper.destination & 0xff);
						break;
				}
			}
		}
	}
	return;
}




void *execute_file_thread(void *pParam)
{
	char		command[256];
	FILE 		*fpipe;
	FILE 		*result;
	char 		line[256];
	char 		err[256];
	char		result_name[256];
	int		line_cnt;

	printf(">>>>>>>Entered execute_file_thread()\n");
	printf("'execute_file_thread_fileName' == %s\n", execute_file_thread_fileName);
	printf("'execute_file_thread_result_name == %s\n", execute_file_thread_result_name);



	//sprintf(command, "sh %s", execute_file_thread_fileName);
	sprintf(command, "sh %s 2>&1", execute_file_thread_fileName);

        printf("\n executing file %s via 'popen()' - piping result to console and '%s'...\n", execute_file_thread_fileName, execute_file_thread_result_name);
        if ( !(fpipe = (FILE*)popen(command,"r")) )
        {  // If fpipe is NULL
          perror("Problems with pipe");
          //exit(1);
        }
        result = fopen(execute_file_thread_result_name, "w");
        if (result == NULL)
        {
          sprintf(err, "Problem opening %s\n", execute_file_thread_result_name);
          perror(err);
          //exit(1);
        }

        line_cnt = 0;

        while ( fgets( line, sizeof line, fpipe))
        {
          printf("%s", line);
          fprintf(result, "%s", line);
          line_cnt++;
        }
        pclose(fpipe);

	if (line_cnt == 0)		// Don't queue up a zero length file - always send at least one byte!
		fprintf(result, "\n");
        fclose(result);
        printf("\nDone piping result of 'popen()' to console and to '%s'n", execute_file_thread_result_name);
        printf("Sending '%s' to shore...\n", execute_file_thread_result_name);
        PIBFileWatcher(execute_file_thread_result_name);
        printf("...returned from PIBFileWatcher(%s)\n", execute_file_thread_result_name);

	pthread_exit(NULL);
}










void FileDelete(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	char fileName[13] = {0};
	uint32_t hyperionID;
	BOOL proceed = TRUE;
	int nakType = 0;
	uint8_t retval = FAIL;
			
	hyperionID = pHeaders->deleteFile.fileID;
	if(hyperionID != 0xFFFFFFFF)
	{
		//Find Hyperion ID in log file and get file name
		if(fileName[0] == 0)
		{
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}
		if(proceed)
		{
			//printf("Delete: File ID = %08X\r\n", hyperionID);
			//  ""lX" rather than "X"...
			printf("Delete: File ID = %08lX\r\n", hyperionID);
			remove(fileName);
			//Remove info for file from log file so there is no longer a correlation between file ID and file name
		}
	}
	else
	{
		retval = PadToDot(pHeaders->deleteFile.fileName, fileName);

		if(retval == FAIL)
		{
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}

		if(proceed)
		{
			printf("Delete: File Name = %s\r\n", fileName);
			remove(fileName);
			//Clean up any log file if necessary
		}
	}

	if(nakType == 0)
	{
		pyldFileAcks.headers.destination = pHeaders->wrapper.source;
		pyldFileAcks.headers.source = pHeaders->wrapper.destination;
		pyldFileAcks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileAcks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER) + CRC16_SIZE;
		pyldFileAcks.headers.msgType = 0x05;
		pyldFileAcks.ackInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileAcks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileAcks.toShoreheader.size = 0;
		pyldFileAcks.toShoreheader.type = 0x13;
		pyldFileAcks.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER), OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	else
	{
		pyldFileNaks.headers.destination = pHeaders->wrapper.source;
		pyldFileNaks.headers.source = pHeaders->wrapper.destination;
		pyldFileNaks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileNaks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE);
		pyldFileNaks.headers.msgType = 0x04;
		pyldFileNaks.nakInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileNaks.nakInfo.nakSummary = 0;
		pyldFileNaks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileNaks.toShoreheader.size = 3;
		pyldFileNaks.toShoreheader.type = 0x24;
		pyldFileNaks.nakFile.count = 1;
		pyldFileNaks.nakFile.result = nakType;
		pyldFileNaks.nakFile.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	return;
}


void FileReadBlock(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	int fd = -1;
	char fileName[13] = {0};
	BOOL proceed = TRUE;
	int nakType = 0;
	int bytesRead = 0;
	int numBytes = 0;
	char dataRead[MAX_PYLD_FILE_BLOCK_SIZE] = {0};
	uint8_t retval = FAIL;
			
	retval = PadToDot(pHeaders->readFile.fileName, fileName);

	//printf("Read: File = %s -- start = %d\r\n", fileName, pHeaders->readFile.offset);
	//  "ld" rather than "d"...
	printf("Read: File = %s -- start = %ld\r\n", fileName, pHeaders->readFile.offset);

	if(retval == FAIL)
	{
		nakType = NAKDISP_DATA;
		proceed = FALSE;
	}

	if(proceed)
	{
		//fd = _open(fileName, _O_BINARY | _O_RDONLY, _S_IREAD | _S_IWRITE);  //  Windows
		fd = open(fileName, O_RDONLY, S_IREAD | S_IWRITE);
		if(fd != -1)
		{
			numBytes = pHeaders->readFile.readLength;
			//if(_lseek(fd, pHeaders->readFile.offset, SEEK_SET) == pHeaders->readFile.offset)  //  Windows
			if(lseek(fd, pHeaders->readFile.offset, SEEK_SET) == pHeaders->readFile.offset)  //  Linux
			{
				//bytesRead = _read(fd, dataRead, numBytes);
				bytesRead = read(fd, dataRead, numBytes);
				//_close(fd);  // Windows
				close(fd);  // Linux
				if(bytesRead == 0)
				{
					nakType = NAKDISP_STORAGE_IO_ERROR;
					proceed = FALSE;
				}
			}
			else
			{
				nakType = NAKDISP_STORAGE_IO_ERROR;
				proceed = FALSE;
			}
		}
		else
		{
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}
	}

	if(nakType == 0)
	{
		pyldFileAcks.headers.destination = pHeaders->wrapper.source;
		pyldFileAcks.headers.source = pHeaders->wrapper.destination;
		pyldFileAcks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileAcks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER) + sizeof(ACK_READ_FILE);
		pyldFileAcks.headers.msgType = 0x05;
		pyldFileAcks.ackInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileAcks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileAcks.toShoreheader.size = sizeof(ACK_READ_FILE) - CRC16_SIZE;
		pyldFileAcks.toShoreheader.type = 0x1B;
		pyldFileAcks.ackRead.numDataBytes = bytesRead;
		pyldFileAcks.ackRead.seekOffset = pHeaders->readFile.offset;
		memcpy(pyldFileAcks.ackRead.data, dataRead, bytesRead);
		pyldFileAcks.ackRead.eofFlag = 0xFF;
		pyldFileAcks.ackRead.storageControllerAddress = pHeaders->readFile.storageControllerAddress;
		pyldFileAcks.ackRead.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER)+ sizeof(ACK_READ_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	else
	{
		pyldFileNaks.headers.destination = pHeaders->wrapper.source;
		pyldFileNaks.headers.source = pHeaders->wrapper.destination;
		pyldFileNaks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileNaks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE);
		pyldFileNaks.headers.msgType = 0x04;
		pyldFileNaks.nakInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileNaks.nakInfo.nakSummary = 0;
		pyldFileNaks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileNaks.toShoreheader.size = 3;
		pyldFileNaks.toShoreheader.type = 0x24;
		pyldFileNaks.nakFile.count = 1;
		pyldFileNaks.nakFile.result = nakType;
		pyldFileNaks.nakFile.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	return;
}

//Need to modify so appropriate for read file complete
void FileReadComplete(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	int fd = -1;
	char fileName[13] = {0};
	BOOL proceed = TRUE;
	int nakType = 0;
	int bytesRead = 0;
	int numBytes = 0;
	char dataRead[MAX_PYLD_FILE_BLOCK_SIZE] = {0};
	uint8_t retval = FAIL;
			
	retval = PadToDot(pHeaders->readFile.fileName, fileName);

	//printf("Read: File Complete = %s -- start = %d\r\n", fileName, pHeaders->readFile.offset);
	//  "ld" rather than "d"...
	printf("Read: File Complete = %s -- start = %ld\r\n", fileName, pHeaders->readFile.offset);

	if(retval == FAIL)
	{
		nakType = NAKDISP_DATA;
		proceed = FALSE;
	}

	if(proceed)
	{
		//fd = _open(fileName, _O_BINARY | _O_RDONLY, _S_IREAD | _S_IWRITE);  // Windows
		fd = open(fileName, O_RDONLY, S_IREAD | S_IWRITE);
		if(fd != -1)
		{
			numBytes = pHeaders->readFile.readLength;
			//if(_lseek(fd, pHeaders->readFile.offset, SEEK_SET) == pHeaders->readFile.offset)  // Windows
			if(lseek(fd, pHeaders->readFile.offset, SEEK_SET) == pHeaders->readFile.offset)  // Linux
			{
				//bytesRead = _read(fd, dataRead, numBytes);
				bytesRead = read(fd, dataRead, numBytes);
				//_close(fd);  //Windows
				close(fd);  // Linux
				if(bytesRead == 0)
				{
					nakType = NAKDISP_STORAGE_IO_ERROR;
					proceed = FALSE;
				}
			}
			else
			{
				nakType = NAKDISP_STORAGE_IO_ERROR;
				proceed = FALSE;
			}
		}
	}

	if(nakType == 0)
	{
		pyldFileAcks.headers.destination = pHeaders->wrapper.source;
		pyldFileAcks.headers.source = pHeaders->wrapper.destination;
		pyldFileAcks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileAcks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER) + sizeof(ACK_READ_FILE);
		pyldFileAcks.headers.msgType = 0x05;
		pyldFileAcks.ackInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileAcks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileAcks.toShoreheader.size = sizeof(ACK_READ_FILE) - CRC16_SIZE;
		pyldFileAcks.toShoreheader.type = 0x1B;
		pyldFileAcks.ackRead.numDataBytes = bytesRead;
		pyldFileAcks.ackRead.seekOffset = pHeaders->readFile.offset;
		memcpy(pyldFileAcks.ackRead.data, dataRead, bytesRead);
		pyldFileAcks.ackRead.eofFlag = 0xFF;
		pyldFileAcks.ackRead.storageControllerAddress = pHeaders->readFile.storageControllerAddress;
		pyldFileAcks.ackRead.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER)+ sizeof(ACK_READ_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	else
	{
		pyldFileNaks.headers.destination = pHeaders->wrapper.source;
		pyldFileNaks.headers.source = pHeaders->wrapper.destination;
		pyldFileNaks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileNaks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE);
		pyldFileNaks.headers.msgType = 0x04;
		pyldFileNaks.nakInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileNaks.nakInfo.nakSummary = 0;
		pyldFileNaks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileNaks.toShoreheader.size = 3;
		pyldFileNaks.toShoreheader.type = 0x24;
		pyldFileNaks.nakFile.count = 1;
		pyldFileNaks.nakFile.result = nakType;
		pyldFileNaks.nakFile.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	return;
}


void FileGetInfo(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	char fileName[13] = {0};
	uint32_t hyperionID;
	BOOL proceed = TRUE;
	int nakType = 0;
	uint8_t fileAttributes = 0;
	uint32_t fileSize = 0;
	uint8_t retval = FAIL;

	struct stat statBuf;

	printf("Get Info\r\n");

	hyperionID = pHeaders->getFileList.fileID;

	hyperionID = 0xFFFFFFFF;

	if(hyperionID != 0xFFFFFFFF)
	{
		//Get File Name from Hyperion ID
		if(fileName[0] == 0)
		{
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}
	}
	else
	{
		retval = PadToDot(pHeaders->getFileList.fileName, fileName);
		if(retval == FAIL)
		{
			//NAK -- invalid name
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}
	}

	if(proceed)
	{
		if(stat(fileName, &statBuf) == 0)
		{
			fileSize = statBuf.st_size;
			//Read Only from statBuf.st_mode
		}
		else
		{
			nakType = NAKDISP_DATA;
		}
	}

	//Return File information (size, etc.)
	if(nakType == 0)
	{
		pyldFileAcks.headers.destination = pHeaders->wrapper.source;
		pyldFileAcks.headers.source = pHeaders->wrapper.destination;
		pyldFileAcks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileAcks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER) + sizeof(ACK_FILE_LIST);
		pyldFileAcks.headers.msgType = 0x05;
		pyldFileAcks.ackInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileAcks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileAcks.toShoreheader.size = sizeof(ACK_FILE_LIST) - CRC16_SIZE;
		pyldFileAcks.toShoreheader.type = 0x31;
		pyldFileAcks.ackFileInfo.common.lastReport = 0xFF;
		pyldFileAcks.ackFileInfo.common.numFiles = 1;
		pyldFileAcks.ackFileInfo.common.offset = 0;
		pyldFileAcks.ackFileInfo.common.storageControllerAddress = pHeaders->getFileList.storageControllerAddress;

		pyldFileAcks.ackFileInfo.records[0].fileAttributes = fileAttributes;		//File Attributes fneed to be filled in
		pyldFileAcks.ackFileInfo.records[0].fileID = hyperionID;	//Hyperion ID needs to be filled in
		pyldFileAcks.ackFileInfo.records[0].fileSize = fileSize;	//File Size needs to be filled in

		DotToPad(pyldFileAcks.ackFileInfo.records[0].fileName, fileName);

		pyldFileAcks.ackFileInfo.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER)+ sizeof(ACK_FILE_LIST) - CRC16_SIZE, OTHER_CRC_START);

		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	else
	{
		pyldFileNaks.headers.destination = pHeaders->wrapper.source;
		pyldFileNaks.headers.source = pHeaders->wrapper.destination;
		pyldFileNaks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileNaks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE);
		pyldFileNaks.headers.msgType = 0x04;
		pyldFileNaks.nakInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileNaks.nakInfo.nakSummary = 0;
		pyldFileNaks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileNaks.toShoreheader.size = 3;
		pyldFileNaks.toShoreheader.type = 0x24;
		pyldFileNaks.nakFile.count = 1;
		pyldFileNaks.nakFile.result = nakType;
		pyldFileNaks.nakFile.crc = CalculateCRC16((uint8_t*) &pyldFileNaks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileNaks, pyldFileNaks.headers.length);
	}
	return;
}


void FileGetDetail(PPYLD_MGR_FILE_RX_BUFFER pHeaders)
{
	char fileName[13] = {0};
	uint32_t hyperionID;
	BOOL proceed = TRUE;
	int nakType = 0;
	uint8_t fileAttributes = 0;
	uint32_t fileSize = 0;
	uint8_t retval = FAIL;

	struct stat statBuf;

	printf("Get Info (Detailed)\r\n");

	hyperionID = pHeaders->getFileList.fileID;
	if(hyperionID != 0xFFFFFFFF)
	{
		//Get File Name from Hyperion ID
		if(fileName[0] == 0)
		{
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}
	}
	else
	{
		retval = PadToDot(pHeaders->getFileList.fileName, fileName);

		if(retval == FAIL)
		{
			//NAK -- invalid name
			nakType = NAKDISP_DATA;
			proceed = FALSE;
		}
	}

	if(proceed)
	{
		if(stat(fileName, &statBuf) == 0)
		{
			fileSize = statBuf.st_size;
			//Read Only from statBuf.st_mode
			//File Times from statBuf.st_ctime and statBuf.st_mtime
			//CRCs and MD5s either from logged information, set to 0, or calculated on the fly
		}
		else
		{
			nakType = NAKDISP_DATA;
		}
	}

	//Return File information (size, etc.) -- need to expand to Detailed Ack
	if(nakType == 0)
	{
		pyldFileAcks.headers.destination = pHeaders->wrapper.source;
		pyldFileAcks.headers.source = pHeaders->wrapper.destination;
		pyldFileAcks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileAcks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER) + sizeof(ACK_FILE_LIST);
		pyldFileAcks.headers.msgType = 0x05;
		pyldFileAcks.ackInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileAcks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileAcks.toShoreheader.size = sizeof(ACK_FILE_LIST) - CRC16_SIZE;
		pyldFileAcks.toShoreheader.type = 0x31;
		pyldFileAcks.ackFileInfo.common.lastReport = 0xFF;
		pyldFileAcks.ackFileInfo.common.numFiles = 1;
		pyldFileAcks.ackFileInfo.common.offset = 0;
		pyldFileAcks.ackFileInfo.common.storageControllerAddress = pHeaders->getFileList.storageControllerAddress;

		pyldFileAcks.ackFileInfo.records[0].fileAttributes = fileAttributes;		//File Attributes fneed to be filled in
		pyldFileAcks.ackFileInfo.records[0].fileID = hyperionID;	//Hyperion ID needs to be filled in
		pyldFileAcks.ackFileInfo.records[0].fileSize = fileSize;	//File Size needs to be filled in

		DotToPad(pyldFileAcks.ackFileInfo.records[0].fileName, fileName);

		pyldFileAcks.ackFileInfo.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_ACK) + sizeof(COMM_HEADER)+ sizeof(ACK_FILE_LIST) - CRC16_SIZE, OTHER_CRC_START);

		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	else
	{
		pyldFileNaks.headers.destination = pHeaders->wrapper.source;
		pyldFileNaks.headers.source = pHeaders->wrapper.destination;
		pyldFileNaks.headers.msgID = pHeaders->wrapper.msgID;
		pyldFileNaks.headers.length = sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE);
		pyldFileNaks.headers.msgType = 0x04;
		pyldFileNaks.nakInfo.originalCmd = pHeaders->wrapper.msgType;
		pyldFileNaks.nakInfo.nakSummary = 0;
		pyldFileNaks.toShoreheader.packetID = pHeaders->header.packetID;
		pyldFileNaks.toShoreheader.size = 3;
		pyldFileNaks.toShoreheader.type = 0x24;
		pyldFileNaks.nakFile.count = 1;
		pyldFileNaks.nakFile.result = nakType;
		pyldFileNaks.nakFile.crc = CalculateCRC16((uint8_t*) &pyldFileAcks, sizeof(LRI_COMM_WRAPPER) + sizeof(LRI_GENERIC_NAK) + sizeof(COMM_HEADER) + sizeof(NAK_FILE) - CRC16_SIZE, OTHER_CRC_START);
		TxHDLC((uint8_t*)&pyldFileAcks, pyldFileAcks.headers.length);
	}
	return;
}

void PIBToFloatSendNAK(uint16_t command, uint16_t msgSeq, uint16_t destination)
{

	return;
}


void TxHDLC(uint8_t* pTxHDLCBuf, uint16_t activeTxLen)
{
	//Write out HDLC SOF
	//OSuartPutCharWait(FLOAT_PORT, HDLC_SOF, INFINITE);
	char c = HDLC_SOF;

	SerialWrite(&c, 1);

#ifdef SHOW_SENDS_AND_RECEIVES
	char* sendMessageBuffer = (char*) malloc(3*2*activeTxLen+100);
	sprintf(sendMessageBuffer, "Sending %.2X", c);
#endif

	//myDialog->m_SerialPort.Write(&c, 1);

	//myDialog->AddHexDataToWindow(OUTBOUND_WINDOW, (unsigned char*)pTxHDLCBuf, (int)activeTxLen);

	while(activeTxLen > 0)
	{
		switch (*pTxHDLCBuf)
		{
			case HDLC_SOF:
			case HDLC_ESC:
			{
				//Write out 1 char at a time
				//OSuartPutCharWait(FLOAT_PORT, HDLC_ESC, INFINITE);
				c = HDLC_ESC;
				SerialWrite(&c, 1);
				//myDialog->m_SerialPort.Write(&c, 1);
				*pTxHDLCBuf &= HDLC_TX_AND_MASK;
				break;
			}
			default:
			{
				//Write out 1 char at a time
				//OSuartPutCharWait(FLOAT_PORT, *pTxHDLCBuf, INFINITE);
				sprintf(sendMessageBuffer + strlen(sendMessageBuffer), " %.2X", *pTxHDLCBuf);	
				SerialWrite(pTxHDLCBuf, 1);
				//myDialog->m_SerialPort.Write(pTxHDLCBuf, 1);
				pTxHDLCBuf++;
				activeTxLen--;
				break;
			}
		}
	}
#ifdef SHOW_SENDS_AND_RECEIVES
	puts(sendMessageBuffer);
	free(sendMessageBuffer);
#endif
	return;
}





uint16_t RxHDLC(char *pHDLCBuf)
{
	uint16_t msgLength = 3;
	BOOL rxInProgHDLC = FALSE;
	uint16_t lenRxHDLCBuf = 0;
	BOOL escapedHDLC = FALSE;
	uint16_t*	lenHDLCMsg = (uint16_t*)(pHDLCBuf + 1);
	BOOL waitingForPacket = TRUE;
	uint8_t err = 0;
	char c = 0;
	int bytesRead;

#ifdef SHOW_SENDS_AND_RECEIVES
	int totalRead = 0;
#endif

	while(waitingForPacket == TRUE)
	{
		bytesRead = 0;

		while((bytesRead != 1) && (runThreads == TRUE))
		{
			bytesRead = SerialRead(&c, 1);
			//if(bytesRead == 0) Sleep(10);
		}

#ifdef SHOW_SENDS_AND_RECEIVES
		if (bytesRead)
		{
			if (!totalRead)
				printf("Received ");

			printf(" %.2X", c & 0xFF);
			++totalRead;
		}
#endif

		if(runThreads == FALSE)
		{
			waitingForPacket = FALSE;
			rxInProgHDLC = FALSE;
			c = 0;
		}
		//Get one character at a time and process
		//c = (char) OSuartGetCharWait(FLOAT_PORT, INFINITE, &err);
		
		if(rxInProgHDLC == TRUE)
		{
			switch (c)
			{
				case HDLC_ESC:
				{
					escapedHDLC = TRUE;
					break;
				}
				default:
				{
					switch (escapedHDLC)
					{
						case TRUE:
						{
							c |= HDLC_RX_OR_MASK;
							escapedHDLC = FALSE;
							*pHDLCBuf = c;
							pHDLCBuf++;
							lenRxHDLCBuf++;
							break;
						}
						case FALSE:
						{
							*pHDLCBuf = c;
							pHDLCBuf++;
							lenRxHDLCBuf++;
							break;
						}
					}

					break;
				}
			}
			if(lenRxHDLCBuf == 3)
			{
				msgLength = *lenHDLCMsg;
				if(msgLength >556)
				{
					pHDLCBuf = (char*)&(rxFloatData[0]);
					lenRxHDLCBuf = 0;
					rxInProgHDLC = FALSE;
				}
			}
			if(lenRxHDLCBuf >= msgLength + 1) 
			{
				pHDLCBuf = (char*)&(rxFloatData[0]);
				waitingForPacket = FALSE;		
				//msgLength = 3;
				escapedHDLC = FALSE;
				//myDialog->AddHexDataToWindow(INBOUND_WINDOW, (unsigned char*)&rxFloatData[1], (int)msgLength);
			}
		}
		else
		{
			if(c == HDLC_SOF)
			{
				rxInProgHDLC = TRUE;
				*pHDLCBuf = c;
				pHDLCBuf++;
				lenRxHDLCBuf++;
				escapedHDLC = FALSE;
			}
		}
	}

#ifdef SHOW_SENDS_AND_RECEIVES
	if (totalRead)
		printf("\n");
#endif

	return lenRxHDLCBuf;
}






//---------------------------------------------------------------------------------
//
//	Validates A CRC value passed in a communication -- assumes crc is passed at the end of the buffer
//
//---------------------------------------------------------------------------------
uint8_t ValidateCRC16(uint8_t* pBuffer, uint16_t size, uint16_t initValue)
{
	uint8_t retval = FALSE;
	uint16_t crc = initValue;
	uint16_t* pRxCRC = NULL;
	uint16_t i = 0;

	for(i = 0; i < (size - CRC16_SIZE); i++)
	{
		crc = crc16_update(crc, *(pBuffer + i));
	}

	pRxCRC = (uint16_t*)(pBuffer + i);

	if(crc == *pRxCRC)
	{
		retval = SUCCESS;
	}

	return retval;
}


//---------------------------------------------------------------------------------
//
//	Calculates A CRC value for an outbound communication
//
//---------------------------------------------------------------------------------
uint16_t CalculateCRC16(uint8_t* pBuffer, uint16_t size, uint16_t initValue)
{
	uint16_t crc = initValue;
	uint16_t i = 0;

	for(i = 0; i < size; i++)
	{
		crc = crc16_update(crc, *(pBuffer + i));
	}

	return crc;
}


uint16_t crc16_update(uint16_t crc, uint8_t a)
{
	int i;

	crc ^= a;
	for (i = 0; i < 8; ++i)
	{
		if (crc & 1)
			crc = (crc >> 1) ^ 0xA001;
		else
			crc = (crc >> 1);
	}

	return crc;
}




uint8_t	PadToDot(char* pad, char* dot)
{
	uint8_t retval = FAIL;
	int dotpos = -1;
	int i = 0;

	memset(dot, 0, 13);
	memcpy(dot, pad, 8);

	for(i = 7; i>=0; i--)
	{
		if(pad[i] != ' ')
		{
			dotpos = i+1;
			retval = SUCCESS;
			break;
		}
	}

	if(dotpos > 0)
	{
		dot[dotpos] = '.';
		memcpy(&dot[dotpos + 1], &pad[8], 3);
		dot[dotpos + 4] = '\0';
		for(i = (dotpos + 3); i>dotpos; i--)
		{
			if(dot[i] == ' ')
				dot[i] = 0;
		}
	}
	
	return retval;
}

uint8_t	DotToPad(char* pad, char* dot)
{
	uint8_t retval = FAIL;
	int dotpos = -1;
	int len = -1;
	int i = 0;

	memset(pad, ' ', 11);
	len = strlen(dot);
	
	for(i = 0; i<len; i++)
	{
		if(dot[i] == '.')
		{
			dotpos = i;
			break;
		}
	}

	if((len > 0) && (len < 13))
	{
		if(dotpos > 0)
		{
			memcpy(pad, dot, dotpos);
			if(len > dotpos)
				memcpy(&pad[8], &dot[dotpos+1], (len-(dotpos+1)));
		}
		else
		{
			memcpy(pad, dot, len);
		}
		retval = SUCCESS;
	}

	return retval;
}


void send_error_return(char *error_str, int transaction_id)
{
	char	result_filename[256];
	FILE	*result_file;

	sprintf(result_filename, "%08x.txt", transaction_id);
	
	result_file = fopen(result_filename, "w");
	if (result_file == NULL)
	{
		printf("Can't 'fopen(%s)' in 'send_error_return()'\n", result_filename);
		return;
	}
	fprintf(result_file, "%s\n", error_str);
	fclose(result_file);
	PIBFileWatcher(result_filename);

}
