Comunicaciones Serie en Windows I: bestiario. (2ª parte)

Este punto es sólo para aquellos lectores interesados en la comunicación vía módem. Los lectores inclinados hacia los módem nulos podrán saltar a la siguiente sección sin perjuicio y esperarnos allí: enseguida llegamos. Los demás síganme, por favor.

Vamos a ver a continuación el procedimiento que se sigue en una llamada telefónica. El proceso se esquematiza en la figura 4. Lógicamente, parte de lo que se explicará a continuación no se aplica a los módem nulos ya que no requieren el proceso de marcado, negociación, etc.

Figura 4. Proceso de una comunicación

Dado que no habrá una conexión si el destino de la llamada no está preparado, comenzaremos por el lado del receptor de la llamada (derecha de la figura 4). El programa encargado de la recepción de llamadas ha de configurar el puerto de tal forma que puedan ser detectadas las llamadas entrantes.

Como se ha visto en la sección anterior, el módem receptor activará el circuito RI cuando se produzca este evento. Cuando se programan las comunicaciones bajo Windows tenemos dos alternativas: comprobar periódicamente el indicador de la señal, mediante un bucle o un ‘timer‘, o indicarle al controlador del puerto que le avise cuando se detecte un determinado número de llamadas (sonidos ‘ring’). Cuando se programan las comunicaciones bajo MS-DOS sólo nos queda la primera alternativa, excepto que tengamos un controlador para el puerto capaz de avisarnos de los eventos del mismo o se programe la UART (de la que se hablará más adelante).

En Windows tenemos un programa encargado de realizar determinadas tareas con el puerto serie al que encontraremos a lo largo de toda esta serie: el driver o controlador del puerto. En lo posible, intentaré separar las funciones propias del módem de las que realiza el controlador por su cuenta. Hasta ahora no ha entrado en juego pero a partir de aquí entramos en sus dominios. Ha de entenderse que el driver se sitúa entre nuestro programa y el puerto serie (la UART) y que siempre va a estar ahí. Así que muchas de las funciones que encontramos en Windows para la comunicación se refieren a la comunicación con y desde el driver del puerto en vez de con el puerto mismo. Cuando se supone que realizamos alguna tarea con el puerto, lo que verdaderamente estamos haciendo es encargando o delegando dicha tarea al controlador.

La desventaja de poner el programa en un bucle continuo para leer el estado del puerto es que, lógicamente, nos impide realizar otras tareas. La desventaja de utilizar un timer es obvia y mucho más en Windows: por un lado, el mensaje del timer es uno de los que menos preferencia tiene de todos los mensajes que llegan a la aplicación; por otro lado, el indicador de llamada, RI, se encenderá el tiempo que escuchamos cada ring telefónico y, a continuación, se apagará hasta el próximo ring. Si, en ese momento, nuestro programa está haciendo otra labor no detectará la llamada. Por otro lado, ambas formas duplican la labor del controlador del puerto: ¿para qué comprobar el puerto si podemos ser avisados desde el propio controlador cuando se produzca algún cambio en su estado?

Entonces, nos quedamos con la otra alternativa: configurar el controlador para que avise al detectar una llamada entrante. A su vez, se ha de configurar el módem para que se ponga en estado de autorespuesta.

En la actualidad todos los módem que se encuentran en el mercado tienen una serie de comandos que permiten configurar el módem desde un programa de aplicación. A este juego de comandos se les denomina comandos Hayes o comandos AT (de atención) debido a que todos comienzan por las dos letras ‘AT’. Los comandos Hayes se dividen en dos categorías: los básicos y los extendidos.

Comentaba al comienzo del artículo que algunas funciones de Windows se quedan cortas a la hora de realizar una comunicación efectiva. Mediante el uso de los comandos Hayes podemos manipular las características de los módem a las que no se tiene acceso desde las funciones del API de Windows.

