Uno de los inconvenientes que nos encontramos al usar la clase SerialPort de NetDuino es que solo nos permitía enviar y recibir bytes por el puerto Serial. Pero eso tampoco es mucho problema ya que en un momento podemos montarnos nuestra propia clase que haga todo lo de la de serie y mucho mas.
Para ello necesitamos crear una nueva clase desde el IDE, esta clase llamada en esta ocasión SerialStream pertenecerá a un namespace distinto (o no, según queramos) llamado com.giltesa.netduino.io
1 2 3 4 5 6 7 8 9 |
using System.IO.Ports; namespace com.giltesa.netduino.io { class SerialStream : SerialPort { } } |
Además podemos observar como después del nombre de la clase aparece el carácter :, y después el nombre de otra clase. Aquí estamos indicando que nuestra clase hereda de la clase SerialPort. De este modo todas las propiedades y métodos de la clase SerialPort estarán disponibles en la clase SerialStream y podremos dejarlos como estén, sobreescribirlos o añadir nuevos métodos como es nuestro caso.
Aclarar también que el nombre de nuestra clase en vez de SerialStream podría haber sido Serial a secas. Pero luego nos reñirían nuestra clase Serial con otra que tiene el IDE y deberíamos o bien no poner el using (import) del espacio de nombres para que no estén las dos a la vez o añadir toda la jerarquía a mano cada vez. Es decir:
1 |
com.giltesa.netduino.io.Serial variable = new com.giltesa.netduino.io.Serial(); |
Como eso es un rollo se le da otro nombre y punto 😉
Con nuestra clase creada nos falta añadir los constructores y los métodos. Recordemos que la clase de la que heredamos, SerialPort, tiene 5 constructores distintos. Entonces podemos crear nuestros 5 constructores que simplemente tienen que llamar al costructor padre correspondiente, o podemos crear uno genérico con los argumentos con un valor por defecto:
1 2 3 4 5 |
public SerialStream( String portName , Int32 baudRate = 9600 , Parity parity = Parity.None , Int32 dataBits = 8 , StopBits stopBits = StopBits.One ) : base(portName , baudRate , parity , dataBits , stopBits) { } |
Como vemos el constructor public SerialStream(...) : base(...){...}, llama a su vez al constructor padre, eso se indica con : base(), y le envía los parámetros en orden y en la cantidad necesaria para que coincida con uno de los cinco constructores deseados.
En nuestro caso siempre llamamos al constructor SerialPort con todos sus parámetros posibles, y al usuario le obligamos a indicar como mínimo el número de puerto, el resto son opcionales y de no indicarlos se envían con un valor indicado por defecto.
Cuando rellenemos los parámetros del constructor lo debemos de hacer en orden, si quisiéramos poner el primero y el ultimo deberíamos de poner todos los que haya en medio o bien indicarle de forma explicita que valor corresponde a cada parámetro:
1 |
SerialStream serial = new SerialStream( "COM1" , 9600 , dataBits: 7 ); |
Ya nos quedaría añadir todos los métodos que queramos para facilitarnos el trabajo, dos de ellos podrían ser print() y println() que harán uso de WriteByte(). Así podremos imprimir Strings directamente.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public void Print( String text ) { byte[] bytes = Encoding.UTF8.GetBytes(text); foreach( byte b in bytes ) WriteByte(b); Flush(); } public void Println( String text ) { Print(text + "\r\n"); } |
Nuestro primer nuevo método pasa el String a un array de bytes y después estos se envían por el puerto Serial uno a uno con WriteByte.
En cuanto al segundo método hace uso de del nuestro primer método pero antes de enviar el texto le concatena un salto de linea.
Por ultimo nos quedaría añadir el resto de métodos de lectura que necesitásemos y comentar todo usando los comentarios de .Net ya que así nos aparecerá un cuadro con ayuda con la información de los métodos. El constructor por ejemplo quedaría así:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/// <summary> /// Constructor por defecto, como mínimo es necesario indicar el puerto, el resto de parámetros son opcionales. /// </summary> /// <param name="portName">Número de puerto Serial como: COM1, COM2, COM3 ó COM4</param> /// <param name="baudRate">Velocidad de transmisión como: 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600 ó 115200</param> /// <param name="parity">Permite verificar si hay errores durante el envió de los datos, la paridad puede ser de: Even, Mark, None, Odd o Space</param> /// <param name="dataBits">Numero de bits a enviar por paquete como: 5, 6, 7 u 8</param> /// <param name="stopBits">Indica cuando la comunicación ha terminado, puede ser de: None, One, OnePointFive o Two</param> public SerialStream( String portName , Int32 baudRate = 9600 , Parity parity = Parity.None , Int32 dataBits = 8 , StopBits stopBits = StopBits.One ) : base(portName , baudRate , parity , dataBits , stopBits) { } |
Y así es como quedarían los comentarios:
Para terminar adjunto la librería que he creado y un ejemplo para sumar números enteros y obtener su resultado:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
/* Author: Alberto Gil Tesa WebSite: http://giltesa.com License: CC BY-NC-SA 3.0 http://goo.gl/CTYnN NameSpace: com.giltesa.netduino.io File: SerialStream.cs Date: 05/06/2013 Enunciado: Clase que hereda de la clase SerialPort y que añade unos métodos para la escritura de Strings y lectura de Strings, Int, float, double y boolean. Info: http://msdn.microsoft.com/en-us/library/ee436109.aspx http://digital.ni.com/public.nsf/allkb/039001258CEF8FB686256E0F005888D1 */ using System; using System.IO.Ports; using System.Text; using System.Threading; using Microsoft.SPOT; namespace com.giltesa.netduino.io { class SerialStream : SerialPort { /// <summary> /// Constructor por defecto, como mínimo es necesario indicar el puerto, el resto de parámetros son opcionales. /// </summary> /// <param name="portName">Número de puerto Serial como: COM1, COM2, COM3 ó COM4</param> /// <param name="baudRate">Velocidad de transmisión como: 300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600 ó 115200</param> /// <param name="parity">Permite verificar si hay errores durante el envió de los datos, la paridad puede ser de: Even, Mark, None, Odd o Space</param> /// <param name="dataBits">Numero de bits a enviar por paquete como: 5, 6, 7 u 8</param> /// <param name="stopBits">Indica cuando la comunicación ha terminado, puede ser de: None, One, OnePointFive o Two</param> public SerialStream( String portName , Int32 baudRate = 9600 , Parity parity = Parity.None , Int32 dataBits = 8 , StopBits stopBits = StopBits.One ) : base(portName , baudRate , parity , dataBits , stopBits) { } /// <summary> /// Escribe la cadena de texto en el puerto Serial. /// </summary> /// <param name="text">String o cualquier otro tipo de dato como texto a imprimir.</param> public void Print( String text ) { byte[] bytes = Encoding.UTF8.GetBytes(text); lock( this ) { foreach( byte b in bytes ) WriteByte(b); } Flush(); } /// <summary> /// Escribe la cadena de texto en el puerto Serial y añade un salto de línea. /// </summary> /// <param name="text">String o cualquier otro tipo de dato como texto a imprimir.</param> public void Println( String text ) { Print(text + "\r\n"); } /// <summary> /// Lee todo el contenido del buffer y lo devuelve como un String. /// </summary> /// <returns></returns> public String ReadString() { byte[] chars = new byte[1]; String result = ""; lock( this ) { while( this.BytesToRead > 0 ) { this.Read(chars , 0 , 1); result += new String(System.Text.Encoding.UTF8.GetChars(chars)); Thread.Sleep(5); } } return result; } /// <summary> /// Lee un numero entero del buffer. /// </summary> /// <returns>Devuelve el numero entero leído o un -1 en caso de error.</returns> public Int32 ReadInteger() { Int32 result = -1; String line = ""; try { line = ReadString(); result = Int32.Parse(line); } catch( Exception ) { Debug.Print("ReadInteger: Formato incompatible => " + line); } return result; } /// <summary> /// Lee un boolean del buffer /// </summary> /// <returns>Devuelve el valor boolean leído o un false en caso de error.</returns> public Boolean ReadBoolean() { Boolean result = false; String line = ""; try { line = ReadString(); result = (line.Equals(1) ? true : false); } catch( Exception ) { Debug.Print("ReadBoolean: Formato incompatible => " + line); } return result; } /// <summary> /// Lee un double del buffer /// </summary> /// <returns>Devuelve un double o un -1.0 en caso de error.</returns> public double ReadDouble() { double result = -1.0; String line = ""; try { line = ReadString(); result = double.Parse(line); } catch( Exception ) { Debug.Print("ReadDouble: Formato incompatible => " + line); } return result; } /// <summary> /// Lee un float del buffer. /// </summary> /// <returns>Devuelve un float o un -1.0 en caso de error.</returns> public float ReadFloat() { return (float)ReadDouble(); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
using System; using com.giltesa.netduino.io; namespace com.giltesa.netduino.ejemplos { public class Program { public static void Main() { SerialStream serial = new SerialStream("COM1"); serial.Open(); int numA , numB; while( true ) { if( serial.BytesToRead > 0 ) { numA = serial.ReadInteger(); Boolean exit = false; while( !exit ) { if( serial.BytesToRead > 0 ) { numB = serial.ReadInteger(); serial.Println("El resultado de " + numA + " + " + numB + " es = " + (numA + numB)); exit = true; } } } } } } } |