/*****************************    RCVDUMP.C    ******************************* 
 *                                                                           *
 * Lecture de trames sur un port COM.                      					 *
 * Affichage de la trame en hexa et en ASCII.								 *
 * En cas d'erreur, des messages sont affichés à l'écran					 *
 *		Usage: RCVDUMP VoieRx nb_octets_max_lu								 *
 *		Exemple: Reception d'une trame de longueur max 1024 octets sur COM3	 *
 *		RCVDUMP com3 1024						 							 *
 *			VoieRx : Nom du port COM                                         *
 *		    nb_octets_max_lu : Nombre d'octets max lu						 *
 * La voie doit etre initialisee auparavant par MCXMODE ou une fonction 	 *
 * d'initialisation qui appelle PROTO + VINIT + RXENB + MINTR				 *

 * Tapez Ctrl C pour sortir de la boucle infinie							 *
 *****************************************************************************/
 
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include "mcc_mcx.h"
#include "ack_w32.h"

unsigned char rcvbuf[2048];	/* Buffer de reception 				*/
HANDLE hfd;					/* Handle du port COM				*/
char AcksysFile[20];		/* Nom complet du port COM : \\.\	*/
OVERLAPPED ReadOverlap;		/* structure overlap pour le read	*/
char ConsoleTitle[100];		/* la barre de titre de la fenetre	*/

void InitRead();
void InitPort();
DWORD AsyncRead(HANDLE,char *, DWORD);
void Dump(unsigned char *, unsigned int);

void 
main(int c,char **v) {
	
	DWORD BytesRead, MaxBytesToRead;


	/* affichage barre de titre */
	sprintf(ConsoleTitle,"Rx Transfer: %s  %s ", v[0], v[1]);
	if(!SetConsoleTitle(ConsoleTitle)) {
		printf("SetConsoletitle: error %d\n", GetLastError());
	}
	
	/* Verification ligne de commande */
	if(c != 3)   {
		printf("Invalid command line\n");
    	printf("Usage: %s COMn MaxBytesToRead\n",v[0]); 
    	printf("Example : %s COM3 1024\n",v[0]);
		exit(255);
    }

	 /* ouverture de la voie com en mode OVERLAPPED... */
	hfd = AcksysOpen(v[1],FILE_FLAG_OVERLAPPED);

	/* Initialisation des timeout de lecture/ecriture */
	InitPort();
	/* Initialisation structure overlapped pour readfile */
	InitRead();
	
	
	MaxBytesToRead= atoi(v[2]);
	while(1) {	/* boucle infinie de lecture */
   
		BytesRead = AsyncRead(hfd,rcvbuf,MaxBytesToRead);
		
		{ DWORD errs; 	ClearCommError(hfd,&errs,NULL);
			if(errs){
				if(errs&CE_OVERRUN)		            // ecrasement de caractere
							printf("OverrunHard, Code %x   ",errs); 
				if(errs&CE_FRAME)		
							printf("FrameError, Code %x   ",errs);
				if(errs&CE_RXOVER)					// longueur max depassee
							printf("OverrunSoft, Code %x   ",errs); 
				if(errs&CE_RXPARITY)	
							printf("CRCErr  Code %x  ",errs);
				if(errs&CE_BREAK)	
							printf("BREAK	");
				if(errs&~(CE_OVERRUN|CE_FRAME|CE_RXOVER|CE_RXPARITY|CE_BREAK))
							printf("ClearCommError Code %x",errs);
				printf("\n");
			}
		}
		if(BytesRead == 0)
			puts(" No data read !");
		else	
			Dump(rcvbuf, BytesRead);
		puts(" ");
		printf("Press Ctrl C to stop %s\n",v[0]);
	}
	exit(0);
}

