#ifndef __ASE_H
#define __ASE_H

#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <limits.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#include <linux/usbdevice_fs.h>
#include <pthread.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <stdio.h>
//#include <linux/spinlock.h>
#include <syslog.h>
#include <usb.h>

#include "LinuxDefines.h"
#include "atr.h"
#include "T1Protocol.h"
#include "MemoryCards.h"


//#define ASE_DEBUG

/*****************************************************************************
* IOCTL
*****************************************************************************/
#define ASE_IOCTL_CLASS               0xF0
#define ASE_IOCTL_XI2C_INS            0xA0
#define ASE_IOCTL_CLOCK_INS           0xB0

// for sending raw reader ioctls
#define ASE_IOCTL_RAW_CLASS           0xFF
#define ASE_IOCTL_RAW_INS             0xA0


/*****************************************************************************
*
*****************************************************************************/
#define LEFT_NIBBLE(c) ((c & 0xF0) >> 4)
#define RIGHT_NIBBLE(c) (c & 0x0F)
#define PRINT_CHAR(c) LEFT_NIBBLE(c), RIGHT_NIBBLE(c)


#define MIN(a, b) (a > b ? b : a)
#define MAX(a, b) (a > b ? a : b)


#define ASE_READER_ETU_DELTA       150

/*****************************************************************************
*
*****************************************************************************/
#define BULK_BUFFER_SIZE        300 

#define EVENT_BUFFER_SIZE       16
#define RESPONSE_BUFFER_SIZE    4096 

#define MAX_SOCKET_NUM          4

#define ASE_DATA_MEMORY_SIZE    64 
#define READER_FIDI_TABLE_SIZE  100

#define BUFFER_SIZE             8192

#define MAX_READER_NUM  16

/*****************************************************************************
*
*****************************************************************************/
struct card_params {
    uchar       protocol;
    uchar       N;
    uchar       CWT[3];
    uchar       BWT[3];
    uchar       A; 
    uchar       B; 
    uchar       freq;
    float       fTod;
};


typedef struct {
    int                 status; /* 0 - absent, 1 - inserted, 2 - powered on */
    int                 ceei;
    ATR                 atr;

    long                cwt; /* max time in microseconds to wait between characters */
    long                bwt; /* max time in microseconds to wait to first character (in T=0, equals to cwt) */

    T1Protocol          T1;

    struct card_params  cardParams;

    uchar               FiDi;

    char                activeProtocol;

    MemCard             memCard;

} card;



typedef struct {
    HANDLE          handle;
    unsigned char   baud;
    unsigned char   bits;
    int             stopbits;
    char            parity;
    long            blocktime;

} ioport;


#define BUS_DEVICE_STRSIZE 32

typedef struct {
    //    int                 handle;

    usb_dev_handle*     handle;
    struct usb_device*  dev;
    char                bus_device[BUS_DEVICE_STRSIZE];

	int					interface;

	/*
	 * Endpoints
	 */
	int					bulk_in;
	int					bulk_out;

    char                response[RESPONSE_BUFFER_SIZE];
    unsigned int        curPos, lastPos;

    char                stopReading;
} usbDevice;



typedef struct {
    usbDevice           io;

    char                dataMemory[ASE_DATA_MEMORY_SIZE];
    
    int                 readerStarted; /* 1 - started, 0 - not yet */

    char                commandCounter;
    
    card                cards[MAX_SOCKET_NUM]; 

    pthread_mutex_t     semaphore;     

} reader;


/*****************************************************************************
*
*****************************************************************************/
/* return codes */
#define ASE_OK                      0
#define ASE_ERROR_DATA_INCOMPLETE     -1
#define ASE_ERROR_IOCTL_RESPONSE      -2
#define ASE_ERROR_IOCTL_EVENT         -3
#define ASE_ERROR_READ              -4
#define ASE_ERROR_WRITE             -5
#define ASE_ERROR_TIMEOUT           -6
#define ASE_ERROR_COMMAND           -7
#define ASE_ERROR_CHECKSUM          -8
#define ASE_ERROR_RESPONSE_INCORRECT  -9
#define ASE_ERROR_OVERHEATING        -10
#define ASE_ERROR_ATR                -11
#define ASE_ERROR_PARITY             -12
#define ASE_ERROR_FIFO_OVERRUN       -13
#define ASE_ERROR_FRAMING            -14
#define ASE_ERROR_EARLY_ANSWER       -15

#define ASE_ERROR_RESEND_COMMAND       -16


#define ASE_READER_PID_ERROR               -110
#define ASE_READER_CNT_ERROR               -111
#define ASE_READER_TRUNC_ERROR             -112
#define ASE_READER_LEN_ERROR               -113
#define ASE_READER_UNKNOWN_CMD_ERROR       -114
#define ASE_READER_TIMEOUT_ERROR           -115
#define ASE_READER_CS_ERROR                -116
#define ASE_READER_INVALID_PARAM_ERROR     -117
#define ASE_READER_CMD_FAILED_ERROR        -118
#define ASE_READER_NO_CARD_ERROR           -119
#define ASE_READER_CARD_NOT_POWERED_ERROR  -120
#define ASE_READER_COMM_ERROR              -121
#define ASE_READER_EXTRA_WAITING_TIME      -122

