// rdrtest.cpp : Defines the entry point for the application.
//

#define LINUX		1
#define WINDOWS_CE	2
#define WINDOWS		3

#define OS_TYPE		LINUX

#if OS_TYPE == LINUX

#include "casmcard.h"
#include <stdlib.h>  
#include <sys/utsname.h>
#include <string.h>
#include <stdio.h>
#include <memory.h>


#define WCHAR	char
#define swscanf	sprintf
#define wcscmp	strcmp
#define wprintf	printf
#define wcslen strlen
#define Sleep(a)


#elif OS_TYPE == WINDOWS_CE

#include "stdafx.h"
#include <windows.h>
#include <winscard.h>
#include <string.h>
#include <stdio.h>
#include <memory.h>

//#undef UNICODE
//#undef _UNICODE
//#undef _UNICODE_

#else


#endif

#define SLE4442_TYPE	0
#define SLE4428_TYPE	1
#define SLE5536_TYPE	2
#define I2C_TYPE		3

#define MAX_READER_NUMBER	10
#define MAX_RECV_BUFFER_SIZE 4096

SCARDCONTEXT ScardContext;
DWORD	ReaderNameLength;
DWORD	ReadersNum = 0;
LPTSTR  ReaderName;
SCARD_READERSTATE ScardReaderState[MAX_READER_NUMBER];
SCARDHANDLE ScardHandle[MAX_READER_NUMBER];
SCARD_IO_REQUEST ScardIoRequest[MAX_READER_NUMBER];
DWORD  ScardProtocol[MAX_READER_NUMBER];
int CurrentReader;

BYTE SendBuffer[256+5];
DWORD SendLength;
BYTE RecvBuffer[MAX_RECV_BUFFER_SIZE];
DWORD RecvLength;

BYTE GetChallengeCommand[] = {0xCA, 0x86, 0x00, 0x00, 0x08};
BYTE ReadBinaryCommand[] = {0xCA, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00};
BYTE WriteBinaryCommand[] = {0xCA, 0xD0, 0x00, 0x00, 0x00};

int MessageLevel;

#define NO_MESSAGE	0
#define SHOW_LOOP	1
#define SHOW_ACTION	2
#define SHOW_DATA	3

void PrintBuffer(const char* msg, BYTE* buf, DWORD len)
{
	DWORD i;

	printf(msg);
	for(i = 0; i < len; ++i)
	{
		printf("%02X ", buf[i]);
	}
	printf("\n");
}

int ReadBinary(short int readlen)
{
	long result;
	short int t;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("ReadBinary %d byte(s)\n", readlen);
	}

	ScardIoRequest[CurrentReader].dwProtocol = ScardProtocol[CurrentReader];
    ScardIoRequest[CurrentReader].cbPciLength = sizeof(SCARD_IO_REQUEST);	   	
	
	RecvLength = MAX_RECV_BUFFER_SIZE;

	t = (readlen >> 8);

	ReadBinaryCommand[5] = t;
	ReadBinaryCommand[6] = readlen;

	if(MessageLevel >= SHOW_DATA)
	{
		PrintBuffer("	    Send : ", ReadBinaryCommand, sizeof(ReadBinaryCommand));
	}

	result = CasTransmit(ScardHandle[CurrentReader],
							&ScardIoRequest[CurrentReader],
							ReadBinaryCommand,
							sizeof(ReadBinaryCommand),
							&ScardIoRequest[CurrentReader],
							RecvBuffer,
							&RecvLength);

    if(result == SCARD_S_SUCCESS)
	{
		if(RecvLength > 2)
		{
			if(RecvLength != (readlen+2))
			{
				printf("ReadBinary : Read %d bytes but got %d bytes", readlen, RecvLength);
				return 0;
			}
		}

		if(MessageLevel >= SHOW_DATA)
		{
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}
		return 1;
	}
	
	printf("ReadBinary : 0x%08x (%d)\n", result, result);

	return 0;	
}