Todos los comandos se envían escribiendo en el puerto el comando en modo de texto, generalmente en mayúsculas, al menos las letras ‘AT’. Asimismo, todos ellos devuelven algún resultado o un error si no está soportado. Los comandos pueden encadenarse, esto es, enviarse varios comandos en una misma operación de escritura. Entre cada comando pueden dejarse espacios o pueden enviarse sin ellos. Por poner un ejemplo (ver más adelante la explicación de los comandos), si se quisiese marcar el número 123456789 desde un teléfono de tonos pasando por una centralita telefónica y poniendo el altavoz del módem a su más bajo nivel, se podría escribir (sin comillas) ‘ATL0DT0W123456789’ o ‘AT L0 DT 0W 123456789’. La finalización de un comando o grupo de ellos requiere el envío de un carácter de retorno de carro (#13). En los ejemplos, se pondrán todas las letras en mayúscula, todos los comandos seguidos y se obviará el carácter de retorno de carro.

Comandos AT básicos
Comando Descripción
AT Atención. Debe preceder a las demás órdenes
A Ponerse en modo autorrespuesta.
D Marca un número telefónico
T Marca el número telefónico mediante tonos.
P Marca el número telefónico mediante pulsos
A/ Vuelve a ejecutar la última orden enviada.
B Selecciona el tipo de modulación del módem.
C Activar o desactivar el transmisor o portadora.
E Habilita (E1) o inhabilita (E0) el eco local.
H Cuelga o descuelga el teléfono.
I Muestra información del módem..
L Controla el volumen del altavoz.
M Controla la habilitación del altavoz del módem.
N Controla la forma de negociación.
O Devuelve al módem a estado descolgado.
Q Controla los códigos de resultado del módem.
S Modifica el valor de uno de los registros del módem.
V Mostrar los códigos de resultado como número o texto.
W Controla lo que devuelve el módem.
X Selecciona los códigos de resultado.
Y Habilita o inhabilita la desconexión mediante espacios
Z Reinicializa a los valores de fábrica
+++ Comando de escape.
Tabla 1. Comandos principales del juego de comandos básicos Hayes

Algunos de los comandos Hayes básicos se muestran en la tabla 1 y se explican a continuación:

AT. Atención. Debe preceder a las demás órdenes

A. Ponerse en modo autorespuesta. Este comando hace que el módem descuelgue y genere un tono de portadora (CD). En el proceso de conexión se suele escribir ATA en el módem receptor al recibir un ring mientras que en el módem originador de la llamada se escribe un ATD sin especificar un número telefónico cuando se detecta la portadora.

D. Marca un número telefónico. Si no sigue un comando T o P se intentará comunicar marcando el número lo que, dicho sea de paso, no es ninguna garantía ya que depende de la configuración que tenga el módem. Si se quiere escribir este comando y se desea que marque por tonos, se debería escribir antes ATT para cambiar a tonos por defecto; si se desea que marque por pulsos por defecto, escribiríamos el comando ATP antes de este. Por ejemplo, ATD123456789.

T. Si se escribe sin un número de teléfono a continuación (ATD), configura el módem para que marque, por defecto, mediante tonos. Si se pone un número de teléfono a continuación, marca el número telefónico mediante tonos. Por ejemplo, ATDT123456789.

P. Si se escribe sin un número de teléfono a continuación (ATT), configura el módem para que marque, por defecto, mediante pulsos. Si se pone un número de teléfono a continuación, marca el número telefónico mediante pulsos. Por ejemplo, ATDP123456789.

Poner una coma sirve para que el módem realice una pausa antes de seguir marcando y suele usarse para marcar un número de teléfono internacional. Por ejemplo, ATDT007,123456789. El tiempo de espera son 2 segundos pero puede modificarse a través del registro S8 del módem.

Poner una W en mitad del comando hace que el módem espere un segundo tono de llamada antes de continuar marcando el número de teléfono y es útil para aquellos módem que están conectados a centralitas telefónicas. Por ejemplo, ATDT0W123456789. . Se consigue el mismo efecto poniendo una coma: ATDT0,123456789. La espera por defecto son 30 segundos pero puede modificarse mediante el valor del registro S7 del módem.

H. Hace que el módem cuelgue (0) o descuelgue (1) el teléfono. Generalmente se envía el comando ATH0 justo antes de cortar la comunicación cerrando el puerto.

I. Sirve para obtener información de las características del módem. Puede tener un valor de 0 (ATI es igual a ATI0) a 7 y muestra distintas características del módem. ATI0 devuelve el código del producto en formato 24X donde X es el nivel de revisión del producto. En algunos módem, devuelve la velocidad en baudios. ATI1 devuelve 3 dígitos con la suma de control o cheksum de la ROM del módem. ATI2 hace que el módem calcule la suma de control del firmware contenido en la ROM y devuelve el resultado con OK o ERROR ATI3 muestra la duración de la llamada. En algunos módem, muestra el código del producto. ATI4 muestra la configuración actual del módem. ATI5 muestra la configuración de la memoria NVRAM. ATI6 muestra diagnósticos de enlace. ATI7 muestra la versión del producto. Este grupo de comandos es el que muestra el módem cuando se le pide ‘más información’ desde el panel de control de Windows.

L. Controla el volumen del altavoz y puede valer 0 (más bajo) a 3 (más alto). Por ejemplo, en las oficinas con mucho tráfico de llamadas y módem externo les agradará que les ponga ATL0.

M. Controla la habilitación del altavoz del módem y puede tener ningún valor o entre 0 y 3. Así, ATM es igual a ATM0 y desconecta el altavoz permanentemente. ATM1 mantiene el altavoz conectado durante la marcación y lo desconecta cuando detecta la portadora. ATM2 mantiene conectado el altavoz permanentemente y, ATM3 conecta el altavoz desde que marca el último dígito hasta que detecta la portadora. Esto es la teoría: en la práctica no todos los módem responden a este comando.

N. Determina la forma de negociación del módem local con el módem remoto cuando sus velocidades son distintas y puede tener un valor entre 0 y 5. Los módem origen y destino mantienen un proceso de negociación al conectarse que puede controlarse mediante este comando.

O. Devuelve al módem a estado en línea, esto es, descolgado. Como antes, esto es la teoría. En la práctica es muy posible que el módem no haga ningún caso.

Q. Controla los códigos de resultado del módem y puede valer ATQ0 para mostrar los códigos, ATQ1 para suprimirlos y ATQ2 para mostrarlos sólo cuando el módem es el origen de la llamada, no cuando es destino de ella.

S. Se utiliza para modificar los valores de los registros S del módem (ver tabla 2). Por ejemplo, para hacer que el módem descuelgue cuando detecte el primer ring se escribe el valor 1 en el registro S0 con el siguiente comando: ATS0=1. Para saber el valor de uno de los registros del módem se escribe una interrogación al final del comando. Por ejemplo, para comprobar si el comando anterior ha dado resultado y ha situado un 1 en el registro S0 se escribiría ATS0?

Registros S del módem
Registro Descripción Rango Defecto
S0 Número de llamadas antes de descolgar 0-255 0
S1 Cuenta del número de llamadas recibidas 0-255 0
S2 Código ASCII del carácter de escape 0-127 43 (+)
S3 Código ASCII del retorno de carro 0-127 13
S4 Código ASCII del avance de línea 0-127 10
S5 Código ASCII del retroceso 0-32,127 8
S6 Tiempo de espera del tono antes de marcar (segundos) 2-255 2
S7 Tiempo de espera de la portadora antes de colgar (segundos) 1-255 50
S8 Tiempo de pausa causado por una coma (segundos) 0-255 2
S9 Tiempo de respuesta de detección de portadora (1/10 de segundo) 1-255 5
S10 Tiempo de espera entre la pérdida de la portadora y el colgado (1/10 de segundo) 1-255 14
S31 Carácter XON 0-255 17
S32 Carácter XOFF 0-255 19
S38 Retardo antes de forzar un colgado (segundos) 0-255 20
S86 Código del motivo del fallo de conexión. 0-19
Tabla 2. Algunos de los registros S del módem y su significado

V. Controla la forma en que se mostrarán los códigos de resultado del módem y puede valer ATV0 para devolverlos como números o ATV1 para texto.

W. No todos los módem lo soportan pero los que lo hacen permiten controlar lo que se devuelve desde el módem. ATW0 devuelve sólo CONNECT y la velocidad de conexión. ATW1 devuelve mensajes del progreso de la negociación y ATW2 sólo devuelve CONNECT. Es más seguro usar el comando X siguiente.

X. Selecciona los códigos de resultado que se desean que el módem devuelva. Estos pueden ser en modo texto o como un código numérico según se halla especificado con el comando V (por defecto son en modo texto). La tabla 3 muestra estos códigos según el comando especificado. Hay que tener en cuenta que no todos los módem aceptan los 8 niveles de códigos pero, en general, llegan hasta el ATX4. Se produce el código 0 (CONNECT) cuando el módem que realiza la llamada detecta la portadora enviada por el módem remoto. En ese momento, se recibe un cero o la palabra CONNECT desde el módem. El código 2 (RING) se recibe, evidentemente, cuando se detecta una llamada. El código 3 (NO CARRIER) se recibe cuando el módem no detecta la portadora. El código 4 (ERROR) yo sólo lo he detectado cuando he enviado un comando que el módem no reconoce. El código 5 (CONNECT 1200) no creo que a estas alturas, con las velocidades de los módem, se pueda recibir nunca. Lo mismo vale para el código 10 (CONNECT 2400). El código 6 (NO DIALTONE) se recibe cuando no hay tono de llamada que es ese ruido tan característico que oímos al levantar el auricular. El código 7 (BUSY) se produce si el módem remoto comunica. El código 8 (NO ANSWER) se produce cuando no hay respuesta del módem remoto. Este último código lo he detectado cuando se ha producido un error en la negociación entre los módem.

Código Texto X0 X1 X2 X3 X4 X5 X6 X7
0 OK X X X X X X X X
1 CONNECT X X X X X X X X
2 RING X X X X X X X X
3 NO CARRIER X X X X X X X X
4 ERROR X X X X X X X X
5 CONNECT 1200 X X X X X X X
6 NO DIALTONE X X X X
7 BUSY X X X X X
8 NO ANSWER X X X X X
10 CONNECT 2400 X X X X X X X
Tabla 3. Resultados devueltos por el módem según el comando Hayes X

Z. Este comando restaura los valores que el módem tenía al salir de fábrica y es conveniente utilizarlo justo antes de configurar el módem a nuestro gusto y un poco antes de la desconexión y cierre del puerto si hemos cambiado su configuración.

+++. Esta secuencia se utiliza para situar el módem en modo comando (esto es, para enviarle un comando AT). Se suele usar para dar por terminada la comunicación: se espera un segundo, se envía +++AT, se espera a que el módem digiera esta información, se le envía el comando de cierre de línea ATH0 y, a continuación, un comando ATZ para restaurar valores. Luego se cierra el puerto. Hay algunos problemas asociados a esta secuencia y se derivan del hecho de que, entre los datos a transmitir se encuentren los caracteres +++. Si es así y el módem se situase en modo comando la comunicación se detendría y, probablemente, se perdería. Debido a eso comentaba antes la necesidad de esperar un segundo sin enviar nada antes de la secuencia de comandos: generalmente, el módem no se detendrá al encontrar entre las tramas que enviamos al puerto esta secuencia, pero sí lo hará si lleva un tiempo sin recibir nada.

Los comandos Hayes extendidos comienzan por el carácter &. Entre ellos se encuentran:

&C. Sirve para controlar la forma en que el módem controla la señal de portadora (CD). AT&C0 mantiene la señal de portadora siempre activa y es el valor por defecto. AT&C1 activa la señal de portadora sólo cuando el módem se encuentra conectado a otro módem y la desactiva al desconectarse.

&D. Selecciona la forma en que el módem controla la señal DTR, terminal preparado. Con AT&D0 el módem ignora la señal DTR. Con AT&D1 cuando se desactiva la señal DTR el módem pasa a modo comando. Con AT&D2 el módem cuelga al desactivarse la señal DTR y se sitúa en modo comando. Por último, con AT&D3 al desactivar DTR el módem cuelga y realiza una reinicialización.

&F. Es similar al ATZ: restaura los valores de fábrica del módem.

&K. Se utiliza para el tipo de control de flujo. AT&K0 deshabilita el control de flujo. AT&K1 habilita el control de flujo hardware RTS/CTS para la salida de datos. AT&K2 habilita el control de flujo software XON/XOFF. AT&K3 habilita el control de flujo hardware DTR/DSR a la entrada. AT&K4 habilita XON/XOFF utilizando los caracteres DC1 (generalmente, ASCII 17) y DC3 (generalmente, ASCII 19). Por último, AT&K5 habilita el control de flujo transparente XON/XOFF. Hay métodos mejores que este para habilitar el control de flujo en Windows que veremos más adelante.

&Z. Este es un comando cuando menos curioso. Si se envía el comando AT&V en el programa de ejemplo, verá que al final de la información aparece ‘TELEPHONE NUMBERS‘ y luego 4 números del 0 al 3 (puede variar de unos módem a otros). Pues bien, el comando &Z almacena en la memoria no volátil del módem un número telefónico. Para usarlo, simplemente se escribe AT&Z0= ó AT&Z1= ó… seguido del número telefónico que se desee. Para eliminar un número de memoria, escriba el mismo comando pero sin número a continuación.

No todos los módem soportan todos los comandos Hayes así que habrá que comprobar en cada caso el juego de comandos que un determinado módem soporta. Por ello, es práctica común en las aplicaciones de comunicaciones el proporcionar al usuario un cuadro de edición para que pueda especificar qué comandos enviar al módem para su configuración correcta.

La aplicación de ejemplo que acompaña a este artículo permite enviar comandos al módem y comprobar sus resultados: un comando soportado devuelve la información y un OK al final; uno no soportado, devolverá, en todo caso, el comando enviado y ERROR al final.

Entonces, para configurar el receptor se haría lo siguiente:

1) El programa abre la línea y, si es necesario, configura los parámetros del puerto.