#define ASE_READER_NOT_CPU_CARD            -123
#define ASE_READER_NO_MATCHING_PARAMS      -124
#define ASE_READER_CARD_REJECTED           -125

#define ASE_READER_INVALID_STATUS_BYTE     -126
#define ASE_READER_RETRY_FAILED            -127


/*****************************************************************************
* externs
*****************************************************************************/
extern int ParseATR  (reader* globalData, char socket, char data[], int len);
extern int GetCurrentMode (ATR* atr);
extern int CapableOfChangingMode (ATR* atr);
extern uchar GetSpecificModeProtocol (ATR* atr);
extern uchar GetFi (ATR* atr);
extern uchar GetDi (ATR* atr);
extern uchar GetN (ATR* atr);
extern uchar GetWI (ATR* atr);
extern long GetMaxFreq (ATR* atr);
extern uchar GetFirstOfferedProtocol (ATR* atr);
extern float GetFToDFactor (int F, int D);
extern float GetDToFFactor (int F, int D);
extern uchar GetT1IFSC (ATR* atr);
extern uchar GetT1CWI (ATR* atr);
extern uchar GetT1BWI (ATR* atr);
extern uchar GetT1EDC (ATR* atr);
extern int   IsT1Available (ATR* atr);
extern uchar GetClassIndicator (ATR* atr);


extern int parseStatus (uchar ackByte);
extern int isEvent (uchar event);
extern int parseEvent  (reader* globalData, char socket, uchar event);

extern int readResponse (reader* globalData, char socket, int num, 
                         char* outBuf, int* outBufLen, unsigned long timeout/*, int startOfResponse*/);

extern int writeToReader (reader* globalData, char* data, int len, int* actual);


extern int checkValidity (int retVal, int len, int actual, char* message);

extern int sendCloseResponseCommand (reader* globalData, char socket, char* cmd, int len, char* outBuf, int* outBufLen, char ignoreEvents);
extern int sendControlCommand (reader* globalData, char socket, char* cmd, int len, char* outBuf, int* outBufLen, char ignoreEvents);


extern int cardCommandInit (reader* globalData, char socket, char needToBePoweredOn);
extern int readerCommandInit (reader* globalData, char needToBeStarted);

extern int ReaderStartup (reader* globalData, char* response, int* len);
extern int ReaderFinish (reader* globalData);
extern int GetStatus (reader* globalData, char* response, int* len);
extern int SetCardParameters (reader* globalData, char socket, struct card_params params);
extern int CardPowerOn (reader* globalData, char socket, uchar cardType, uchar voltage);
extern int CPUCardReset (reader* globalData, char socket);
extern int CardPowerOff (reader* globalData, char socket);
extern int ChangeLedState (reader* globalData, char on);
extern int PPSTransact (reader* globalData, char socket, char* buffer, int len, char* outBuf, int* outBufLen);
extern int CardCommand (reader* globalData, char socket, char command, 
			uchar* buffer, int len, uchar* outBuf, int* outBufLen);

/*
extern int T0CPUCardTransact (reader* globalData, char socket, char* buffer, int len, char* outBuf, int* outBufLen,
                              openResponseProccessor orp, unsigned long arg);
*/

extern int T1CPUCardTransact (reader* globalData, char socket, char* buffer, int len, char* outBuf, int* outBufLen);

extern int MemoryCardTransact (reader* globalData, char socket, 
                               char cmdType, uchar command, ushort address, uchar len,
                               uchar* data, char* outBuf, int* outBufLen);


/* the protocol is not NULL if a PPS is required to switch to it.*/
extern int InitCard (reader* globalData, char socket, char coldReset, char* protocol);

/* outBuf will contain the SW1/SW2 as well */
extern int T0Read  (reader* globalData, char socket, 
                    uchar* inBuf, int inBufLen, uchar* outBuffer, int *outBufLen);
extern int T0Write  (reader* globalData, char socket, 
                     uchar* inBuf, int inBufLen, uchar* outBuffer, int *outBufLen);


extern int T1InitProtocol (reader* globalData, char socket, char setIFSD);
extern int T1Command (reader* globalData, uchar socket, 
                      uchar* inBuf, int inBufLen, uchar* outBuffer, int *outBufLen);

extern int MemoryCardCommand (reader* globalData, uchar socket, 
                              uchar* inBuf, int inBufLen, uchar* outBuffer, int *outBufLen);

extern int SendIOCTL (reader* globalData, uchar socket, 
                      uchar* inBuf, int inBufLen, uchar* outBuffer, int *outBufLen);


bool OpenUSB(reader* allReaders, reader* globalData);

bool CloseUSB(reader* globalData);

int WriteUSB(reader* globalData, int writesize, unsigned char* data);

int ReadUSB(reader* globalData, unsigned long timeout, int len, unsigned char *buf);

void  CleanReadBufferUSB(reader* globalData);

#endif 