// flag : 1 - use buf
//		  0 - don't use
int WriteBinary(short int writelen, BYTE* buf, int flag)
{
	long result;
	int i;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("WriteBinary %d byte(s)\n", writelen);
	}

	ScardIoRequest[CurrentReader].dwProtocol = ScardProtocol[CurrentReader];
    ScardIoRequest[CurrentReader].cbPciLength = sizeof(SCARD_IO_REQUEST);	
    	
	RecvLength = MAX_RECV_BUFFER_SIZE;

	memcpy(SendBuffer, WriteBinaryCommand, 4);

	SendBuffer[4] = writelen;

	if(flag)
	{
		memcpy((void*)(SendBuffer + 5), buf, writelen);
	}
	else
	{
		for(i = 0; i < writelen; ++i)
			SendBuffer[5+i] = i;	
	}

	SendLength = 5 + writelen;

	if(MessageLevel >= SHOW_DATA)
	{
		PrintBuffer("	    Send : ", SendBuffer, SendLength);
	}

	result = CasTransmit(ScardHandle[CurrentReader],
							&ScardIoRequest[CurrentReader],
							SendBuffer,
							SendLength,
							&ScardIoRequest[CurrentReader],
							RecvBuffer,
							&RecvLength);

    if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

		return 1;
	}	

	printf("WriteBinary : 0x%08X (%d)\n", result, result);

	return 0;		
}

int GetRandomNumber()
{
	long result;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("GetRandomNumber\n");
	}

	ScardIoRequest[CurrentReader].dwProtocol = ScardProtocol[CurrentReader];
    ScardIoRequest[CurrentReader].cbPciLength = sizeof(SCARD_IO_REQUEST);	
    	
	RecvLength = MAX_RECV_BUFFER_SIZE;

	if(MessageLevel >= SHOW_DATA)
	{
		PrintBuffer("	    Send : ", GetChallengeCommand, sizeof(GetChallengeCommand));
	}

	result = CasTransmit(ScardHandle[CurrentReader],
							&ScardIoRequest[CurrentReader],
							GetChallengeCommand,
							sizeof(GetChallengeCommand),
							&ScardIoRequest[CurrentReader],
							RecvBuffer,
							&RecvLength);

    if(result == SCARD_S_SUCCESS)
	{
		if(MessageLevel >= SHOW_DATA)
		{
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}
		
		return 1;
	}
	
	printf("GetRandomNumber : 0x%08X (%d)\n", result, result);

	return 0;
}

int Connect()
{
	long result;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("Connect\n");
	}

	result = CasConnect(	 ScardContext,
	                     ScardReaderState[CurrentReader].szReader,
	                     SCARD_SHARE_EXCLUSIVE,
	                     SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
	                     &ScardHandle[CurrentReader],
	                     &ScardProtocol[CurrentReader]);
	
	if(result == SCARD_S_SUCCESS)
	{
		if(MessageLevel >= SHOW_ACTION)
		{
			printf("Connect Success\n");
		}
		return 1;
	}
	
	printf("CasConnect Fail : %08X (%d)\n", result, result);
	
	return 0;
}

int Disconnect()
{
	long result;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("Disconnect\n");
	}

	result = CasDisconnect(ScardHandle[CurrentReader],
                                       SCARD_UNPOWER_CARD);
                                       
	if(result == SCARD_S_SUCCESS)
	{
		if(MessageLevel >= SHOW_ACTION)
		{
			printf("Disconnect Success\n");
		}
		return 1;
	}

	printf("CasDisconnect Fail : %08X\n", result);

	return 0;
}


int Init()
{
	long result;
    int i;	
    LPTSTR readerName;


    result = CasEstablishContext(SCARD_SCOPE_SYSTEM,
                                 NULL,
                                 NULL,
                                 &ScardContext);

    if(result != SCARD_S_SUCCESS)
	{
        printf("CasEstablishContext Fail : %08X\n", result);
        return 0;
    }
    
    printf("CasEstablishContext Success\n");

	// Find out ReaderNameLength
    result = CasListReaders(ScardContext, NULL, NULL, &ReaderNameLength);

    if(result != SCARD_S_SUCCESS)
	{
		printf("CasListReadersA Fail : %08X\n", result);
		ReaderNameLength = 100;
        return 0;
    }
    
    printf("CasListReaders Success : %d\n", ReaderNameLength);

    // Allcoate Memory for ReaderName
    ReaderName = (LPTSTR)malloc(ReaderNameLength); //new char[ReaderNameLength];    

    // List Reader Name
    ReadersNum= 0;
    result = CasListReaders(ScardContext,
                              NULL,
                              ReaderName,
                              &ReaderNameLength);

    if(result == SCARD_S_SUCCESS)
	{

       readerName = ReaderName;

       while((*readerName != '\0') && (ReadersNum < MAX_READER_NUMBER))
	   {

          ScardReaderState[ReadersNum].szReader = (LPTSTR)readerName;
          ScardReaderState[ReadersNum].dwCurrentState = SCARD_STATE_UNAWARE;
          ++ReadersNum;
          readerName += strlen(readerName) + 1;
          //readerName += wcslen(readerName) + 1;
       }
    }
	else
	{

	   printf("CasListReadersA Fail : %08X\n", result);

      return 0;
    }

    printf("List  Readers (%d): \n", ReadersNum);
	for(i = 0; i < (int)ReadersNum; ++i)
	{

		wprintf("%d)%s\n", i, ScardReaderState[i].szReader);

	}

	return 1;
}