2) El programa envía una señal DTR, terminal de datos preparado, al módem.

3) Si el módem está en condiciones, debería contestar con una señal DSR, módem preparado.

4) Una vez recibida la señal DSR, el programa envía una señal al módem de petición de envío, RTS.

5) El módem contestará con una señal de preparado para transmitir, CTS.

6) Ahora se ha de indicar al módem que se desea recibir notificación de llamadas entrantes. Las funciones de comunicación serie no tienen ninguna opción para especificar esta característica. Sí existe esta posibilidad usando las funciones TAPI, Telephony Application Programming Interface, pero no es el caso. Así que nos valemos de la escritura directa en el puerto enviándole un comando Hayes al módem. En concreto, hemos de indicarle a la de cuantas llamadas se debe avisar. El módem controla esto a través del registro S0 (ver tabla 2). Un valor de cero aquí hará que el módem (¿o es el controlador del puerto?) ignore las señales de llamada. Un valor superior hará que nos avise de la llamada. Por ejemplo, si queremos que avise a la primera llamada (con llamada, me refiero al sonido de un ring), escribiríamos en el puerto ‘ATS0=1’, sin comillas.

Con esto, el receptor queda configurado para recibir llamadas entrantes. Fíjese que el puerto no se ha cerrado: poner un ordenador como receptor de llamadas bloqueará el módem de ese ordenador tanto para llamadas entrantes, que serán interceptadas por la aplicación, como salientes, las cuales serán rechazadas (excepto que las haga la propia aplicación) por tener bloqueado el puerto.

