//---------------------------------------------------------------------------
#ifndef USBCommH
#define USBCommH

#include <Classes.hpp>
#include "Com.h"


//#define PACKET_MAX_SIZE			97 * 1024
#define PACKET_DATA_MAX_SIZE	(PACKET_MAX_SIZE - USB_PACKET_HEADER_SIZE * 4)

#define USB_MAX_TRANSFER_SIZE	4 * 1024 * 1024
#define USB_MAX_RECEIVE_SIZE	64 * 1024
//---------------------------------------------------------------------------

#define TRANSFER_INFO_TYPE_RX		    0
#define TRANSFER_INFO_TYPE_TX           1
#define TRANSFER_INFO_TYPE_RESET        2

#define NEW_USB_PROTOCOL_VER			110
#define OLD_USB_PROTOCOL_VER			100

/** @brief Firmware와 협약된 구조 */
typedef struct {
  unsigned int Size;	    ///< 파일 사이즈
  unsigned int Index;	    ///< 원하는 상황의 index
  unsigned int Type;      ///< 0이면 Out transfer(Host->Device), 1이면 In Transfer(Device->Host)
} TTransferInfo;

typedef struct
{
	int ParamCount;
	unsigned int Params[1];
} TOverlapIOStr;


#define USB_PACKET_HEADER_SIZE_OLDVER				5
typedef struct
{
  unsigned short 		header;
  unsigned short 		command;				///< command
  unsigned int		shortLength;			///< length of short data
  unsigned int		longLength;				///< length of long data
  unsigned short 		destination;		///< receiver
  unsigned short 		source;					///< sender
  unsigned short		type;
  unsigned short 		dataID;					///< count of packet
} TUSBDataHeader_OldVer;

#define USB_TRANSFER_MAX_SIZE_OLDVER				504
typedef struct
{
	unsigned int PacketIndex;
	unsigned int Checksum;
  unsigned char Data[USB_TRANSFER_MAX_SIZE_OLDVER];
} TTransferPacket_OldVer;
#define PACKET_MAX_SIZE_OLDVER						(97 * 1024)
//---------------------------------------------------------------------------
typedef void __fastcall (__closure *TUSBCompletionRoutine) (bool result, TOverlapIOStr *OverlapIOStr);
//---------------------------------------------------------------------------
class TCommandUnit
{
private:
public:
	int Status;
	int DFStatus;
	volatile bool Complete;
	bool Result;
	int Type;
	unsigned short Command;
    void *ShortData;
    unsigned int ShortDataLength;
    void *LongData;
    unsigned int LongDataLength;
    void *ReceiveBuffer;
    unsigned int ReceiveBufferMaxSize;
    bool Overlapped;
    int OverlapState;
    int TransferTimeOut;
	TUSBCompletionRoutine CompletionRoutine;
    TOverlapIOStr *OverlapIOStr;
    __fastcall TCommandUnit();
};
//---------------------------------------------------------------------------
class TUSBComm
{
private:
	bool FConnected;
	HANDLE DeviceHandle;
	AnsiString LastErrorMessage;
	AnsiString FDeviceName;

	int FMaxWaitingTime;
	bool FAbort;
	bool AutoRecover;
	unsigned short PacketID;
	bool FIgnoreState;
	bool FVirtualState;
	bool FBusy;
  int ProtocolVer;

	OVERLAPPED  ol;

	void __fastcall ProcessCommand(TCommandUnit *aCommandUnit);

  bool __fastcall SendData(void *data, int dataLength, unsigned int writeStartTime, int timeout);
	bool __fastcall SendCommand(unsigned short command, void *data, unsigned int dataLength,
		unsigned short type, int timeout);
	bool __fastcall SendCommandEx(unsigned short command, void *shortData, unsigned int shortDataLength,
		void *longData, unsigned int longDataLength, unsigned short type, int timeout);
  bool __fastcall ReceiveData(void *data, int dataLength, int *readCount, unsigned int readStartTime, int timeout);
	bool __fastcall ReceiveCommand(void *receiveBuffer, unsigned int receiveBufferMaxSize,
		unsigned int *receivedLength, int timeout);

  void __fastcall ProcessCommand_OldVer(TCommandUnit *aCommandUnit);
  bool __fastcall SendCommand_OldVer(unsigned short command, void *data, unsigned int dataLength,
    unsigned short type, int timeout);
  bool __fastcall SendCommandEx_OldVer(unsigned short command, void *shortData, unsigned int shortDataLength,
    void *longData, unsigned int longDataLength, unsigned short type, int timeout);
  bool __fastcall ReceiveCommand_OldVer(void *receiveBuffer, unsigned int receiveBufferMaxSize,
    unsigned int *receivedLength, int timeout);

public:
	__fastcall TUSBComm();
	__fastcall ~TUSBComm();

  TUSBDataHeader TXDataHeader, RXDataHeader;

	bool __fastcall Connect(AnsiString deviceName);
	bool __fastcall Disconnect(void);
	bool __fastcall RequestCommand(unsigned short command, void *data = NULL, unsigned int dataLength = 0,
		void *receiveBuffer = NULL, unsigned int receiveBufferMaxSize = 0);

	bool __fastcall RequestCommandEx(unsigned short command, void *shortData, unsigned int shortDataLength,
		void *longData, unsigned int longDataLength,
		void *receiveBuffer = NULL, unsigned int receiveBufferMaxSize = 0,
		TUSBCompletionRoutine CompletionRoutine = NULL, TOverlapIOStr *OverlapIOStr = NULL);

	void __fastcall SetDefaultMaxWaitingTime(void);
	AnsiString __fastcall GetLastErrorMessage(void);
	bool __fastcall RecoverDevice();
	bool __fastcall RequestStallTest(int stallEvent);
  void __fastcall ProtocolCheck(void);
	
	__property bool Connected = {read = FConnected};
	__property bool IgnoreState = {read = FIgnoreState, write = FIgnoreState};
	__property bool VirtualState = {read = FVirtualState, write = FVirtualState};
	__property int MaxWaitingTime = {read = FMaxWaitingTime, write = FMaxWaitingTime};
  __property bool Busy = {read = FBusy};
};
//---------------------------------------------------------------------------
#endif