int Test_Part_1(int loop, int flag, int repeat)
{
	int i;

	printf("Test Part 1 - Power Action\n");
	printf("Start.........................\n");
	for(i = 0; i < loop; ++i)
	{
		if(!Connect())
		{
			printf("Test Part 1 - Power Action Fail - \n");
			printf("	<%d> Connect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		if(!Disconnect())
		{
			printf("Test Part 1 - Power Action Fail - \n");
			printf("	<%d> Disconnect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		if(flag)
		{
			printf("<%d> Part 1 loop = %d\n", repeat, i);
		}
	}
	printf("End.........................\n");
	printf("Test Part 1 -  Success\n");

	return 1;
}

int Test_Part_2(int loop, int flag, int repeat)
{
	int i, j;
	short int const lenarray[] = {1, 5, 128, 241, 242, 243, 249, 254, 255, 262};
	short int writelen;

	printf("Test Part 2 - Power Read Write Action\n");
	printf("Start.........................\n");
	for(i = 0; i < loop; ++i)
	{
		if(!Connect())
		{
			printf("Test Part 2 - Power Read Write Action Fail - \n");
			printf("	<%d> Connect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		for(j = 0; j < 10; ++j)
		{

			writelen = lenarray[j] > 255 ? 255 : lenarray[j];
			if(!WriteBinary(writelen, NULL, 0))
			{
				printf("Test Part 2 - Power Read Write Action Fail - \n");
				printf("	<%d> WriteBinary(%d) Fail : Loop = %d\n", repeat, writelen, loop+1);
				return 0;
			}
			
			if(!ReadBinary(lenarray[j]))
			{
				printf("Test Part 2 - Power Read Write Action Fail - \n");
				printf("	<%d> ReadBinary(%d) Fail : Loop = %d\n", repeat, lenarray[j], loop+1);
				return 0;
			}
		}

		if(!Disconnect())
		{
			printf("Test Part 2 - Power Read Write Action Fail - \n");
			printf("	<%d> Disconnect Fail : Loop = %d\n", repeat, loop+1);
			return 0;
		}

		if(flag)
		{
			printf("<%d> Part 2 loop = %d\n", repeat, i);
		}
	}
	printf("End.........................\n");
	printf("Test Part 2 -  Success\n");

	return 1;
}


int Test_Part_3(int loop, int flag, int repeat)
{
	int i, j;
	short int const lenarray[] = {1, 5, 128, 241, 242, 243, 249, 254, 255, 262};
	short int writelen;

	printf("Test Part 3 - Read Write Action\n");
	printf("Start.........................\n");

	if(!Connect())
	{
		printf("Test Part 3 - Read Write Action Fail - \n");
		printf("	<%d> Connect Fail\n", repeat);
		return 0;
	}

	for(i = 0; i < loop; ++i)
	{
		for(j = 0; j < 10; ++j)
		{
			writelen = lenarray[j] > 255 ? 255 : lenarray[j];
			if(!WriteBinary(writelen, NULL, 0))
			{
				printf("Test Part 3 - Read Write Action Fail - \n");
				printf("	<%d> WriteBinary(%d) Fail : Loop = %d\n", repeat, writelen, loop+1);
				return 0;
			}
			
			if(!ReadBinary(lenarray[j]))
			{
				printf("Test Part 3 - Read Write Action Fail - \n");
				printf("	<%d> ReadBinary(%d) Fail : Loop = %d\n", repeat, lenarray[j], loop+1);
				return 0;
			}
		}

		if(flag)
		{
			printf("<%d> Part 3 loop = %d\n", repeat, i);
		}
	}

	if(!Disconnect())
	{
		printf("Test Part 3 - Read Write Action Fail - \n");
		printf("	<%d> Disconnect Fail\n", repeat);
		return 0;
	}

	printf("End.........................\n");
	printf("Test Part 3 -  Success\n");

	return 1;
}

int Test_SLE4442()
{
	long result;
	
	if(!Connect())
	{
		printf("Test_SLE4442 - Fail - \n");
		printf("	<%d> Connect Fail : Loop = %d\n");
		return 0;
	}

	RecvLength = 256;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("SLE4442 Read Main Memory %d byte(s)\n", RecvLength);
	}
	

	result = SLE4442_Read_Main_Memory(ScardHandle[CurrentReader],
							RecvBuffer,
							0,
							&RecvLength);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

		return 1;
	}
	else
	{
		printf("SLE4442 Read Main Memory : 0x%08x (%d)\n", result, result);
	}

	if(!Disconnect())
	{
		printf("Test_SLE4442 - Fail - \n");
		printf("	<%d> Disconnect Fail\n");
		return 0;
	}

	return 0;	
}

int Test_SLE4428()
{
	long result;
	
	if(!Connect())
	{
		printf("Test_SLE4428 - Fail - \n");
		printf("	<%d> Connect Fail : Loop = %d\n");
		return 0;
	}

	RecvLength = 1024;

	if(MessageLevel >= SHOW_ACTION)
	{
		printf("SLE4428 Read Data Without Protect Bit %d byte(s)\n", RecvLength);
	}
	

	result = SLE4428_Read_Data_Without_Protect_Bit(ScardHandle[CurrentReader],
							RecvBuffer,
							0,
							&RecvLength);

	if(result == SCARD_S_SUCCESS)
	{

		if(MessageLevel >= SHOW_DATA)
		{
			printf(     "       Recv Length = %d byte(s)\n", RecvLength);
			PrintBuffer("	    Recv : ", RecvBuffer, RecvLength);
		}

		return 1;
	}
	else
	{
		printf("SLE4428 Read Data Without Protect Bit : 0x%08x (%d)\n", result, result);
	}
	
	if(!Disconnect())
	{
		printf("Test_SLE4428 - Fail - \n");
		printf("	<%d> Disconnect Fail\n");
		return 0;
	}

	return 0;
}

#if OS_TYPE == LINUX
int
main(int argc, char** argv)
{
	int loop1, loop2, loop3, sleeptime, repeat, i;
	int arg_start;
	int select;  // indicate cpu or memory card
	int memkind;

	select = 0;
	loop1 = 1;
	loop2 = 1;
	loop3 = 1;
	sleeptime = 0;
	repeat = 1;
	MessageLevel = 3;
	memkind = 0;
	
	if(Init())
	{
		if(argc >= 2)
		{
			arg_start = 1; // Skip the name of command

			if(strcmp(argv[arg_start], "-h") == 0)
			{
				arg_start++;

				if(strcmp(argv[arg_start], "-m") == 0)
				{
					arg_start++;
					select = 1;
					printf("Argument : \n");
					printf("           [-h] CurrentReader MemoryCardType MessageLevel\n");
					printf("\n");
					printf("MemoryCardType : 0 - SLE4442\n");
					printf("                 1 - SLE4428\n");
					//printf("                 2 - SLE5536");
					//printf("                 3 - I2C\n");
					printf("MessageLevel : 0 - no message\n");
					printf("               1 - show loop\n");
					printf("               2 - show action\n");
					printf("               3 - show data\n");
					
				}
				else
				{
					printf("Argument : \n");
					printf("           [-h] CurrentReader Test_Part1_Loop Test_Part2_Loop Test_Part3_Loop SleepTime Repeat MessageLevel\n");
					printf("\n");
					printf("SleepTime : thee time to starting next testing, in second\n");
					printf("MessageLevel : 0 - no message\n");
					printf("               1 - show loop\n");
					printf("               2 - show action\n");
					printf("               3 - show data\n");
				}

				if(argc == arg_start)
				{	// just help
					return 0;
				}

			}
			else if(strcmp(argv[arg_start], "-m") == 0)
			{
				arg_start++;
				select = 1;
			}
			

			if(select == 0 && argc == (arg_start + 7))
			{
				sscanf(argv[arg_start++], "%d", &CurrentReader);
				sscanf(argv[arg_start++], "%d", &loop1);
				sscanf(argv[arg_start++], "%d", &loop2);
				sscanf(argv[arg_start++], "%d", &loop3);
				sscanf(argv[arg_start++], "%d", &sleeptime);
				sscanf(argv[arg_start++], "%d", &repeat);
				sscanf(argv[arg_start++], "%d", &MessageLevel);
			}
			else if(select == 1 && argc == (arg_start + 3))
			{
				sscanf(argv[arg_start++], "%d", &CurrentReader);
				sscanf(argv[arg_start++], "%d", &memkind);
				sscanf(argv[arg_start++], "%d", &MessageLevel);
			}
			
		}

		if(select == 0)
		{

			printf("CurrentReader = %d, loop1 = %d, loop2 = %d, loop3 = %d, sleeptime = %d, repeat = %d, MessageLevel = %d\n",
					CurrentReader, loop1, loop2, loop3, sleeptime, repeat, MessageLevel);
		}
		else
		{
			printf("CurrentReader = %d, MemoryCardType = %d, MessageLevel = %d\n", CurrentReader, memkind, MessageLevel);

		}

		if(CurrentReader > (int)ReadersNum)
		{
			printf("Select Out of Range\n");
			return -1;
		}

		printf("%s Selected\n", ScardReaderState[CurrentReader].szReader);

		printf("Start Processing\n");

		if(select == 0)
		{
		
			for(i = 0; i < repeat; ++i)
			{
				if(!Test_Part_1(loop1, MessageLevel, repeat))
					return 0;

				if(!Test_Part_2(loop2, MessageLevel, repeat))
					return 0;

				if(!Test_Part_3(loop3, MessageLevel, repeat))
					return 0;

				Sleep(sleeptime * 1000);
			}
		}
		else if(select == 1)
		{
			if(memkind == SLE4442_TYPE)
			{	// 4442
				Test_SLE4442();
			}
			else if(memkind == SLE4428_TYPE)
			{	// 4428
				Test_SLE4428();
			}
		}

		printf("End Processing\n");
	}

	return 0;
}
#else
int
main(LPTSTR cmdline)
{
	int loop1, loop2, loop3, sleeptime, repeat, i;
	WCHAR temp[40];

	loop1 = loop2 = loop3 = sleeptime = repeat = MessageLevel = 1;



    if(Init())

	{

		swscanf(cmdline, "%s", temp);


		if(wcscmp(temp, "-h") == 0)
		{
			printf("Argument : \n");
			printf("           [-h] CurrentReader Test_Part1_Loop Test_Part2_Loop Test_Part3_Loop SleepTime Repeat MessageLevel\n");
			printf("\n");
			printf("SleepTime : the time to starting next testing, in second\n");
			printf("MessageLevel : 0 - no message\n");
			printf("               1 - show loop\n");
			printf("               2 - show action\n");
			printf("               3 - show data\n");
			wprintf("Get CommandLine : %s\n", cmdline);

			swscanf(cmdline, "%s %d %d %d %d %d %d %d",
					temp, &CurrentReader, &loop1, &loop2, &loop3, &sleeptime, &repeat, &MessageLevel);

		}
		else
		{

			swscanf(cmdline, "%s %d %d %d %d %d %d %d", temp,
					&CurrentReader, &loop1, &loop2, &loop3, &sleeptime, &repeat, &MessageLevel);


		}

		printf("CurrentReader = %d, loop1 = %d, loop2 = %d, loop3 = %d, sleeptime = %d, repeat = %d, MessageLevel = %d\n",
				CurrentReader, loop1, loop2, loop3, sleeptime, repeat, MessageLevel);

		//printf("Select \n ");
		//CurrentReader = 0;


		//printf("Select : ");
		//scanf("%d", &CurrentReader);


		if(CurrentReader > (int)ReadersNum)
		{
			printf("Select Out of Range\n");
			return -1;
		}
		//printf("%d\n", CurrentReader);

		wprintf("%s Selected\n", ScardReaderState[CurrentReader].szReader);

		printf("Start Processing\n");

		for(i = 0; i < repeat; ++i)
		{
			if(!Test_Part_1(loop1, MessageLevel, repeat))
				return 0;

			if(!Test_Part_2(loop2, MessageLevel, repeat))
				return 0;

			if(!Test_Part_3(loop3, MessageLevel, repeat))
				return 0;

			Sleep(sleeptime * 1000);
		}

		printf("End Processing\n");

	}


	return 0;
}

int WINAPI WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR     lpCmdLine,
                     int       nCmdShow)
{
	// Current Reader, Part1_Loop, Part2_Loop, Part3_Loop, sleeptime, repeat, MessageLevel
	main(lpCmdLine);
	return 0;
}
#endif
