
/***************************		SENDSTR.C     ****************************
 * vi:ts=4:sw=4:
 *      Emission d'une trame sur un port COM                                 *
 *		avec affichage en HEX et ASCII de la trame émise					 *
 *		Usage: SENDSTR VoieTx Chaine						                 *
 *		Exemple: Emission du bloc "coucou" sur le port COM3					 *
 *		sendstr com3 coucou							 						 *
 *			VoieTx : Nom du port COM                                         *
 *		    Chaine : chaine de caracteres a emettre							 *
 *  La voie doit etre initialisee auparavant par MCXMODE ou une fonction 	 *
 *  d'initialisation qui appelle PROTO + VINIT + RXENB + MINTR				 *
 *****************************************************************************/
 
 
#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
#include <winioctl.h>
#include "mcc_mcx.h"
#include "ack_w32.h"


unsigned char sendbuf[2048];/* Buffer d'émission					*/
HANDLE hfd;					/* Handle du port COM					*/
ULONG TxLen;				/* Longueur trame emise					*/
char AcksysFile[20];		/* Nom complet du port COM: "\\.\..."	*/
OVERLAPPED WriteOverlap;	/* structure overlap pour le write		*/
char ConsoleTitle[100];		/* la barre de titre de la fenetre		*/

void InitPort();
void InitWrite();
void AsyncWrite(HANDLE, char *, DWORD);
void Dump(unsigned char *, unsigned int);

void 
main(int argc,char **argv)
{
	char hex_flag = 0;
	char *prog = argv[0];
	char *arg_port, *arg_str;

    /* Verification ligne de commande */
	if (argc > 1 && stricmp(argv[1],"-x") == 0) {
		hex_flag = 1;
		argv++;
		argc--;
	}
	if (argc != 3){
		printf ("Invalid command line\n");
		printf ("usage : %s [-x] COMn DataToTransfer\n",prog);
		printf ("Example 1: %s COM3 Hello\n",prog);
		printf ("Example 2: %s -x COM3 48656c6c6F\n",prog);
		exit(255);
	}
	arg_port = argv[1];
	arg_str = argv[2];

	/* affichage barre de titre */
	sprintf(ConsoleTitle,"Tx Transfer: %s  %s ", prog, arg_port);
	if(!SetConsoleTitle(ConsoleTitle)) {
		printf("SetConsoletitle: error %d\n", GetLastError());
	}

    /* ouverture de la voie com en mode OVERLAPPED... */
	hfd = AcksysOpen(arg_port,FILE_FLAG_OVERLAPPED);

	/* Initialisation des timeout de lecture/ecriture */
	InitPort();
	/* Initialisation structure overlapped pour writefile */	
	InitWrite();	
	/* emission */
	if (hex_flag) {
		char *p;
		char hex[3];

		if (strlen(arg_str) & 1) {
			printf("ERROR: length of hex string must be even\n");
			exit(255);
		}
		for (TxLen=0,p=arg_str; *p; TxLen++) {
			hex[0] = *p++;
			hex[1] = *p++;
			hex[2] = '\0';
			if (sscanf(hex, "%x", &sendbuf[TxLen]) != 1) {
				printf("ERROR: bad digits in hex string\n");
				exit(255);
			}
		}
	} else {
		strcpy(sendbuf, arg_str);
		TxLen = strlen(sendbuf);
	}
	AsyncWrite(hfd,sendbuf,TxLen);
	/* affichage de la trame emise */
	Dump(sendbuf,TxLen);
	puts("	Tapez sur la touche Entree");
	while(getchar()!='\n');/* attendre une frappe sur la touche Entree */
	
	FlushFileBuffers(hfd);
	CloseHandle(hfd);
	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
InitWrite()
{
	WriteOverlap.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	if(WriteOverlap.hEvent == NULL)
		printf("Event failed, code %d\n",GetLastError());
}


void
AsyncWrite(HANDLE hfd,char *str, DWORD len)
{
	DWORD count;/* count = number of bytes written */
				/* len = number of bytes to write */


	/*
		if hfd was opened with FILE_FLAG_OVERLAPPED and Overlapped structure is not NULL, 
		WriteFile may return before the write operation has been completed. 
		In this case, WriteFile returns FALSE and the GetLastError function 
		returns ERROR_IO_PENDING. 
	*/
	if( !WriteFile(hfd,str,len,&count,&WriteOverlap) ){
		// write failed
		int lasterror = GetLastError();
		if(lasterror != ERROR_IO_PENDING)
			printf("Write failed, code %d\n",GetLastError());
		else{
			// Operation blocked until write has been completed
			if(!GetOverlappedResult(hfd, &WriteOverlap, &count,TRUE))
				printf("Write GetOver failed, code %d\n",GetLastError());
			ResetEvent(WriteOverlap.hEvent);
			printf ("%d bytes written\n",count);
		}
	}
	// write ok
	else if(len != count)
		printf("Warning: only %d bytes written\n",count);
	else //(len == count)
		printf ("%d bytes written\n",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(Data, 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, "%02x ",(*ptr)&0xff); /* (2'%x' +1espace +0x00) */
        strcat(dmp_buf, x_buf);  
            t_buf[i] = *ptr < ' ' ? '?' : *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);
}      

/*****************************************************************************/
