//----------------------------------------------------------------------------------
// <copyright file="PIB_FileTransfer.h" company="LiquidRobotics">
//	Copyright (c) Liquid Robotics Corporation.  All rights reserved.
// </copyright>
//
// <summary>
// 	This is the header file for the module that controls file transfers with the
//  Wave Glider
// </summary>
//
// <owner>Jim Kirklin</owner>
//----------------------------------------------------------------------------------

#ifndef _FLOAT_MANAGER_FILETRANSFER_H_
#define _FLOAT_MANAGER_FILETRANSFER_H_










#ifndef OMIT_FILE_TRANSFER
#define FILE_TRANSFER
#endif

#ifdef FILE_TRANSFER


#define ACK_WITH_READ_FILE		0x1B
#define ACK_WITH_LIST_DETAILED	0x1C
#define ACK_WITH_FILE_AT_DEST	0x1F
#define NAK_DATA_ENUMERATED		0x24
#define ACK_WITH_FILE_LIST		0x31


#define	COMM_MAX_TX_MSG	(300)

typedef struct PIB_COMM_XMIT_WRAPPER
{
	LRI_COMM_WRAPPER		pktInfo;
	LRI_GENERIC_NAK			ack_nak;

}PIB_COMM_XMIT_WRAPPER, *PPIB_COMM_XMIT_WRAPPER;




typedef struct _ACK_READ_FILE_
{
	uint16_t	storageControllerAddress;	// storage controller address from request
	uint32_t	seekOffset;			// offset from start of file
	uint8_t		eofFlag;			// EOF flag (0 = not EOF, 0xFF = EOF)
	uint16_t	numDataBytes;		// number of data bytes to follow
	uint8_t		data[64];			// data bytes (content of file; may be larger, but at least 64)
	uint16_t	crc;				// placeholder for CRC
}ACK_READ_FILE, *PACK_READ_FILE;

typedef struct _ACK_FILE_LIST_COMMON_HEADER_
{
	uint16_t	storageControllerAddress;	// storage controller address from request
	uint16_t	offset;				// number of files reported before this
	uint8_t		lastReport;			// 0 = not last report, 0xFF = last report
	uint16_t	numFiles;			// number of files in this message
}ACK_FILE_LIST_COMMON_HEADER, *PACK_FILE_LIST_COMMON_HEADER;

typedef struct _ACK_FILE_LIST_RECORD_
{
	char		fileName[11];		// padded file name
	uint32_t	fileID;				// ID of file
	uint32_t	fileSize;			// size of file
	uint8_t		fileAttributes;		// attributes of file
}ACK_FILE_LIST_RECORD, *PACK_FILE_LIST_RECORD;

typedef struct _ACK_FILE_LIST_
{
	ACK_FILE_LIST_COMMON_HEADER common;
	ACK_FILE_LIST_RECORD records[1];
	uint16_t	crc;
}ACK_FILE_LIST, *PACK_FILE_LIST;

typedef struct _ACK_FILE_LIST_DETAILED_RECORD_
{
	char		fileName[11];		// padded file name
	uint32_t	fileID;				// ID of file
	uint32_t	fileSize;			// size of file
	DATE_TIME	creationDate;		// creation date from file
	DATE_TIME	modifiedDate;		// modified date from file
	uint8_t		fileAttributes;		// attributes of file
	uint16_t	providedCRC;		// CRC provided at initialization
	MD5			providedMD5;		// MD5 provided at initialization
	uint16_t	calculatedCRC;		// CRC calculated at last check
	MD5			calculatedMD5;		// MD5 calculated at last check
}ACK_FILE_LIST_DETAILED_RECORD, *PACK_FILE_LIST_DETAILED_RECORD;

typedef struct _ACK_FILE_LIST_DETAILED_
{
	ACK_FILE_LIST_COMMON_HEADER common;
	ACK_FILE_LIST_DETAILED_RECORD records[1];
	uint16_t	crc;
}ACK_FILE_LIST_DETAILED, *PACK_FILE_LIST_DETAILED;

typedef struct _ACK_FILE_AT_DEST_
{
	uint16_t	storageControllerAddress;
	uint32_t	fileID;
	uint16_t	crc;
}ACK_FILE_AT_DEST, *PACK_FILE_AT_DEST;

