Conversión entre C y VB6 para MsComm

Jos?anuel
03 de Abril del 2005
Estoy desarrollando un proyecto para la univ, lo estoy haciendo en VB6 en la cual es requerido que me conecte a un equipo de medición (OTDR), este equipo posee un puerto serial y necesito conectarme a él por medio de dicha interfaz DB9. El punto es que el fabricante (Hp/Agilent), me da ciertas rutinas en C? que supuestamente me permiten conectarme al equipo, enviarle comandos y recibir respuestas. Los comandos que les envio, son de un estandar para todos los equipos de medición denominado SCPI (Standards Commands for Programmable Instruments).

Las rutinas que aparecen en el manual del equipo son las siguientes:

(para configurar el puerto serial del PC)

HANDLE InitSerial( int baudrate )
{
static HANDLE hSer = CreateFile(
INTERFACE, // use COM1 / Serial A
GENERIC_READ | GENERIC_WRITE, // open for read & write access
0, NULL,
OPEN_EXISTING, // well, hopefully ... :-)
0, NULL );
if(!hSer)
{
return NULL;
}
// configure the interface ...
DCB dcb;
COMMTIMEOUTS commtimeout;
GetCommTimeouts(hSer, &commtimeout);
commtimeout.ReadIntervalTimeout = 3000;
commtimeout.ReadTotalTimeoutMultiplier = 200;
commtimeout.WriteTotalTimeoutMultiplier = 200;
commtimeout.WriteTotalTimeoutConstant = 3000;
GetCommState(hSer, &dcb);
dcb.DCBlength = sizeof(dcb);
dcb.BaudRate = baudrate;
dcb.ByteSize = 8;
dcb.Parity = 0;
dcb.StopBits = 1;
dcb.fBinary = 1;
dcb.fParity = 0 ;
dcb.fOutX = 0;
dcb.fInX = 0;
dcb.fDtrControl = DTR_CONTROL_DISABLE;
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; // RTS flow control
SetCommState(hSer, &dcb);
SetCommTimeouts(hSer, &commtimeout);
ClearCommBreak(hSer);
PurgeComm(hSer,
PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return hSer;
}

Según lo poco que se de C?, esta parte del código lo que está haciendo es permitirme configurar el puerto serial del Pc, te digo, que el equipo requiere que la configuración sea:

Baut rate: 19200
Hardware handshaking
8 bits de datos
Sin paridad
1 bit de parada

En el código que mostré veo que configura el puerto de esa manera; ahora hay un par de puntos que no entiendo; básicamente que hacen estas lineas?,

GetCommTimeouts(hSer, &commtimeout);
commtimeout.ReadIntervalTimeout = 3000;
commtimeout.ReadTotalTimeoutMultiplier = 200;
commtimeout.WriteTotalTimeoutMultiplier = 200;
commtimeout.WriteTotalTimeoutConstant = 3000;

creo que son unos intervalos de tiempo que espera entre el envío y recepción de bits, estoy en lo correcto? Me podrían explicar mas o menos dicha estructura?

Existe una segunda parte, esta si la he cogido mejor, que me permite enviarle los comandos al puerto, ellas son:

// write query
sprintf (txtbuffer, "n");
numbytes = strlen(txtbuffer);
WriteFile(hSerial, txtbuffer, numbytes, &cnt, 0);
sprintf(txtbuffer,"*IDN?n");
numbytes = strlen(txtbuffer);
WriteFile(hSerial, txtbuffer, numbytes, &cnt, 0);
// read response
ReadFile(hSerial, txtbuffer, MAXNUMBYTES, &cnt, 0);
if(cnt == 0 || strlen(txtbuffer) == 0)
{
printf("SCPI query failed, exiting!n");
CloseHandle(hSerial);
return;
}
// print result (in txtbuffer)
printf("Connected to: %sn", txtbuffer);

A ver si tengo la idea, lo que hacen dichas lineas es permitirme enviar comandos al equipo (Optical Time Domain Reflectometer); básicamente lo que hace es enviarle un retorno de carro, el cual es necesario antes de enviar cualquier comando, luego lo que permite es colocar un string en el bufer, para que luego sea tomado el número de bytes de este string, y junto con él pueda ser enviado, hasta alli creo que voy bien... lo que no entiendo de esas estructuras es:

que es &cnt? que me representaría?, y ese 0? para que sirve?


Otro punto crítico es la recepción de los caracteres en el puerto, la estructura que me muestra la gente de Agilent es la siguiente:

sprintf(txtbuffer,"*IDN?n");
numbytes = strlen(txtbuffer);
WriteFile(hSerial, txtbuffer, numbytes, &cnt, 0);
// read response
ReadFile(hSerial, txtbuffer, MAXNUMBYTES, &cnt, 0);

La estructura anterior me permitiría enviar y leer una respuesta, en cuanto a la lectura de la sentencia para leer la respuesta tengo una duda, en el MAXNUMBYTES, ese valor debo delimitarlo YO como un tope? máximo o ese valor no tiene límites? Es importante mencionarles que una respuesta del instrumento termina con un "<END>"

En instrumento, de igual manera me puede devolver bloques de bits, que según el manual, pueden ser leidos mediante lo siguiente:

// read the trace data ...
sprintf(txtbuffer,"TRACE:DATA?n");
numbytes = strlen(txtbuffer);
WriteFile(hSerial, txtbuffer, numbytes, &cnt, 0);
// now comes the data: e.g. #48000.... which means:
// | 4 digits following to tell the number
// of bytes
// |||| 8000 bytes following, containing
// 4000 trace pts
cnt=0;
while(!cnt) ReadFile(hSerial, header, 1, &cnt, 0); // read "#"
ReadFile(hSerial, header, 1, &cnt, 0); // read number of digits
header[1]=0;
numbytes = atoi(header);
ReadFile(hSerial, header, numbytes, &cnt, 0); // read digits
header[cnt] = 0;
numbytes = atoi(header);
printf("Reading %d points of trace data ...n", numbytes/2);
// 1 point = 16 bit unsigned short
ReadFile(hSerial, tracebuf, numbytes, &cnt, 0); // read trace data
ReadFile(hSerial, header, 15, &cnt, 0); // read rest:
<END>n

De esta estructura no entiendo ABSOLUTAMENTE NADA a partir de la línea cnt=0; alguna ayudita?

Eso es el código que el fabricante me da para operar el equipo desde un Pc, no me da absolutamente mas nada!, dicho código aparece en el siguiente manual: http://cp.literature.agilent.com/litweb/pdf/E4310-91016.pdf

Ahora si voy a lo que me interesa, tengo que traducir dicho código a VB6, y no se si es demasiado simple esto o es que estoy equivocado en algo (que es lo mas probable), pero cuando traduje dicho código, no me ocupo más de 10 lineas... Lo que hice fue lo siguiente:


En un boton de comando (Enviar) coloqué:

MsComm1.PortOpen=True
MsComm1.Settings="19200,8,N,1"
MsComm1.Handshaking = 2 'comRTS //es esté el handshaking por hardware?

tanto el RTholding y el STholding los coloque diferentes de 0 y les varié valores hasta que me canse para ver si era eso.

MsComm1.Output= "n" //el equipo no emite respuesta ante ese comando
MsComm1.Output= "*idn?"

En otro botón de comando (Recibir) escribi.

respuesta = MsComm1.Input
label1.caption=respuesta //antes de recibir la respuesta había colocado algo en el caption del label 1 y luego desaparece al darle recibir, no aparece mas nada

MsComm1.PortOpen=False

Resultado: No llega nada :-(

Se muy bien que efectivamente el puerto es abierto, porque cuando trato de acceder a él por el hyperterminal u otro lado, me dice que el puerto está abierto.

Ahora, les digo que inspecciono el OutBufferCount, y me dice que es 0, como que si nunca enviara nada? y por lo tanto no tengo respuesta. Mis preguntas son:

1. Está bien la conversión de un lenguaje a otro?
2. Los tiempos especificados en: commtimeout.ReadIntervalTimeout = 3000; commtimeout.ReadTotalTimeoutMultiplier = 200; commtimeout.WriteTotalTimeoutMultiplier = 200; commtimeout.WriteTotalTimeoutConstant = 3000; donde los puedo alterar para configurar el control MsComm?
3. Alguna idea de por qué no transmite nada?


y por último, en el manual, especifica que se puede acceder al equipo desde el Hyperterminal, el punto es, como hago para enviarle los comandos? Ya que dice que está conectado y no puedo escribir nada en el workspace, les envio los comandos por el contenido de un archivo de texto y nada. El punto sería, se pueden enviar cadenas de caracteres a un dispositivo, empleando el Hyperterminal?

Les agradecería enormemente su ayuda, y cualquier cosa no duden en preguntarme para darte una idea del contexto mas amplia.

Saludos,
José Manuel