//
// Demonstration de l'utilisation des acces aux boites aux lettres
// des cartes MCC/MCX sous Win32, et de la commande IOCTL_SERIAL_MCX_OPTIONS.
//
// (c)Acksys, 1997 -- JPT
//
#include <windows.h>
#include <winioctl.h>
#include <mcc_mcx.h>

void
main(int argc, char **argv)
{
	HANDLE hDevice;

	hDevice = CreateFile(argv[1],GENERIC_WRITE|GENERIC_READ,
				0,
				NULL,
				OPEN_EXISTING,
				FILE_ATTRIBUTE_NORMAL,
				NULL);
	if(hDevice == INVALID_HANDLE_VALUE){
		printf("CreateFile: error %d\n", GetLastError());
		exit(1);
	}
	DemoOptions(hDevice);
	CloseHandle(hDevice);
}

DemoOptions(HANDLE hDevice)
{
	DWORD retLen;		/* longueur renvoyee dans tous les appels */
	int canal;		/* canal physique, resultat de GET_CHANNEL */
	FILETIME dateFromCard;	/* date BTRAN, resultat de GET_MEMORY */
	
	{ /* activer l'horodatage de la commande BTRAN */

		PMCX_OPTION pOptionDesc;	/* exemple avec malloc */
		int optionLen = MCX_OPTION_SIZE(sizeof(short));

		pOptionDesc = malloc(optionLen);
		pOptionDesc->Option = MCX_OPTION_CMD_TIME;
		pOptionDesc->Value.Short[0] = BTRAN;
		if(!DeviceIoControl(hDevice,IOCTL_SERIAL_MCX_OPTIONS,
				pOptionDesc, optionLen,
				NULL, 0, &retLen, NULL )){
			printf("CMD_TIME: error %d\n", GetLastError());
		}
		free(pOptionDesc);
	}

	/* la ligne suivante engendre un BTRAN */
	WriteFile(hDevice, "ABC", 3, &retLen, NULL);
		/* Il n'y a pas de struct Overlap, donc BTRAN est termine */
		/* quand WriteFile se termine : la date est disponible */

	{ /* obtenir le numero de canal */

		PMCX_OPTION pOptionDesc;	/* exemple avec malloc */
		MCX_OPTION optionResult;	/* exemple sans malloc */

		pOptionDesc = malloc(MCX_OPTION_SIZE(0));
		pOptionDesc->Option = MCX_OPTION_GET_CHANNEL;
		if(!DeviceIoControl(hDevice,IOCTL_SERIAL_MCX_OPTIONS,
				pOptionDesc, MCX_OPTION_SIZE(0), 
				&optionResult, sizeof(optionResult), &retLen,
				NULL )){
			printf("GET_CHANNEL: error %d\n", GetLastError());
		}
		free(pOptionDesc);
		canal = optionResult.Value.Short[0];
	}
	{ /* recuperer la date du BTRAN avec IOCTL_SERIAL_ACCESS_AREA */

		MCX_AREA_DESCRIPTOR areaDesc;

		areaDesc.Operation = MCX_AREA_GET+MCX_AREA_MEMORY;
		areaDesc.StartAddress = MCX_OPTION_CMD_OFFSET + 16*(canal-1);
		areaDesc.Length = sizeof(dateFromCard);
		if(!DeviceIoControl(hDevice,IOCTL_SERIAL_ACCESS_AREA,
				&areaDesc, sizeof(areaDesc), 
				&dateFromCard, sizeof(dateFromCard), &retLen,
				NULL )){
			printf("AREA_GET: error %d\n", GetLastError());
		}
	}
	{ /* Eventuellement, convertir dans le format ad hoc */

		FILETIME localDate;
		SYSTEMTIME formattedDate;

		FileTimeToLocalFileTime(&dateFromCard,&localDate);
			FileTimeToSystemTime(&localDate, &formattedDate);
		printf("From chan#%d: day=%02d/%02d\n",
			canal,formattedDate.wDay,formattedDate.wMonth);
	}
	{ /* test des acces hors limite */

	    static long essais[][3] = {
		/* offset len result */
		{ -2,	-1,	0 },
		{ -2,	0,	0 },
		{ -2,	1,	0 },
		{ -2,	2,	0 },
		{ -2,	3,	0 },
		{ 0x8002, -3,	0 },
		{ 0x8002, -2,	0 },
		{ 0x8002, -1,	0 },
		{ 0x8002, 0,	0 },
		{ 0x8002, 1,	0 },
		{ 0x7fff, 0,	1 },
		{ 0x7fff, 1,	1 },
		{ 0x7fff, 2,	0 },
		{ 0,	-1,	0 },
		{ 0,	0,	1 },
		{ 0,	1,	1 },
		{ 1,	-2,	0 },
		{ 1,	-1,	0 },
		{ 1,	0,	1 },
		{ 1,	1,	1 },
		{ 0,	0x10001,0 },
	    };
	    char buffer[4];
	    MCX_AREA_DESCRIPTOR areaDesc;
	    int i;

	    for(i=0; i<sizeof(essais)/sizeof(essais[0]); i++){
		areaDesc.Operation = MCX_AREA_GET+MCX_AREA_MEMORY;
		areaDesc.StartAddress = essais[i][0];
		areaDesc.Length = essais[i][1];
		if(!DeviceIoControl(hDevice,IOCTL_SERIAL_ACCESS_AREA,
				&areaDesc, sizeof(areaDesc), 
				buffer, sizeof(buffer), &retLen,
				NULL )){
			if(essais[i][2])
			    printf("AREA_GET: error %d\n", GetLastError());
			/* sinon l'erreur est prevue */
		}else{
			if(!essais[i][2]){
			    printf("AREA_GET: ");
			    printf("missing error for interval %d [%d,%d[\n",
			    	i,essais[i][0], essais[i][0]+essais[i][1]);
			}
			/* sinon c'est un intervalle valable, sans erreur */
		}
	    }
	}
}