typedef struct _ACK_NEW_FILE_AVAILABLE_
{
	uint16_t	storageControllerAddress;	// storage controller reporting new file
	char		fileName[11];		// padded file name
	uint32_t	fileSize;			// size of file
	DATE_TIME	creationDate;		// creation date from file
	DATE_TIME	modifiedDate;		// modified date from file
	uint8_t		fileAttributes;		// attributes of file
	uint16_t	providedCRC;		// CRC provided at initialization
	MD5			providedMD5;		// MD5 provided at initialization
	uint16_t	calculatedCRC;		// CRC calculated at last check
	MD5			calculatedMD5;		// MD5 calculated at last check
	uint16_t	crc;
}ACK_NEW_FILE_AVAILABLE, *PACK_NEW_FILE_AVAILABLE;

typedef struct _NAK_DISPOSITIONS_
{
	uint16_t	countDispositions;
	uint8_t		disposition[1];
	uint16_t	crc;
}NAK_DISPOSITIONS, *PNAK_DISPOSITIONS;


typedef struct _COMM_MGR_TX_BUFFER_
{
	PIB_COMM_XMIT_WRAPPER	wrapper;
	COMM_HEADER				header;
	union
	{
		ACK_READ_FILE		ackReadFile;
		ACK_FILE_LIST		ackGetFileList;
		ACK_FILE_LIST_COMMON_HEADER ackFileListCommon;
		ACK_FILE_LIST_DETAILED ackGetDetailedFileList;
		ACK_FILE_AT_DEST	ackFileAtDest;
		ACK_NEW_FILE_AVAILABLE ackNewFileAvailable;
		NAK_DISPOSITIONS	nakDispositions;
		uint8_t				testBuffer[275];
		uint8_t				sizer[COMM_MAX_TX_MSG - sizeof(COMM_HEADER) - sizeof(PIB_COMM_XMIT_WRAPPER)];
	};
}COMM_MGR_TX_BUFFER, *PCOMM_MGR_TX_BUFFER;



#ifdef FILE_TRANSFER_LOCAL

// Configures the maximum number of concurrent operations
#ifndef FT_MAX_FILE_OPS
#define FT_MAX_FILE_OPS (3)
#endif

#ifndef FT_MIN_RESPONSE_DATA
#define FT_MIN_RESPONSE_DATA (64)			// minimum number of bytes to permit for read sizing
#endif

#ifndef FT_MAX_BUFFER
#define FT_MAX_BUFFER	(400)				// maximum buffer to be used for read/writes
#endif

#define FILE_ENTRY_LINE_LENGTH					(200)

#define INVALID_FILE_ID							((uint32_t) 0xFFFFFFFF)
#define	IS_VALID_FILE_ID(fid)					((fid) != INVALID_FILE_ID)
#define INVALID_FILE_INDEX						((uint16_t) 0xFFFF)
#define	IS_VALID_FILE_INDEX(idx)				((idx) != INVALID_FILE_INDEX)

#define ACK_READ_DATA_OVERHEAD					(2 + OFFSET_OF(COMM_MGR_TX_BUFFER, ackReadFile.data[0]))
#define	ACK_READ_DATA_BUFFER_AVL				(COMM_MAX_TX_MSG-ACK_READ_DATA_OVERHEAD)
#define	ACK_GET_FILE_LIST_MINSIZE0				(OFFSET_OF(COMM_MGR_TX_BUFFER, ackGetFileList.records[1]) + sizeof(uint16_t))
#define ACK_GET_FILE_LIST_DETAILED_MINSIZE0		(OFFSET_OF(COMM_MGR_TX_BUFFER, ackGetDetailedFileList.records[1]) + sizeof(uint16_t))
									
#define ACK_GET_FILE_MINSIZE(detailed)			((detailed) ? ACK_GET_FILE_LIST_DETAILED_MINSIZE0 : ACK_GET_FILE_LIST_MINSIZE0)

#define ACK_GET_FILE_BASE_SIZE					(ACK_GET_FILE_LIST_MINSIZE0-sizeof(ACK_FILE_LIST_RECORD))
#define	ACK_GET_FILE_MAX_RECORDS(s)				(((s)-ACK_GET_FILE_BASE_SIZE)/sizeof(ACK_FILE_LIST_RECORD))
#define ACK_GET_FILE_DEFAULT_SIZE				(ACK_GET_FILE_BASE_SIZE + ACK_GET_FILE_MAX_RECORDS(COMM_MAX_TX_MSG)*sizeof(ACK_FILE_LIST_RECORD))
#define ACK_GET_FILE_D_BASE_SIZE				(ACK_GET_FILE_LIST_DETAILED_MINSIZE0-sizeof(ACK_FILE_LIST_DETAILED_RECORD))
#define	ACK_GET_FILE_D_MAX_RECORDS(s)			(((s)-ACK_GET_FILE_D_BASE_SIZE)/sizeof(ACK_FILE_LIST_DETAILED_RECORD))
#define ACK_GET_FILE_D_DEFAULT_SIZE				(ACK_GET_FILE_D_BASE_SIZE + ACK_GET_FILE_D_MAX_RECORDS(COMM_MAX_TX_MSG)*sizeof(ACK_FILE_LIST_DETAILED_RECORD))
#define ACK_GET_FILE_DEF_SIZE(detailed) 		((detailed) ? ACK_GET_FILE_D_DEFAULT_SIZE : ACK_GET_FILE_DEFAULT_SIZE)