El programa servidor estará atento a la señal RI, indicador de llamada entrante. Al recibirla, deberá indicar la módem que descuelgue el teléfono y genere la señal de portadora (por sí mismo, el módem no lo hará). Esto se consigue escribiendo en el puerto la cadena ‘ATA’, sin comillas. Luego de la negociación entre módem, si todo ha ido bien, recibirá lo que el emisor decida. Esto es, estará a la espera de la recepción de la señal RD, recepción de datos. Si la negociación con el módem llamador va mal el módem colgará y se mantendrá en atento a futuras llamadas, como antes. Puede suceder esta situación si, por ejemplo, la llamada es de una persona o el módem no recibe respuesta del llamador o no consigue llegar a identificar al módem llamador.

Ahora analizaremos el lado del emisor de la llamada (ver figura 4). Suponemos que el lado receptor ya está configurado para que conteste las llamadas entrantes, esto es, está ‘a la escucha’. Los pasos que se siguen son:

1) El programa abre la línea y, si es necesario, configura los parámetros del puerto.

2) El programa envía una señal DTR, terminal de datos preparado, al módem.

3) Si el módem está en condiciones (encendido, por ejemplo), debería contestar con una señal DSR, módem preparado: algo así como ‘estoy aquí’.

4) Una vez recibida la señal DSR, el programa envía una señal al módem de petición de envío, RTS.

