Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# ¿Cómo controlar el puerto serie usando C# ? Javier Gómez Ingeniero de Telecomunicaciones por la Escuela Tecnica Superior de Bilbao Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# ¿Cómo controlar el puerto serie usando c# ? Prerrequisitos Para poder utilizar el puerto serie, es necesario tener instalada la librería “MSComm.ocx”. Esta librería viene incluida con el VB del Visual Studio 6 y versiones anteriores. Aquellos programadores que tengan instalado Visual Studio 2003 .NET y no tengan las versiones anteriores necesitarán instalar este archivo. En algunas versiones de Windows se puede encontrar en el directorio de instalación de Windows (c:/WINNT/system32/ o c:/WINDOWS/system32/). Para usar esta librería se necesita una licencia para componentes ActiveX de Visual Studio 6. Los pasos para instalar la librería y obtener la licencia usando Visual Studio .NET 2003 son los siguientes: 1. Insertar el disco de instalación de Visual Studio .NET que contiene el directorio \Extras\VB6 Controls en el lector de CD o DVD. La siguiente lista describe que disco es necesario en cada versión: Visual Studio .NET 2002 • All Enterprise Editions – Disco 4 • Professional Edition – Disco 4 • Standard Edition – Disco 3 • Academic Edition – Disco 4 Visual Studio .NET 2003 2. 3. 4. 5. • All Enterprise Editions – Disco 2 • Professional Edition – Disco 2 • Standard Edition – Disco 1 • Academic Edition – Disco 2 Ir a Inicio, y luego hacer clic en Ejecutar.... En el cuadro de diálogo Ejecutar, escribir regedit y hacer clic en Aceptar. En el Editor del registro, hacer click en Importar en el menú Archivo. Localizar la carpeta \Extras\VB6 Controls en tu CD-ROM de instalación de Visual Studio .NET, seleccionar el archivo VB6Controls.reg, y luego hacer Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# clic en Abrir. Esto introduce todas las claves de licencia de los controles ActiveX de Visual Basic 6.0 en el registro. Añadiendo el control MSComm Debes añadir el control a un Windows form para poder utilizarlo. Para ello, Visual Studio .NET facilita la tarea siguiendo estos pasos: 1. Crear un Windows Form. 2. Añadir el control MSComm COM/OCX a tu “Windows Form”. a. Clic con el botón derecho en el Cuadro de herramientas. b. Escoger “Agregar o quitar elementos…” c. Seleccionar y añadir “Microsoft Communication Control”. Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# 3. Dibujar el nuevo control en el Form(Icono de teléfono). Propiedades y eventos principales del control MSComm • CommPort Establece u obtiene el puerto serie del ordenador que se va a utilizar. Por ejemplo, 1 = com1, 2 = com2,… • PortOpen Abre o cierra el puerto. • RThreshold Establece cuantos caracteres deben ser recibidos antes de ejecutar un evento del tipo OnComm. Establecer un 0 si no se quieren tener eventos. Poner un 1 si se quiere que aparezca un evento cada vez que se reciba un carácter por el puerto serie. • InputMode Se le pasa una constante de la clase MSCommLib.InputModeConstants, con ella le indicamos el tipo de datos que se van a recibir o a enviar. Pueden ser cadenas de texto (comInputModeText) o arrays de byte (comInputModeBinary). Por defecto, el modo es de texto, más sencillo para poder trabajar, pero menos versátil que el modo binario. Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# • Settings Se usa para configurar las propiedades del protocolo serie. Así, el formato utilizado es “baudios, paridad, bits de datos, bits de stop”. Por ejemplo: “9600,n,8,1” (9600 baudios, paridad no, 8 bits de datos y un bit de stop). • Handshaking Utilizar las constantes de MSCommLib.HandshakeConstants para definir el tipo de control de transmisión que se desea en la comunicación: none (NoHandshaking): sin control de transmisión. RTS/CTS hardware (RtsCts): utiliza los pines RTS (Ready To Send)/CTS (Clear To Send) para controlar la transmisión. Xon/Xoff software (XonXoff): utiliza los comandos Xon/Xoff. • InBufferCount Devuelve el número de caracteres que están esperando en el buffer de entrada. • Input Devuelve los datos que se encuentren en el buffer de entrada y los elimina de allí. Perrmite comprobar si existen datos en el buffer de entrada. Devuelve una cadena de texto o un array de bytes en función de que el modo de entrada sea texto/binario. • Output Escribe una ráfaga de datos en el buffer de salida.. Por ejemplo com.Output=”Hola” envía “Hola” a traés del puerto serie. • CommEvent Devuelve una constante MSCommLib.CommEventConstants, una constante MSCommLib.ErrorConstants, o una constante MSCommLib. OnCommConstants representado el error o evento más reciente. Interesa comprobarlo en el evento OnComm. • NullDiscard Si su valor es true, el controlador del puerto ignorará todos los caracteres que sean nulos (0x00). • InputLen Indica el número de caracteres que puede leer del buffer cuando se utiliza la propiedad Input. Si el valor es 0, entonces se leen todos los caracteres que se encuentre en el buffer de entrada. • Evento OnComm Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# El único evento al que se le llama cuando sucede algo es el OnComm. Para usarlo, hay que asegurarse de que el RThresold esta a 1. Hay que comprobar que tipo de evento se ha producido. Por ejemplo: public Form() { InitializeComponents(); // Inicializa los componentes del Form com.RThreshold = 1; // Activa el registro de los eventos cuando se reciba algún dato com.OnComm += new System.EventHandler(this.OnComm); /* Asigna el controlador de eventos */ } private void OnComm(object sender, EventArgs e) // MSCommLib OnComm Event Handler { if (com.InBufferCount > 0) ProcessData((string) com.Input); if (com.CommEvent == MSCommLib.OnCommConstants.comEvCTS) Console.WriteLine("Cambio del CTS"); } Codigo de ejemplo // Constructor para el Form con un control AxMSCommLib llamado "comSerial" public SerialTerm() { // Inicializa los componentes del Form InitializeComponent(); // Inicializa el control del Puerto COM InitComPort(); // Envía datos por el Puerto COM comSerial.Output = "Serial Terminal Initialized"; } private void InitComPort() { // Establece com1 como Puerto serie comSerial.CommPort = 1; // Si el puerto está abierto, se cierra para resetearlo. if (comSerial.PortOpen) comSerial.PortOpen = false; // Disparar el evento OnComm cuando se reciban datos comSerial.RThreshold = 1; // Configurar el puerto a 9600 baudios, sin paridad, 8 bits de datos y un bit de stop comSerial.Settings = "9600,n,8,1"; Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# // Forzar el DTR a nivel alto, usado a menudo por los modems comSerial.DTREnable = true; // No se usa control de tráfico comSerial.Handshaking = MSCommLib.HandshakeConstants.comNone; // Trabajar sólo con cadenas de texto comSerial.InputMode = MSCommLib.InputModeConstants.comInputModeText; // Usar esta línea para entradas de arrays de bytes. //comSerial.InputMode = MSCommLib.InputModeConstants.comInputModeText; // Leer todos los datos del buffer de entrada cuando se usa comSerial.Input comSerial.InputLen = 0; // No descartar los bytes nulos, 0x00 es un byte útil comSerial.NullDiscard = false; // Agregar el controlador de eventos comSerial.OnComm += new System.EventHandler(this.OnComm); // Abrir el puerto comSerial comSerial.PortOpen = true; } private void OnComm(object sender, EventArgs e) // Controlador de eventos del puerto serie { // Si hay datos esperando en el buffer, procesarlos. if (comSerial.InBufferCount > 0) ProcessComData((string) comSerial.Input); } private void ProcessComData(string input) { // Enviar los datos recibidos a un Rich Text Box rtfTerminal.AppendText(input + "\n"); } Enviando datos con arrays de bytes Generalmente es más sencillo usar el modo texto, pero esto puede causar resultados imprevisibles cuando se usan algunos caracteres especiales. En este caso debe usar arrays de bytes. Ej: comSerial.Output = new byte[] {0, 0x41, (byte) 'A', 255}; Recibiendo datos como arrays de bytes A veces, los datos que se reciben por el puerto serie no son ni letras ni números. Si estás usando un programa con cuadros de texto y ves caracteres extraños, necesitarás utilizar arrays de bytes. A continuación te explico cómo: Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# 1. Configurar el comSerial.Input para recibir arrays de bytes. comSerial.InputMode = MSCommLib.InputModeConstants.comInputModeBinary; 2. Cuando recibas datos, guárdalos en un array de bytes. private void OnComm(object sender, EventArgs e) // Controlador de eventos { // Recibir datos en un array de bytes, una buena idea para cualquier tipo de datos byte[] indata = (byte[]) comSerial.Input; // Mostrar cada byte en la consola de salida foreach (byte b in indata) Console.WriteLine("Byte Data: " + b); } Recibiendo paquetes de datos La recepción de los datos puede ser complicada si no se envían todos a la vez. Si envías "Hola Mundo" por el puerto serie, es posible que en la recepción aparezca en muchos trozos, como por ejemplo "Ho", "la ", "M", "un", "do". Para evitarlo existen diversas técnicas. A continuación se muestra una de ellas: Usar llaves de start y stop Este es el método más común. Se designan unos prefijos y sufijos como delimitadores del paquete de datos. El receptor los conoce y comprueba la llegada de los mismos en el buffer. Cuando los reconoce, extrae los datos que se encuentrn entre las llaves y borra el buffer. El código siguiente es un buen ejemplo de este método: // Usaremos Regular Expressions para las llaves 'start'/'stop' using System.Text.RegularExpressions; // private string ComBuffer = ""; private void OnComm(object sender, EventArgs e) { // Añadir al buffer los datos de entrada ComBuffer += (string) comSerial.Input; // Controlador de eventos // Ejemplo de contenido de buffer de entrada // string ComBuffer = "trash---Hello World===trash---How Are You?===trash"; // Construir una regular expression para delimitar los datos // starts with '---' and ends with '===' Regex r = new Regex("---.*?==="); // Realizar bucles para encontrar las llaves for (Match m = r.Match(ComBuffer); m.Success; m = m.NextMatch()) { Escuela Tecnica Superior de Ingenieros de Bilbao Artículos y colaboraciones C# // Mostrar el resultado por consola Console.WriteLine(m.Value); // Eliminar los datos del buffer ComBuffer = ComBuffer.Replace(m.Value, ""); } }