#define FT_MAX_CLOSE_PENDING_TIME				(30L*60L*SECOND_TO_TICK)

#endif

// Masks for FILE_TRANSFER_ENTRY.attributes
#define FTATTR_READ_ONLY	(1)				// indicates read only file
#define	FTATTR_CHECKED		(0x80)			// indicates file checked

// Enumerates the type or purpose of the file
typedef enum
{
	FT_FILETYPE_DIRECTORY = 1,				// file contains the directory
	FT_FILETYPE_PROGRAMS = 2,				// file contains program selections
	FT_FILETYPE_DATA = 3,					// data file resident on this file system
	FT_FILETYPE_RECEIVING = 4,				// a file being transferred to another controller
	FT_FILETYPE_SENDING = 5,				// a file being transferred to the Host
	FT_FILETYPE_TEMP_DIRECTORY = 6,			// a temporary copy of a file used to return a directory listing
	FT_FILETYPE_PROGRAM_IN_USE = 0x80		// a mask that indicates this is a program selected for use
} FT_FILETYPE;

// Enumerates the actions that can be passed to a task
typedef enum
{
	FT_TASKACTION_START,					// allocate resources for the task
	FT_TASKACTION_STOP,						// deallocate resources for the task
	FT_TASKACTION_RUN_ONCE					// run the task once
} FT_TASKACTION;

// Structure of a file entry
typedef struct _FT_FILE_ENTRY_
{
	BOOL	  inUse;						// true if file entry is in use, false if it has been removed
	char	  reportedFileName[11];			// filename reported remotely
	uint32_t  fileID;						// file Hyperion ID
	uint32_t  fileSize;						// length of the file
	uint8_t   attributes;					// file attributes:
											//  0x01 = read-only (once checked)
											//  0x80 = checked successfully
    DATE_TIME creationDate;					// date/time when file was created
	DATE_TIME modifiedDate;					// date/time when file was modified
	uint16_t  providedCRC;					// CRC provided
	MD5		  providedMD5;					// MD5 signature provided for the file
	uint16_t  computedCRC;					// CRC computed
	MD5       computedMD5;					// MD5 signature computed for the file
	char	  storedFileName[13];			// filename as stored on disk
	uint16_t  storageController;			// the storage controller on which behalf this file is stored
	time_t    copiedTime;					// time when the file started to be copied to Float C&C
	BOOL   	  targetHost;					// true = target is Host, false = target is storage controller
	BOOL	  reportedAtDest;				// true = report of "at destination" already sent, false = no report sent yet
	FT_FILETYPE fileType;					// type of file
}FT_FILE_ENTRY, *PFT_FILE_ENTRY;

// Structure of a program selection
typedef struct _FT_PROGRAM_SELECTION_
{
	uint16_t   boardAddress;				// the board address of the file for which the program is selected
	uint32_t   defaultProgramID;			// file Hyperion ID of the default program
	uint32_t   currentProgramID;			// file Hyperion ID of the current program
}FT_PROGRAM_SELECTION, *PFT_PROGRAM_SELECTION;

// Structure of an operation lock
typedef struct _FT_OPERATION_LOCK_
{
	BOOL		inUse;						// is this entry in use?
	uint16_t	fileIndex;					// file index that is locked
	uint8_t		lockCount;					// count of locks in place
}FT_OPERATION_LOCK, *PFT_OPERATION_LOCK;

typedef enum
{
	FT_TASK_TYPE_WRITE,
	FT_TASK_TYPE_READ,
	FT_TASK_TYPE_GET_DIRECTORY,	
	FT_TASK_TYPE_GET_DETAILED_DIRECTORY,
	FT_TASK_TYPE_SELECT_PROGRAM,
	FT_TASK_TYPE_TRANSFER_FILE
}FT_TASK_TYPE;

typedef enum
{
	FT_TASK_STATE_RX_HOST,					// receiving data from remote host
	FT_TASK_STATE_RX_INTERNAL,				// receiving data from internal board
	FT_TASK_STATE_TX_HOST,					// sending data to remote host
	FT_TASK_STATE_TX_INTERNAL				// sending data to internal board
}FT_TASK_STATE;