void
InitPort()
{
	
	COMMTIMEOUTS Timeouts;
	int n1, n2, n3, n4, n5;
	char *timeoutString;

	timeoutString = getenv("TIMEOUTS");
	n1 = n2 = n3 = n4 = n5 = 0;
	if(timeoutString){
		printf("using SET TIMEOUTS=%s (RIT,RTTM,RTTC,WTTM,WTTC)\n",
			timeoutString);
		sscanf(timeoutString, "%d %d %d %d %d",&n1,&n2,&n3,&n4,&n5);
	}
	Timeouts.ReadIntervalTimeout = n1;
	Timeouts.ReadTotalTimeoutMultiplier = n2;
	Timeouts.ReadTotalTimeoutConstant = n3;
	Timeouts.WriteTotalTimeoutMultiplier = n4;
	Timeouts.WriteTotalTimeoutConstant = n5;

	if(!SetCommTimeouts(hfd,&Timeouts)) {
		printf("SetCommTimeouts '%s' failed, code %d\n",
			AcksysFile,GetLastError());
	}
}


void
InitRead()
{
	ReadOverlap.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	if(ReadOverlap.hEvent == NULL)
		printf("Event failed, code %d\n",GetLastError());
}


DWORD
AsyncRead(HANDLE hfd,char *str, DWORD LenToRead)
{
	DWORD count;    /* count = number of bytes read */
					/* LenToRead = number of bytes to read */
	count=12345;

	/*
	If hfd was opened with FILE_FLAG_OVERLAPPED and Overlapped structure is not NULL, 
	ReadFile may return before the read operation has been completed. 
	In this case, ReadFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING.
	*/

	if( !ReadFile(hfd,str,LenToRead,&count,&ReadOverlap) )  
	{ 	// ReadFile failed		
		int lasterror = GetLastError();
		if(lasterror != ERROR_IO_PENDING) 
			printf("Read failed, code %d\n",lasterror);
		else{
			// Operation blocked until read has been completed
			if(!GetOverlappedResult(hfd, &ReadOverlap, &count,TRUE)) 
				printf("GetOverlap failed, code %d\n",GetLastError());
			ResetEvent(ReadOverlap.hEvent);
			printf("%d bytes read\n",count);
		}
		// if ReafFile failed, count  = 0
	}
	else  // ReaFile OK */
		printf("%d bytes read\n",count);
	return count;
}


HANDLE
AcksysOpen(char *numvoie,int flags)
{
	HANDLE hfd;
    	
	sprintf(AcksysFile,"\\\\.\\%s",numvoie);
	if((hfd=CreateFile(AcksysFile,GENERIC_WRITE|GENERIC_READ,
				0,
				NULL,
				OPEN_EXISTING,
				flags,
				NULL)) == INVALID_HANDLE_VALUE){
		printf("Open '%s' failed, code %d\n",AcksysFile,GetLastError());
		exit(1);
	}
	return hfd;
}


/*******************************    DUMP    **********************************
 *                                                                           *
 * 	Affichage d'une trame en 16 caract. Hexa puis en 16 caract. Ascii		 *
 * 																			 *
 *  Usage : Dump(pData, Size)												 *
 *****************************************************************************/

void 
Dump(unsigned char *ptr,unsigned int sz) {
	
	/* dmp_buf : buffer pour 16 caracteres Hexa */	
static char dmp_buf[50];    /* 50 > 16* (2 '%x' + 1 espace) */
int i;
char    t_buf[20];  /* buffer pour 16 caracteres Ascii */
char    x_buf[4];	/* buffer pour 1 caractere Hexa (2'%x' +1espace +0x00)*/
    if(sz <=0)   return;
    dmp_buf[0] = '\0';
    for(i=0; sz--;ptr++, i++) {
        sprintf(x_buf, "%2x ",(*ptr)&0xff);	/* (2'%x' +1espace +0x00) */
        strcat(dmp_buf, x_buf);
        t_buf[i] = *ptr;
        if(i == 15) {
            t_buf[16] = '\0' ;
            printf("%s %s\n", dmp_buf, t_buf);
            dmp_buf[0] = '\0';
            i= -1;
        }
    }
    t_buf[i]='\0';
    printf("%-48.48s %s\n", dmp_buf, t_buf);
}