5) El módem contestará con una señal de preparado para transmitir, CTS.

6) El programa envía al módem en ese momento la cadena de conexión: una cadena ASCII que contiene, entre otras cosas, el número de teléfono a marcar (‘ATDT1234567’). Este proceso activará, lógicamente, la señal TD, transmisión de datos, ya que se habrá escrito en el puerto el número de teléfono.

7) El módem comprueba que haya línea al igual que hacemos antes de establecer una conversación telefónica: descolgamos el teléfono esperamos el tono y, a continuación, marcamos el teléfono. Si no detecta el tono, el módem cortará con el error de no hay tono (NO DIALTONE). En cambio, si detecta el tono, envía los mismos códigos que se generan al marcar un número de teléfono manualmente. La llamada pasa a la central telefónica que la encaminará como en cualquier otra conexión telefónica.

8) El módem estará atento a la señal de detección de portadora, CD, que debe llegar desde el módem remoto. Si pasa un tiempo (determinado previamente en la propia configuración del módem mediante el registro S7) sin que se reciba la señal CD, el módem cortará la comunicación por falta de respuesta (NO ANSWER: ha pasado el tiempo, el teléfono sigue sonando, y no responde nadie al otro lado de la línea), falta de portadora (NO CARRIER. Pasa esto, por ejemplo, cuando al otro lado de la línea ha descolgado una persona o un contestador automático) u ocupado (BUSY. Sucede cuando la línea comunica).