typedef enum
{
	FT_SPECIAL_NOT,							// not a special file: it's in the file system
	FT_SPECIAL_PROGMEM,						// program memory of the board
	FT_SPECIAL_EEPROM,						// flash memory of the board
	FT_SPECIAL_RAM							// ram on the board
}FT_SPECIAL;

#define FT_MAX_FILES_TO_TRANSFER (10)

// Structure of a file transfer task
typedef struct _FT_TASK_
{
	FT_SPECIAL	special;					// special file indication
	uint16_t    fileEntryIndex;				// the index of the file entry that is being operated on
	uint16_t	fileEntryIndex2;			// the index of a second file being operated on
	char		storedFileName[13];			// name of the file
	uint32_t	fileID;						// ID of the file being operated on
	FT_TASK_TYPE taskType;					// the type of task
	FT_TASK_STATE taskState;				// the current state of the task
	uint16_t	storageController;			// the storage controller involved
	uint32_t	offset;						// current offset in the data
	uint32_t	endOffset;					// size of request
	uint16_t	respSize;					// size of response to give (max)
	time_t		enteredClosingState;		// time entered closing state
	uint8_t		completionType;				// the completion type to use when sending messages asynchronously
	uint32_t	transactionID;				// transaction ID for requester (original request)
	uint32_t	readFileAckTransID;			// transaction ID requester for this request
	BOOL		closePending;				// true if transmission complete and waiting for close
	uint8_t		(*callbackFunc)(struct _FT_TASK_*,FT_TASKACTION); // a pointer to the callback function for this task
	struct _FT_TASK_* pNext;				// next item to be executed
}FT_TASK, *PFT_TASK;

// Custom Messages for File Transfer Module
#define MSG_FILE_TRANSFER_BASE			(0x8000E000)
#define MSG_FILE_TRANSFER_COMMAND		(MSG_FILE_TRANSFER_BASE+0)
#define MSG_FILE_TRANSFER_SCHEDULE_1	(MSG_FILE_TRANSFER_BASE+1)
#define MSG_FILE_TRANSFER_SCHEDULE_2	(MSG_FILE_TRANSFER_BASE+2)
#define MSG_FILE_TRANSFER_INIT2			(MSG_FILE_TRANSFER_BASE+3)
#define MSG_FILE_TRANSFER_DEBUG			(MSG_FILE_TRANSFER_BASE+4)

// Global Function Prototypes
//uint8_t MgrFileTransferEntry(uint32_t msgID, PVOID pParam1, uint16_t size1, PVOID pParam2, uint16_t size2, PVOID* pReturn,
//				uint16_t* pSizeData) CALLBACK;
uint8_t FT_InitFileWrite(uint32_t storageController, PFT_FILE_ENTRY pRequestInfo, uint8_t overwrite, uint8_t* pFirstBlock,
				uint16_t blockLength);
uint8_t FT_DeleteFile(uint32_t storageController, char* pFileName11, uint32_t fileID, uint8_t overrideReadOnly);
uint8_t FT_SelectProgram(uint16_t boardID, uint32_t programID, BOOL isDefault);
uint8_t FT_StartFileRead(uint32_t storageController, char* pFileName11, uint32_t originalTransactionID, uint32_t offset, uint32_t count, uint16_t maxResponseSize,
				uint32_t transactionID, uint8_t completionType, uint16_t fromAddress);
uint8_t FT_StartGetFileList(uint32_t storageController, char* pFileName11, uint32_t fileID, BOOL checkFiles, BOOL deleteIfFailed,
				BOOL detailedList, uint16_t maxResponseSize, uint8_t completionType, uint32_t transactionID);
uint8_t FT_WriteFileBlock(uint32_t storageController, uint32_t fileID, uint32_t offset, uint8_t* pBlock, uint16_t blockLength);
uint8_t FT_ReadFileTransactionClosed(uint32_t storageController, uint32_t transactionID);
uint8_t FT_GetFileEntry(uint16_t fileIndex, PFT_FILE_ENTRY pFileEntry);
uint8_t FT_SetFileEntry(uint16_t fileIndex, PFT_FILE_ENTRY pFileEntry);
uint8_t FT_ReadTask(PFT_TASK pTask, FT_TASKACTION taskAction);
uint8_t FT_GetListTask(PFT_TASK pTask, FT_TASKACTION taskAction);
uint8_t FT_DebugFunction(uint8_t func);


#endif

#endif