Cuando el módem detecta la señal de portadora, realiza la negociación con el módem remoto (veremos qué es esto un poco más adelante. En principio, nos basta saber que la negociación se refleja en esos pitidos que emite el módem al conectarse a Internet) y, finalizada ésta, devolverá un CONNECT o CARRIER y, probablemente, la velocidad a la que ha conseguido establecer la conexión (dependiendo del módem y de su configuración, el resultado de la negociación lo puede devolver en modo texto o numérico y puede incluir más o menos información).

9) Una vez se recibe la señal de detección de portadora, CD, en el programa, éste ya puede enviar y recibir datos. Generalmente, aquí se escribe la cadena ‘ATD’, sin comillas, para indicarle al módem remoto que se está a punto de iniciar el trasvase de datos.

Durante el proceso de negociación de los módem éstos deben fijar unos parámetros que indicarán la forma en que los datos serán transmitidos desde un módem a otro. Esto no afecta al programa de aplicación pero se explica a continuación como referencia.

La velocidad a la que un módem puede modular los bits y demodular la señal analógica se denomina velocidad de modulación y se mide en baudios que es el número de señales por segundo que transmite el módem. La velocidad de transmisión serie es la velocidad a la que el puerto serie puede transmitir los bits hasta el módem y se mide en bits por segundo (bps). La velocidad de modulación, su cadencia, es determinante en una conexión: si el módem receptor lee con una cadencia distinta a la que le envía el emisor puede saltarse bits lo que dará lugar a pérdidas de información y, en último término, al corte de la conexión. Los módem contienen un reloj programable que, durante el proceso de negociación, se ajusta para que ambos módem actúen a la misma frecuencia y se ajustará a la velocidad más alta soportada por ambos módem.

En un módem simple, cada bit recibido se modula y se envía a la línea telefónica. En este caso, la velocidad de transmisión serie coincide con la velocidad en baudios. Pero los módem actuales tienen varios sistemas para comprimir los bits que le llegan del terminal y enviar varios en una sola modulación. La forma en que se realiza este tipo de compresión de la información se denomina técnica de modulación. Lógicamente, si un módem está comprimiendo la información enviará más bits por segundo que otro que no lo haga. El módem receptor debe saber cómo le van a llegar modulados los datos para poder demodularlos correctamente. Durante el proceso de negociación los módem acuerdan la forma en que se intercambiarán los datos, ateniéndose a una serie de normas internacionales (V21, V22, V32, V32,…).

Además, los módem actuales contienen varios métodos para la corrección y detección de errores: cuando se produce un error en la transmisión (¿hay alguien que no ha sufrido interferencias mientras hablaba por teléfono?), el módem receptor le notifica al emisor de la contingencia y éste volverá a enviarle la trama errónea. Para implementar la técnica de corrección de errores los módem deben tener una memoria intermedia donde almacenar las tramas para poder reenviarlas en caso de error. Basándose en el tipo de control de errores, los módem se clasifican en categorías o clases. También es en el proceso de la negociación los módem intercambian información para acordar el tipo de control de errores a llevar a cabo que viene determinado por la clase más baja de los dos módem.