diseÑo de aplicaciÓn en c# para gestiÓn de...

130
PROYECTO FIN DE CARRERA INGENIERÍA DE TELECOMUNICACIÓN DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA UNIVERSIDAD DE SEVILLA ESCUELA SUPERIOR DE INGENIEROS DE SEVILLA DEPARTAMENTO DE INGENIERÍA DE SISTEMAS Y AUTOMÁTICA Autor: Guillermo José Núñez Sánchez Tutor: Daniel Rodríguez Ramírez

Upload: hakhuong

Post on 30-Sep-2018

217 views

Category:

Documents


0 download

TRANSCRIPT

PROYECTO FIN DE CARRERA

INGENIERÍA DE TELECOMUNICACIÓN

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES

INALÁMBRICA

UNIVERSIDAD DE SEVILLA

ESCUELA SUPERIOR DE INGENIEROS DE SEVILLA

DEPARTAMENTO DE INGENIERÍA DE SISTEMAS Y AUTOMÁTICA

Autor: Guillermo José Núñez Sánchez

Tutor: Daniel Rodríguez Ramírez

AGRADECIMIENTOS

Quiero manifestar mi más sincero agradecimiento al profesor Don Daniel Rodríguez por haberme dirigido este proyecto de fin de carrera. Por todas las atenciones, por el tiempo que ha perdido conmigo, y sobre todo por su apoyo.

También agradecer de forma muy especial a Jesús María González por prestarme ayuda de manera altruista a la realización de este proyecto.

Agradecerles a mis padres, hermanos y abuelos, tanto a los que están como a los que se fueron y a toda mi familia en general, la gran dedicación y apoyo incondicional en mi educación y en mi por venir. Hoy soy lo que soy gracias a todos vosotros.

A Carmen Gloría, por estar ahí, por ser mi cómplice, por entender de mí lo que otros no entienden y darme aliento cuando a veces me ahogaba.

En general, a todos aquellos profesores y alumnos que a lo largo de la carrera me han ayudado a formarme tanto humanamente como técnicamente, que aunque no les mencione de forma explícita, no les puedo negar un sincero agradecimiento.

No puedo dejar de agradecer a mis amigos por los buenos momentos que me han brindado, por las vivencias que hemos tenido y que nos han hecho crecer juntos y lo seguirán haciendo.

Gracias a todos porque a vuestra manera habéis sido importantes, y porque en todo esto y en mí hay un trozo de cada uno de vosotros.

Guillermo José Núñez Sánchez

15 de mayo de 2014

In me omnis spes mihi est.

TERENCIO,

Phormio, 139.

[Sólo en mí mismo está toda esperanza.]

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

1

I�NDICE GENERAL

1.- Introducción ........................................................................................................................7

1.1.- Enunciado y objetivo del proyecto ...............................................................................7

1.2.- Organización de la memoria .........................................................................................7

2.- Estado del arte ....................................................................................................................9

2.1.- Redes de sensores inalámbricos ...................................................................................9

2.1.1.- Definición ..............................................................................................................9

2.1.2.- Descripción Hardware de un nodo sensor. .......................................................... 11

2.1.3.- Topología y jerarquía ........................................................................................... 15

2.1.4.- Problemas característicos .................................................................................... 17

2.2.- Estándares de comunicación ...................................................................................... 19

2.2.1.- Bluetooth y Wi-Fi ................................................................................................. 20

2.2.2.- Estándar IEEE 802.15.4......................................................................................... 21

2.2.3.- ZigBee .................................................................................................................. 23

2.2.4.- Wireless HART ..................................................................................................... 25

2.2.5.- DUST Networks .................................................................................................... 26

2.3.- Nuevas tendencias ..................................................................................................... 27

2.3.1.- Procesado ubicuo ................................................................................................ 27

2.3.2.- Web de sensores ................................................................................................. 27

2.4.- Representación de datos adquiridos mediantes la red de sensores ........................... 28

3.- Componentes y escenario de la solución adoptada........................................................... 30

3.1.- Elección de dispositivos para la implementación de la WSN ...................................... 30

3.1.1.- Descripción del Waspmote .................................................................................. 30

3.1.2.- Descripción del Transceptor ................................................................................ 37

3.1.3.- Topología de la Red ............................................................................................. 41

3.2.- Elección de herramientas y requisitos para el desarrollo de una aplicación para

Windows de adquisición y gestión de datos ....................................................................... 43

4.- Implementación de Red Sensores Inalámbrica mediante Waspmote ............................... 46

4.1. – Solución Adoptada .................................................................................................... 46

4.1.1.- Tipos de tramas de comunicación........................................................................ 46

4.1.2.- Diagrama de estados de los nodos Waspmote ................................................... 52

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

2

4.1.3.- Código utilizado en los Waspmote....................................................................... 53

5.- DESCRIPCIÓN FUNCIONAL Y DE IMPLEMENTACIÓN DEL SOFTWARE ................................. 58

5.1.- Organización del software en C# ................................................................................ 58

5.1.1.- Diagrama de flujo ................................................................................................ 58

5.1.2.- Diagrama de clases .............................................................................................. 60

5.1.3.- Instalador de la App............................................................................................. 62

6.- CONCLUSIONES ................................................................................................................. 73

7.-Bibliografía ......................................................................................................................... 75

APÉNDICE A: AYUDA APLICACIÓN “Utilidad gestión motas” ................................................. 77

APÉNDICE B: DIAGRAMAS DE CLASES..................................................................................... 85

APÉNDICE C: CÓDIGO DE LA APLICACIÓN EN C# ..................................................................... 86

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

3

LISTA DE FIGURAS

Figura 1: Visualización de una red de adquisición de datos y una red de distribución de datos.

.................................................................................................................................................9

Figura 2: hardware básico de un nodo sensor. ....................................................................... 11

Figura 3: tipos de sensores que pueden presentarse en un nodo. .......................................... 12

Figura 4: Sensores de tamaño reducido. ................................................................................ 12

Figura 5: Nodo sensor de la empresa CROSBOW. ................................................................... 13

Figura 6: Dispositivo sensor de la empresa Motei IV. ............................................................. 13

Figura 7: Nodo sensor de la empresa BTnode ........................................................................ 13

Figura 8: Nodo sensor de la Arduino. ..................................................................................... 14

Figura 9: Nodo sensor de la empresa LIBELIUM. .................................................................... 14

Figura 10: Topología en estrella. ............................................................................................ 15

Figura 11: Topología en anillo. ............................................................................................... 15

Figura 12: Topología en árbol. ................................................................................................ 16

Figura 13: Topología en malla. ............................................................................................... 16

Figura 14: Tipos de jerarquías de una red............................................................................... 17

Figura 15: Algunos ejemplos de baterías. ............................................................................... 18

Figura 16: Torre de protocolo 802.15.4. ................................................................................ 23

Figura 17: Torre de protocolo ZigBee..................................................................................... 24

Figura 18: Red ZigBee en estrella............................................................................................ 24

Figura 19: Red ZigBee en malla............................................................................................... 25

Figura 20: Torre de protocolo de Wireless HART. ................................................................... 26

Figura 21: Nodos sensores Waspmote de la empresa LIBELIUM. ........................................... 30

Figura 22: Componentes principales en Waspmote - Cara superior. ...................................... 31

Figura 23: Componentes principales en Waspmote - Cara inferior......................................... 32

Figura 24: Jumpers de configuración en Waspmote. .............................................................. 32

Figura 25: Modo funcionamiento sleep. ................................................................................. 34

Figura 26: Modo funcionamiento deep sleep ......................................................................... 34

Figura 27: Modo funcionamiento hibernate........................................................................... 34

Figura 28: Partes del IDE - Waspmote. ................................................................................... 35

Figura 29: Panel de botones del IDE - Waspmote. .................................................................. 36

Figura 30: Panel de botones del IDE - Waspmote. .................................................................. 37

Figura 31: Panel de configuración del X-CTU. ......................................................................... 38

Figura 32: Comprobación de firmware del módulo XBee. ...................................................... 39

Figura 33: topología en estrella Coordinator-Router. ............................................................. 42

Figura 34: Módulo XBee montado en un Waspmote Gateway y conectado a un PC. ............. 42

Figura 35: Waspmotes como router enviando información al Gateway conectado a un PC. .. 43

Figura 36: Formato Trama de tranceptores de Digi. ............................................................... 47

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

4

Figura 37: Diagrama de estado de un nodo Waspmote. ......................................................... 52

Figura 38: Diagrama de Estados General ................................................................................ 59

Figura 39: Diagrama de clases de la App. ............................................................................... 61

Figura 40: Pantalla Visual Studio. ........................................................................................... 62

Figura 41: Menú Agregar proyecto Visual Studio. .................................................................. 62

Figura 42: Menú de archivos solución Setup. ......................................................................... 63

Figura 43: Propiedades de archivos solución Setup. ............................................................... 64

Figura 44: Menú para agregar el resultado del proyecto. ....................................................... 64

Figura 45: Menú de la carpeta de escritorio. .......................................................................... 65

Figura 46: Menú para seleccionar elemento en el proyecto. .................................................. 65

Figura 47: Menú de la carpeta menú de programas. .............................................................. 66

Figura 48: Menú para seleccionar elemento en el proyecto. .................................................. 67

Figura 49: Páginas de propiedades de Setup_UGM. ............................................................... 67

Figura 50: Requisitos previos del proyecto Setup_UGM......................................................... 68

Figura 51: Instalador de la aplicación Utilidad Gestión Motas................................................ 69

Figura 52: Directorio donde se alojará la aplicación. .............................................................. 69

Figura 53: Confirmación de la instalación. .............................................................................. 70

Figura 54: Instalando Utilidad de gestión de motas. .............................................................. 70

Figura 55: Instalación completada.......................................................................................... 71

Figura 56: Icono de la aplicación Utilidad Gestión Motas. ...................................................... 71

Figura 57: Interfaz gráfica de la aplicación Utilidad Gestión Motas. ....................................... 77

Figura 58: Elección de eventos de captura. ............................................................................ 78

Figura 59: Configuración de puerto serie................................................................................ 78

Figura 60: Activación de la aplicación para comenzar la captura............................................ 79

Figura 61: Captura de información de la red de sensores inalámbrica. .................................. 79

Figura 62: Campos de la trama de datos de la red de sensores. ............................................. 80

Figura 63: Gráficas de representación de temperatura y nivel de batería. ............................. 80

Figura 64: Aviso de warning. .................................................................................................. 81

Figura 65: Información del warning. ....................................................................................... 81

Figura 66: Generación de un fichero log. ................................................................................ 82

Figura 67: Confirmación para generar un fichero log. ............................................................ 82

Figura 68: Fichero Excel con todas las tramas recogidas......................................................... 83

Figura 69: Limpieza de la información en la interfaz gráfica de la aplicación.......................... 83

Figura 70: Opción de ayuda de la aplicación........................................................................... 84

Figura 71: Aplicación consola. ................................................................................................ 84

Figura 72: Diagrama de clases de la App ................................................................................ 85

.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

5

LISTA DE TABLAS

Tabla 1: Consumo del waspmote en diferentes estados de funcionamiento. ........................ 35

Tabla 2: Módulos XBee de Digi que son compatibles con waspmote. .................................... 37

Tabla 3: Módulos XBee de Digi que se va a usar en el proyecto. ............................................ 37

Tabla 4: Configuración del módulos XBee coordinator ........................................................... 40

Tabla 5: Configuración del módulos XBee router. .................................................................. 41

Tabla 6: Valores y nombres de las API Frame. ........................................................................ 47

Tabla 7: Trama AT Command. ................................................................................................ 48

Tabla 8: Trama AT Command Response. ................................................................................ 49

Tabla 9: Trama Zigbee Transmit Request. .............................................................................. 50

Tabla 10: Formato Trama de Datos. ....................................................................................... 50

Tabla 11: Formato Trama de Indicación Batería Baja. ............................................................ 50

Tabla 12: Formato Trama de Indicación Nodo Caído. ............................................................. 50

Tabla 13: Trama ZigBee Receive Packet.................................................................................. 51

Tabla 14: Horas invertidas. ..................................................................................................... 73

Tabla 15: Coste del proyecto. ................................................................................................. 73

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

6

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

7

1.- Introducción

1.1.- Enunciado y objetivo del proyecto Quizás no somos conscientes al estar inmersos en nuestro día a día, pero sin darnos cuenta que el mundo está cambiando completamente y a pasos agigantados. Cada día se ven más y más proyectos de empresas de todo tipo buscando soluciones inalámbricas. Todo se quiere automatizar, todo se quiere medir, todo se quiere optimizar, todo se quiere controlar y todo se quiere hacer desde la distancia, sin cables, sin gastos de desplazamiento. Todo esto está siendo posible a través de la tecnología basada en redes de sensores inalámbricas o WSN (Por su acrónimo en inglés Wireless Sensor Networks). Una red de sensores inalámbrica, consiste en una serie de dispositivos sensores (nodos), distribuidos a lo largo de una ubicación concreta para cumplir una función determinada de forma cooperativa. Pero la monitorización y el control de un área mediante el uso de redes de sensores inalámbricos, implican la necesidad de capturar, procesar y ordenar los datos de forma fiable y que no interfiera con el desempeño de la red. Por esta causa, el objetivo principal de este proyecto, es el diseño y desarrollo de un sistema o aplicación de adquisición y gestión de datos que recoja toda esa información, de forma amigable o más cómoda para el usuario de dicha aplicación, siendo capaz de procesar, gestionar y ordenar esos datos en tiempo real. El objetivo del proyecto se puede desglosar en los siguientes puntos:

• Configuración y programación de los elementos que componen la red de sensores inalámbrica.

• Diseño y programación de la aplicación software que permita visualizar los datos adquiridos mediante la red desplegada.

1.2.- Organización de la memoria

La memoria se ha dividido en los siguientes capítulos intentando ofrecer una visión clara de todas las fases del proyecto:

• Capítulo 1: Enunciado y objetivo del proyecto y estructura del contenido de la memoria.

• Capítulo 2: Estado del arte, es decir, la base teórica sobre la que se basa el proyecto.

• Capítulo 3: Especificación de los requisitos a cumplir por el proyecto. Exposición y análisis de las diferentes alternativas de las que se dispone para realizar el proyecto y justificación de la decisión final adoptada.

• Capítulo 4: Descripción de la solución tomada para la implementación inalámbrica (WSN).

• Capítulo 5: Descripción y documentación de la solución adoptada para la implementación del sistema o aplicación de adquisición y gestión de datos.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

8

• Capítulo 6: Conclusiones extraídas y posibles líneas de desarrollo futuras a partir del estado final del proyecto.

• Capítulo 7: Bibliografía.

• Apéndice A: Documento de ayuda que explica paso a paso la Aplicación.

• Apéndice B: Diagrama de clases.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

9

2.- Estado del arte En el presente capítulo se expondrán las bases teóricas del diseño de la aplicación, para ello el capítulo se divide en cuatro secciones. En la primera se van a describir de qué tratan las redes de sensores inalámbricos, sus configuraciones, funcionalidades, problemas característicos y algunos de los dispositivos más conocidos, así como sus fabricantes. La segunda sección trata sobre los estándares de comunicación propiamente diseñados para estos dispositivos escasos de recursos tanto de suministros de potencia, memoria como de procesamiento. En la tercera sección, se explicará un poco las nuevas tendencias que está tomando esta tecnología a la hora de funcionar, para sacar el máximo provecho posible. Y por último, en la cuarta sección se hablará sobre las aplicaciones para la representación de los datos adquirido a través de una red de sensores inalámbrica.

2.1.- Redes de sensores inalámbricos

2.1.1.- Definición

Una red de sensores inalámbrica (Wireless Sensor Network, WSN) está formada por elementos

sensores autónomos (llamados nodos o motas) distribuidos en el espacio que se comunican

entre sí de manera inalámbrica, recogiendo información de sus sensores para controlar

diversas condiciones en distintos puntos, entre ellas la temperatura, el sonido, la vibración, la

presión y movimiento o los contaminantes. Típicamente envían la información recogida a un

elemento sumidero de la red que actúa de pasarela, trasladando la información de la red al

usuario final.

En la figura 1 se puede observar la complejidad de una red de sensores inalámbricos, que

generalmente consiste en una red de adquisición de datos y una red de distribución de datos,

monitorizada y controlada por un centro de control.

Figura 1: Visualización de una red de adquisición de datos y una red de distribución de datos.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

10

Las distintas características que hacen peculiares a las redes de sensores inalámbricas son las

siguientes:

• Movilidad de los nodos: la movilidad no es un mandato que se deba cumplir. Por

ejemplo, el despliegue de nodos para monitorizar las propiedades del suelo no lo

requiere.

• Tamaño de la red: el número de sensores en la red puede ser mucho más grande que

una red inalámbrica típica, con lo cual, es necesario que el precio de los mismos sea

bajo para el éxito de esta tecnología.

• Densidad de la red: varía de acuerdo al tipo de aplicación. En el caso de aplicaciones de

seguridad se requiere que la red siempre esté disponible y con redundancia de

información.

• Limitación de energía: en el caso de las redes de sensores, se espera que funcionen en

ambientes agresivos en cuanto a condiciones ambientales, con el mínimo o nula

supervisión humana posible. Emplear este tipo de redes, donde la única fuente de

alimentación para el nodo sensor es la batería, limita la vida útil de la red, exigiendo de

esta manera un conjunto de protocolos de red muy eficientes a nivel capa de red, capa

de enlace de datos y hasta física para brindar un control óptimo de energía.

• Fusión de los datos e información: las limitaciones de ancho de banda y energía

demandan el aumento de bits y de información en los nodos intermedios. Para la

fusión de los datos, se necesita la combinación de múltiples paquetes dentro de uno

solo antes de su transmisión. Lo que se busca es reducir el ancho de banda utilizado

mediante encabezados redundantes en los paquetes y minimizar el retardo al acceder

al medio para transmitir los múltiples paquetes.

• Distribución del tráfico: el patrón de tráfico varía en base al tipo de aplicación de la

red. El sensado de un factor ambiental, genera de manera periódica pequeños

paquetes con datos que indican el estado del parámetro de estudio a una estación

central de monitorización. Esto demanda un bajo ancho de banda. Sin embargo,

cuando se trata de detectar a un intruso en el ámbito militar, se genera un tráfico de

detección en eventos con limitaciones en la transmisión en tiempo real.

Habitualmente una red de sensores está formada por varios de los siguientes elementos:

• Nodo sensor: el elemento más común. Es el encargado de recoger la información que

se quiere medir y transmitirla. Habitualmente está formado por un subsistema de

comunicación (transceptor RF) que es el responsable del intercambio de mensajes con

los nodos sensores vecinos, un subsistema de procesado (microcontrolador y

memoria) que lleva acabo el cómputo de la información recabada por el sensado, un

subsistema del sensor que son un número de sensores que sensan (mide un

parámetro) el medio ambiente y una batería.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

11

• Router: es el dispositivo que tiene la función de encaminar los paquetes por la red

entre los nodos sensores y coordinador.

• Coordinador: es el dispositivo responsable de la red y el encargado de enviar la

información recopilada al usuario final. Habitualmente está conectado a una red de

energía y a Internet mediante conexión de banda ancha.

En algunos protocolos e implementaciones concretas de redes de sensores hacen uso de otros

elementos adicionales o modificaciones en los ya comentados.

2.1.2.- Descripción Hardware de un nodo sensor. Un nodo sensor es un elemento computacional con capacidad de procesamiento, memoria, interfaz de comunicación y con un conjunto de sensores, como se muestra en la figura 2. El hardware básico de un nodo sensor se compone de un transceptor (transmisor/receptor), un procesador, uno o más sensores, memoria y batería.

Los componentes permiten la comunicación (enviar/recibir información) y ejecutar tareas que requieren procesamiento además de efectuar funciones de sensado.

Figura 2: hardware básico de un nodo sensor.

La capacidad de procesamiento depende del tipo de microprocesador que se emplee. Así mismo, posee una memoria interna en el microcontrolador. La comunicación se realiza mediante un transceptor (transmisor/receptor). Además, la fuente de alimentación varía dependiendo el tipo de tecnología con la cual la batería esté fabricada. En cuanto al sensor, éste es el responsable de monitorizar el parámetro de interés e informar del mismo.

Cada nodo sensor puede ser equipado con dispositivos sensores acústicos, sísmicos, infrarrojos, vídeo cámaras, mecánicos, de calor, temperatura, radiación, entre otros. La figura

3 muestra algunos tipos de sensores que pueden presentarse en un nodo sensor tales como un micrófono que puede ser usado para captar señales acústicas del medio ambiente, un detector

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

12

de caudal que es capaz de medir el flujo o corriente de medios líquidos, un diodo detector de luz, un acelerómetro que es un sensor capaz de medir la aceleración de un objeto, un sensor de humedad, un sensor de radiación y un sensor de luz ultravioleta.

Figura 3: tipos de sensores que pueden presentarse en un nodo.

La tendencia es producir sensores a gran escala, a precios bajos, con mejor capacidad de cómputo y de tamaño reducido como se observa en la figura 4.

Figura 4: Sensores de tamaño reducido.

Es elemental resaltar que estos nodos sensores tienen fuertes restricciones en cuanto a la capacidad de memoria, de procesamiento y principalmente de energía, siendo deseable poseer dispositivos de bajo consumo de energía.

Entre los fabricantes de nodos sensores se pueden citar:

• CROSSBOW: especializada en el mundo de los sensores, es una empresa que desarrolla plataformas hardware y software que dan soluciones para las redes de sensores inalámbricas. Entre sus productos se encuentran las plataformas Mica, Mica2, Micaz, Mica2dot, telos, telosb, Iris e Imote2. En la siguiente imagen, figura 5, se puede observar uno de los dispositivos de esta empresa.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

13

Figura 5: Nodo sensor de la empresa CROSBOW.

• SENTILLA: llamada anteriormente MoteIV. Es la encargada de las motas Tmote Sky, diseñados también por la Universidad de Berkeley y preparados para ser usados por TinyOS. Fue Joseph Polastre, antiguo doctorando de un grupo de trabajo de esta universidad, quien formó la compañía MoteIV. Ha desarrollado la plataforma Tmote Sky y Tmote Invent. La figura 6 representa el Tmote Sky.

Figura 6: Dispositivo sensor de la empresa Motei IV.

• BTnode: los módulos fabricados por esta empresa han sido desarrollados por el ETH Zurich, conjuntamente por el Computer Engineering and Networks Laboratory (TIK) y el Research Group for Distributed Systems. Actualmente, los BTnodes son usados en dos grandes proyectos de investigación, apoyando a la plataforma de desarrollo inicial, estos son NCCS MICS y Smart-Its. Una imagen de alguno de sus motes es la siguiente (Figura 7):

Figura 7: Nodo sensor de la empresa BTnode

• SUN: Sun SPOT (Sun Small Programmable Object Technology) es una mota para WSN desarrollado por Sun Microsystems. El aparato está construido bajo la normativa

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

14

estándar IEEE 802.15.4. Al contrario de otros nodos inalámbricos, el Sun SPOT está construido bajo la máquina virtual Java Squawk.

• Nano-RK: ha desarrollado la plataforma FireFly como una plataforma de nodos inalámbricos de bajo consumo y bajo coste, con la idea de dar el mejor soporte en aplicaciones en tiempo real.

• ARDUINO: es una plataforma de electrónica abierta para la creación de prototipos basada en software y hardware flexibles y fáciles de usar. Añadiéndole la Xbee shield permite a la placa Arduino comunicarse de forma inalámbrica usando Zigbee de este modo se pueden crear redes de sensores. En la siguiente imagen (Figura 8) se puede observar el Arduino:

Figura 8: Nodo sensor de la Arduino.

• LIBELIUM: Libelium es una empresa de diseño y fabricación de hardware para la implementación de redes sensoriales inalámbricas, redes malladas y protocolos de comunicación para todo tipo de redes inalámbricas distribuidas. Sus principales líneas de investigación y desarrollo son:

–Waspmote: dispositivo sensorial de bajo consumo para la creación de redes sensoriales inalambricas. –Meshlium: unico router multitecnologia que integra en una maquina las tecnologías Wifimesh (2.4GHz - 5GHz), ZigBee, GPRS, GPS y Bluetooth.

En la siguiente imagen (Figura 9) se puede observar el waspmote:

Figura 9: Nodo sensor de la empresa LIBELIUM.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

15

2.1.3.- Topología y jerarquía

Existen diferentes posibilidades a la hora de interconectar los nodos de una red de sensores

entre sí como se puede ver en las siguientes figuras. Se puede hablar de las siguientes:

• Estrella: es la topología más básica. Los nodos de los extremos pueden ser muy simples

y se conectan directamente al sumidero o a la pasarela.

Figura 10: Topología en estrella.

• Anillo: se trata de una topología típica de redes de fibra óptica, poco práctica en redes

de sensores debido a la distribución que tendrán los nodos en el espacio.

Figura 11: Topología en anillo.

• Árbol: una topología interesante en ciertos casos, donde la información se lleva de los

nodos sensores más alejados de la pasarela hasta el sumidero. Requiere mayor

complejidad que una red en estrella, pero mantiene la simplicidad en los nodos de las

hojas.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

16

Figura 12: Topología en árbol.

• Mallado con conexión total: existe enlace directo entre todos los pares de nodos de la

red. Una malla completa con n nodos requiere de n(n − 1)/2 enlaces directos. Debido a

esta característica, es una tecnología costosa pero muy fiable.

• Mallado con conexión parcial: algunos nodos están organizados en una malla

completa, mientras otros se conectan solamente a uno o dos nodos de la red. Esta

topología es menos costosa que la malla completa pero por supuesto, no es tan

confiable ya que el número de enlaces redundantes se reduce.

Figura 13: Topología en malla.

Considerando la jerarquía que se puede establecer en una red de sensores inalámbricos, pueden existir distintos niveles entre los nodos de la red, que en este caso sería un coordinador, un router y un dispositivo final, como en la figura 14.

Un coordinador, sería el nodo principal, es decir, el responsable de crear la red admitiendo o rechazando a nodos de niveles inferiores. Además dicho coordinador tiene como función actuar como sumidero de la información de la red. Por otra parte, tenemos el siguiente nivel de la red que es el nodo router, el cual tiene la función de rutar o actuar como encaminador de la información que recorre la red. Y por último, estaría el nodo que se comporta como dispositivo final, que tiene como función recolectar la información del medio y subirla a los niveles superiores de la red.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

17

Figura 14: Tipos de jerarquías de una red.

O por otra parte todo lo contrario, que no exista ningún nivel de jerarquía y que todos los nodos formen una red ad hoc sin infraestructura física preestablecida ni administración central.

2.1.4.- Problemas característicos

Las características específicas de las redes de sensores traen consigo retos a superar, como son

la gestión de la energía, los protocolos utilizados, la fiabilidad de la red, el tamaño de los nodos

sensores y la seguridad en las redes de sensores.

2.1.4.1.- Fiabilidad

Es habitual que el lugar donde estén situados los nodos sensores no sea el más adecuado

desde el punto de vista de la transmisión de la información. Ya sea en una fábrica, en una

oficina o en el campo, es seguro que se tienen interferencias en las comunicaciones y que los

nodos pueden dejar de funcionar por causas ajenas a su diseño (son robados, se estropean, se

introducen obstáculos entre los nodos, etc). Es por ello que la fiabilidad de las comunicaciones

es fundamental.

Una manera de mejorar la fiabilidad de la red de sensores es mediante la topología. Se ha

comprobado que una topología en estrella o similar es débil porque confía plenamente en que

la información va a llegar al nodo central de la estrella. Si ese nodo cae, también se pierden

todas sus ramas. Es por eso que la topología que mejor funciona a la hora de la verdad es la

mallada, donde todos los nodos tienen varios nodos a los que pueden comunicarse, de manera

que la información siempre encontrará una manera de llegar a su destino.

El otro punto clave a la hora de la fiabilidad es la utilización de saltos en frecuencia. Los canales

que utilizan las redes de sensores son sometidos habitualmente a fuertes interferencias ya que

son de libre utilización. Por este motivo, es importante realizar saltos en frecuencia para

cambiar de un canal a otro dinámicamente conforme se tienen interferencias si se quiere

mantener la fiabilidad de la red.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

18

2.1.4.2.- Conservación de la energía

Una importante característica de las redes de sensores inalámbricos es reducir al mínimo el

consumo de energía de los nodos, proporcionando al mismo tiempo el mayor rendimiento

posible a los usuarios del sistema.

Diseñar los nodos para un bajo consumo supone elegir componentes de baja potencia. El

primer parámetro a considerar es el consumo de energía de la CPU, el sensor, el transceptor y

otros elementos como la memoria externa y los periféricos durante el modo normal de

operación. La elección de elementos de baja potencia implica normalmente aceptar

compromisos sobre el rendimiento medio. La solución está en elegir elementos con el

rendimiento justo para poder hacer el trabajo.

La manera más común de afrontar el problema es el ciclo de trabajo de los componentes.

Dado que los nodos no necesitan enviar información continuamente, se establece un ciclo de

trabajo para el dispositivo y el resto del tiempo está “dormido”, consumiendo muy poca

energía, del orden de μA. El ciclo de trabajo se sitúa en torno al 1%. A menudo se puede

incluso desconectar por completo la alimentación del sensor y del transceptor. Sin embargo, la

CPU necesitará alguna alimentación en modo dormido para poder reactivarse.

2.1.4.3.- Tamaño de los nodos sensores

En realidad, es el menor de los problemas hoy en día. Son más importantes lo demás en la

mayoría de aplicaciones, pero no en todas. Si se quieren utilizar redes de sensores en

aplicaciones como adquisición de señales vitales en pacientes, el tamaño es importante.

En general el tamaño del nodo sensor está limitado por el de su fuente de energía: la batería

en la mayor parte de los casos. Se puede observar en la figura 15 algunos ejemplos de baterías.

Se tienen tres tipos de fuente de alimentación:

• Baterías convencionales: las más comunes y utilizadas en monitorización de campo, de

fábricas, etc. Son las más baratas.

• Obtención propia de la energía: estos sensores obtienen su propia energía del

ambiente. Existen aquellos que la obtienen de la radiación de la luz, de las vibraciones,

de la presión o de los cambios de temperatura.

Figura 15: Algunos ejemplos de baterías.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

19

2.1.4.4.- Seguridad en redes de sensores inalámbrica.

La seguridad en las redes de sensores ha sido estudiada de forma extensiva por la comunidad

científica, y aunque aún existen problemas de seguridad que deben ser resueltos (p. ej. manejo

de nodos móviles, delegación de privilegios, privacidad, agentes seguros, actualización del

código), actualmente es posible crear una red de sensores que cumpla un conjunto básico de

propiedades de seguridad. Para cumplir con ese conjunto mínimo de propiedades seguras en

sus operaciones internas, las redes de sensores deben utilizar primitivas criptográficas, utilizar

sistemas de gestión de claves, y proporcionar soporte para el conocimiento del entorno y la

autoconfiguración.

Respecto a las primitivas criptográficas, el hardware actual de las redes de sensores es

perfectamente capaz de soportar criptografía simétrica, criptografía de clave pública, y

funciones hash. El estándar IEEE 802.15.4 proporciona soporte hardware para ejecutar la

primitiva AES-128, aunque ésta y otras primitivas pueden ejecutarse por software.

La gestión de claves sigue siendo una línea de investigación abierta, aunque con el estado del

arte actual es posible satisfacer los requerimientos de redes de sensores pequeñas. La

criptografía puede utilizarse como base para crear servicios de seguridad esenciales

(confidencialidad, integridad, autenticación), pero estos servicios no son suficientes para

cumplir una de las propiedades inherentes a las redes de sensores: la autoconfiguración.

2.2.- Estándares de comunicación Desde 1999 las redes de sensores han sufrido un desarrollo importante. Prácticamente todas las universidades tecnológicas del mundo tienen proyectos dedicados a esta tecnología. Las grandes compañías, como Intel, IBM, Microsoft, Google y Motorola están invirtiendo en su desarrollo. El valor de las redes inalámbricas de sensores se basa en su bajo coste y su distribución en grandes cantidades. Para lograr la economía de escala necesarias para alcanzar un mercado de bajo coste, algunos elementos de las redes inalámbricas de sensores deben ser estandarizados, de manera que los productos de muchos fabricantes puedan interoperar. Esta sinergia añadirá utilidad a las redes inalámbricas de sensores y, por tanto, fomentará su uso. Con este fin, se están realizando esfuerzos para estandarizar las distintas capas de los protocolos de comunicación de redes de sensores inalámbricos, incluyendo la carga útil de los datos enviados por sus sensores. El éxito de las redes inalámbricas de sensores como una tecnología se basa en el éxito de estos esfuerzos de estandarización para unificar el mercado, dando lugar a un gran número de dispositivos de bajo coste, interoperables, y evitando la proliferación de la propiedad y de protocolos incompatibles que, aunque tal vez óptimos en sus nichos de mercado, limitan el tamaño del mercado global de sensores inalámbricos. Además, hoy en día no existe un estándar de facto, ni en protocolos, ni en hardware, ni en representación de datos. Esto es debido por una parte, a que las aplicaciones de las redes de sensores son tan amplias que es difícil englobarlas todas. Y por otra parte, a que las tecnologías están en constante cambio y desarrollo. De entre las soluciones existentes, sin

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

20

embargo, sí hay quienes tienen más fuerza y quiénes tienen menos. A continuación se presentan las principales iniciativas en curso.

2.2.1.- Bluetooth y Wi-Fi Los sistemas Bluetooth (IEEE 802.XX) y Wi-Fi (IEEE 802.11) son dos opciones muy populares y

comercialmente disponibles cuya utilización en redes inalámbricas de sensores ha sido

evaluada.

Bluetooth es un sistema diseñado como una red inalámbrica de área personal, su principal

aplicación es la conexión de dispositivos a una computadora personal. Se han hecho prototipos

de redes de sensores basadas en Bluetooth, los nodos organizados en picoredes con un nodo

maestro y un máximo de siete nodos esclavos activos. El maestro elije la secuencia de hopping

que deben seguir los esclavos. Puede haber varios nodos esclavos en estado pasivo en la

picored, el maestro interroga los nodos esclavos activos continuamente.

Hay varios inconvenientes de la aplicación de Bluetooth a redes inalámbricas de sensores:

• La necesidad de tener un nodo maestro constantemente, con el costo de interrogar

sus esclavos.

• La cantidad limitada de esclavos por picored que soporta.

• Para el caso de redes de sensores densas, se necesitara un número enorme de nodos

maestros.

• Un esclavo activo debe permanecer siempre encendido, ya que no puede predecir

cuándo será interrogado por el maestro.

• Un esclavo pasivo debe postularse con el maestro para cambiar a activo, y si ya hay

siete nodos activos, será rechazado.

• Se requiere que cada nodo pueda asumir el rol de maestro o esclavo, agregando una

complejidad considerable.

• Los rápidos saltos de frecuencia requieren una sincronización estricta entre los nodos

de la picored.

En la familia de protocolos IEEE 802.11 se especifican varios tipos de capa física que comparten

un único protocolo de capa MAC (DCF). En términos generales, el estándar de protocolos IEEE

802.11 tiene los siguientes inconvenientes:

• Requiere que los nodos estén permanentemente escuchando el medio, ya que podrán

tener que recibir una trama en cualquier momento.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

21

• Se proveen algunas funcionalidades de ahorro de energía, en general está orientado a

altas tasas transmisión, y los transceptores disponibles requieren una cantidad de

energía que es órdenes de magnitud mayores que lo aceptable en aplicaciones de

redes de sensores.

• Es un protocolo de salto-único para redes ad-hoc, cuando lo común en redes de

sensores es el encaminamiento de salto-múltiple.

2.2.2.- Estándar IEEE 802.15.4 En el estándar IEEE 802.15.4 se definen las especificaciones de la capa física y de enlace para la conectividad inalámbrica de baja tasa de datos con dispositivos fijos, portátiles y móviles sin requisitos de consumo de batería que normalmente operan en el Espacio de Operación Personal (POS) de 10 metros. Este estándar proporciona una norma de baja complejidad, bajo coste, pequeño consumo de energía y conectividad inalámbrica de baja velocidad de datos entre dispositivos. La tasa de datos en bruto será lo suficientemente alta (un máximo de 200 kbps) para satisfacer un conjunto de necesidades simples, pero adaptable a las necesidades de los sensores y de automatización (10 kbps o menos) para comunicaciones inalámbricas. Las tasas de datos máxima y mínima se plantearon más tarde a 250 y 20 kb/s, respectivamente. Este conjunto de objetivos requiere que el estándar IEEE 802.15.4 sea extremadamente flexible. A diferencia de los protocolos que han sido diseñados para una sola aplicación, tales como IEEE 802.11, el estándar IEEE 802.15.4 soporta una variedad casi infinita de posibles aplicaciones en el POS. Estas aplicaciones varían desde requerimiento de alta tasa de transferencia de datos y relativamente baja latencia de mensaje, tales como teclados inalámbricos, ratones, y joysticks, a los que requieren muy baja tasa de transferencia y son capaces de tolerar significante latencia de mensajes, tales como la agricultura inteligente y aplicaciones de detección del entorno. El estándar IEEE 802.15.4 soporta conexiones tanto en estrella como punto a punto, por lo que es capaz de soportar una amplia variedad de topologías de red y de algoritmos de enrutamiento. Cuando se utiliza seguridad, el paquete de seguridad AES-128 es obligatorio. El estándar emplea balizas, aunque su uso es opcional. El período de baliza es variable, de modo que se puede hacer para cada aplicación un equilibrio óptimo entre la latencia del mensaje y el consumo de energía de cada nodo de la red. Las balizas pueden ser omitidas para aplicaciones que tienen limitaciones de ciclo de servicio, como puede ocurrir en las redes en la banda de 868 MHz o aplicaciones que requieren nodos de red con recepción constante. El acceso al canal está basado en la contención a través de mecanismo de acceso múltiple por detección de portadora con prevención de colisión (CSMA-CA); la baliza es seguida por un período de acceso de contención (CAP) para los dispositivos que intentan acceder al canal. La duración del CAP es ajustable a una fracción del período entre balizas. Para atender las necesidades de las aplicaciones que requieren mensajes de baja latencia. El estándar admite el uso de ranuras de tiempo garantizadas (GTSs), que reservan el tiempo del canal para dispositivos individuales sin la necesidad de seguir el mecanismo de acceso CSMA-CA. El estándar tiene un campo de direcciones de 16 bits, sin embargo, la norma incluye también la capacidad de enviar mensajes con direcciones extendidas de 64 bits, lo que permite un número casi ilimitado de dispositivos que se pueden colocar en una única red. La transmisión de mensajes puede ser asentida mediante reconocimientos positivos, tras cada trama transmitida (con la excepción de las balizas y los reconocimientos a sí mismos) se puede recibir

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

22

un reconocimiento explícito dando lugar a un protocolo fiable. La sobrecarga asociada con los reconocimientos explícitos es aceptable dada la baja tasa de datos típica de redes inalámbricas de sensores. El uso de los reconocimientos es opcional con cada trama transmitida, sin embargo, se soportan el uso de técnicas de reconocimiento pasivas. El estándar IEEE 802.15.4 incorpora muchas características diseñadas para minimizar el consumo de energía de los nodos de la red. Además de la utilización de períodos largos de baliza y un modo de extensión de vida de la batería, el período activo de un nodo con baliza se puede reducir, permitiendo que el nodo se duerma entre balizas. La coexistencia de otros servicios que usan bandas sin licencia con los dispositivos IEEE 802.15.4 fue también un factor importante en el diseño del protocolo, y es evidente en muchas de sus características. Por ejemplo, es necesaria la selección dinámica de canales; cuando se puede interferir a otros servicios que se encuentran trabajando en un canal que está siendo utilizado por una red IEEE 802.15.4, el nodo de red que controla la misma (coordinador de red de área personal (PAN)) explora otros canales disponibles para encontrar un canal más adecuado. En esta exploración, se obtiene una medida de la energía de cada canal alternativo y, a continuación, utiliza esta información para seleccionar un canal adecuado. Este tipo de escaneo también se puede usar antes del establecimiento de una nueva red. Antes de cada una de las transmisiones (excepto tramas baliza o de reconocimiento), cada nodo de red IEEE 802.15.4 debe realizar dos evaluaciones de canal (CCAs) como parte del mecanismo CSMA-CA para garantizar que el canal está desocupado antes de la transmisión. Un byte de indicación de la calidad del enlace (LQI) se adjunta a cada trama recibida por la capa física antes de que sea enviada a la capa de control de acceso al medio. El nodo receptor utiliza esta información para diversos fines, dependiendo del diseño de la red. Para maximizar la utilidad de la norma, el grupo de tarea IEEE 802.15.4 tenía que equilibrar el deseo de permitir nodos de red pequeños, de bajo coste y baja potencia con el deseo de producir una norma que se pudiera utilizar por una amplia variedad de aplicaciones en el mercado. El estándar resultante incluye tres tipos de funcionalidades de nodo de red:

• Coordinador: es el nodo que inicia la red y es el principal controlador de la misma. El coordinador puede transmitir balizas y se puede comunicar directamente con cualquier dispositivo en su rango. Dependiendo del diseño de red, es posible que tenga suficiente memoria para almacenar información sobre todos los dispositivos en la red, y debe tener memoria suficiente para almacenar la información de enrutamiento según lo exija el algoritmo empleado por la red.

• Router: puede transmitir balizas y se puede comunicar directamente con cualquier dispositivo a su alcance. Un router puede convertirse en un coordinador en el caso de empezar una nueva red.

• Dispositivo: no genera balizas y sólo puede comunicarse directamente con un router o coordinador.

Estas tres funciones son incorporadas en dos tipos de dispositivos diferentes:

• Dispositivo de función completa (FFD): puede operar en cualquiera de las tres funciones de red (coordinador, router, o dispositivo). Debe tener memoria suficiente

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

23

para almacenar la información de enrutamiento que imponga el algoritmo empleado por la red.

• Dispositivo de función reducida (RFD): es un dispositivo de muy bajo coste, con requisitos de memoria mínimos. Sólo puede funcionar como un dispositivo de red.

Similar a todos los estándares inalámbricos IEEE 802, el estándar IEEE 802.15.4 normaliza sólo las capas física y de control de acceso al medio (MAC). El estándar IEEE 802.15.4 incorpora dos capas físicas:

• La banda inferior: 868,0-868,6 MHz (para Europa), además de los 902-928MHz (para la mayor parte de América y la Cuenca del Pacífico).

• La banda superior: 2,400-2,485 GHz (en todo el mundo). En la figura 16 se puede observar la pila de protocolos que propone dicho estándar, sobre el que está montado Zigbee.

Figura 16: Torre de protocolo 802.15.4.

2.2.3.- ZigBee

ZigBee es un estándar de comunicación orientado a aplicaciones cuyos requerimientos

principales son bajas tasas de transmisión, bajo costo y larga duración de batería.

Los estándares ZigBee son desarrollados por la organización ZigBee Alliance, conformada por

cientos de compañías, y formada en el 2002 como una organización sin fines de lucro. Algunas

empresas promotoras son Philips, Emerson y Texas Instruments. Las empresas participantes

son numerosas, entre ellas se encuentran AT&T, Cisco, Huawei, Indesit, LG, Samsung, Siemens,

Whirpool, Intel.

El estándar ZigBee está definido en capas de protocolos, basadas en el modelo de referencia

OSI. Adoptando la capa física (PHY) y de acceso al medio (MAC) IEEE 802.15.4, define capas de

servicios de red, aplicación y seguridad.

La figura 17 esquematiza las capas de la arquitectura ZigBee.

Las características físicas de la red están determinadas por la capa física IEEE 802.15.4

descripta en la sección 2.2

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

24

Figura 17: Torre de protocolo ZigBee.

El papel que juegan los nodos en ZigBee se corresponden con los del estándar IEEE 802.15.4,

aunque tienen diferente denominación:

• Coordinador ZigBee (coordinator) (Coordinador PAN IEEE 802.15.4).

• Encaminador ZigBee (router) (Coordinador IEEE 802.15.4).

• Dispositivo Final ZigBee (end device) (Dispositivo IEEE 802.15.4).

Se soportan las topologías de red en estrella o punto a punto, como se especifica en IEEE

802.15.4.

En la red estrella, esquematizada en la figura 18, todos los dispositivos de la red se comunican

a través del coordinador, que al activarse selecciona un identificador de red único dentro de su

alcance de radio y establece la red.

Figura 18: Red ZigBee en estrella.

En la red punto a punto, todos los dispositivos pueden comunicarse directamente entre sí. Los dispositivos de funcionalidad reducida participan en la red comunicándose con un coordinador

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

25

o un encaminador ZigBee, pero no encaminan mensajes. En este caso, el encaminador también puede tomar el rol de coordinador. La red punto a punto puede tomar diferentes formas:

• Malla: No hay restricción sobre los dispositivos que pueden comunicarse entre sí.

Figura 19: Red ZigBee en malla.

• Árbol: El coordinador establece la red inicial. Los encaminadores forman las ramas y los dispositivos finales, que no encaminan datos, las hojas del árbol. Los encaminadores pueden agregar más nodos a la red, más allá de la red inicial.

Por otra parte la capa de aplicación es la más alta en la pila ZigBee, y aloja los objetos de aplicación. Los fabricantes desarrollan objetos de aplicación para personalizar los dispositivos para su aplicación. Estos objetos controlan y administran las capas de protocolos del dispositivo. El estándar ZigBee ha definido perfiles de aplicación, un conjunto de acuerdos sobre formatos de mensajes y acciones de procesamiento para promover la interoperabilidad entre diferentes vendedores. ZigBee también provee mecanismos para garantizar la confidencialidad y autenticidad de la información transmitida. El estándar IEEE 802.15.4 soporta el uso de cifrado AES (Advanced Encryption Standard) de los paquetes salientes. La autenticación de los datos se puede comprobar incluyendo un código de integridad de mensaje (MIC) en cada trama. La capa de red es responsable de la administración de la red y del encaminamiento. El coordinador establece la nueva red, selecciona la topología, y asigna direcciones al resto de los dispositivos. Los coordinadores y encaminadores son los que descubren y mantienen las rutas en la red.

2.2.4.- Wireless HART WirelessHART surge como una adaptación de la especificación HART ya existente, que se creó en EE.UU. para la monitorización de sensores en entornos industriales. Esta iniciativa especifica perfiles y casos prácticos en los que se puede aplicar directamente el control inalámbrico. La pila de protocolos de HART se puede observar en la figura 20.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

26

Figura 20: Torre de protocolo de Wireless HART.

La mayor diferencia con respecto a ZigBee es el acceso al medio, realizado mediante TDMA, ahorrando tiempo y energía en los nodos sensores. La topología también es diferente, ya que en esta especificación la red es mallada. De esta manera consigue una red fiable y eficiente energéticamente. Además, todos los nodos pueden encaminar y son iguales, haciendo mucho más sencilla su instalación y consiguiendo mayor flexibilidad. Para la generación de mensajes de información, debido a la naturaleza de la aplicación, tiene su propio protocolo (Smart Data) que permite enviar información sólo cuando se registra un cambio en la medición del sensor.

2.2.5.- DUST Networks

Es una empresa líder en las redes de sensores, surgida a partir del proyecto de Berkeley y

creada por su director, Kris Pister.

Esta empresa ha desarrollado su propio protocolo para redes de sensores, TSMP (Time

Synchronized Mesh Protocol) que tiene las siguientes características:

• Capa física: utiliza DSSS y FHSS para mayor fiabilidad en la comunicación entre nodos y

para evitar interferencias con otras redes u obstáculos. Cuando un nodo entra a

formar parte de la red, recibe la secuencia pseudo-aleatoria de frecuencias de sus

vecinos y genera la suya propia.

• Capa MAC: en lugar de CSMA utiliza TDMA, sincronizando los nodos para la

transmisión de información en slots de tiempo. Para la información de sincronización

de los nodos utiliza los paquetes ACK. Esta manera de actuar consigue evitar colisiones

y hace que el sistema sea fácilmente escalable.

• Auto-organización: todos los nodos son capaces de descubrir vecinos, ajustar la

potencia de la señal RF y adquirir información de sincronización y saltos de frecuencia.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

27

• Diversidad de enrutamiento: un nodo tiene siempre dos o más posibles rutas. Utilizará

una de las dos normalmente y, si después de enviar un mensaje no recibe ACK,

utilizará la otra. Si recibe un NACK, entonces repetirá la misma ruta.

• Consumo de energía: gracias al uso de un acceso al medio sincronizado, el consumo de

energía se reduce drásticamente. La causa está en el ciclo de trabajo, al enviar y recibir

en periodos de tiempo predeterminados, los nodos sólo necesitan estar despiertos en

los slots que tienen asignados. Incluso en los nodos que no realizan enrutamiento se

reduce el consumo, ya que de toda la circuitería de un nodo sensor, la antena RF es la

que más consume (alrededor del 95 %).

2.3.- Nuevas tendencias

2.3.1.- Procesado ubicuo

A pesar de que las redes de sensores son muy recientes, ya se empiezan a observar nuevas

líneas de expansión que sobrepasan el concepto actual de red de sensores. El siguiente salto

en la evolución de esta tecnología parece ser la toma de decisiones «in situ» por la propia red

de sensores. Es lo que se denomina pervasive computing, que podría traducirse como

procesado ubicuo.

En la evolución de las tecnologías inalámbricas y los sensores ha ido aumentando la capacidad

de procesado y de autonomía de los elementos de la red. De los códigos de barras se dio el

salto a RFID sin alimentación. Cuando se conectaron entre sí módulos inalámbricos formando

redes ad-hoc, se llegó a las redes de sensores. El siguiente paso es el procesado ubicuo.

En esta nueva tecnología, los nodos de la red no sólo recopilan información y la envían al

usuario, sino que toman decisiones por sí mismos en función de la información obtenida. De

esta manera, la rapidez de actuación y la flexibilidad de estos sistemas darían un salto

cualitativo importante. La coordinación de grandes cantidades de información, como gestión

de tráfico, por ejemplo, sería resuelta de una manera mucho más eficaz.

2.3.2.- Web de sensores

Quizás la evolución más interesante y prometedora de las redes de sensores sea la web de

sensores. Es muy similar al procesado ubicuo, sólo cambia un poco el enfoque.

Al igual que las redes de sensores, las webs de sensores se definen como una red amorfa de

sensores distribuidos en el espacio que se comunican inalámbricamente entre ellos. La

diferencia está en que la web de sensores actúa como un único ente sensor: la información

que capta un nodo es compartida con todos los nodos de la red, permitiendo la actuación de

toda la web de forma conjunta y autónoma. No necesita de agentes exteriores para funcionar.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

28

De esta manera, el alcance de actuación se incrementa notablemente. Una web de sensores es

capaz de tener en cuenta la región en lugar de sus puntos y, por ejemplo, permite conocer la

dirección y velocidad de un frente en movimiento.

A día de hoy ya existen webs de sensores, pero están lejos de alcanzar el potencial que tienen.

La NASA es el principal promotor de esta tecnología y por el momento ya ha llevado a cabo

proyectos en detección de inundaciones, de actividad volcánica y de condiciones de vida en la

Antártida.

Sin embargo, no se aprovecha realmente las posibilidades del concepto. En realidad, la web de

sensores, a día de hoy, actúa como un sensor que transmite la información a un centro de

datos, en lugar de ser a la vez un sistema que reacciona según esa misma información. Eso sí,

realiza un procesado de esa información para decidir cuándo es importante transmitirla y

cuándo no. El avance es significativo respecto a las redes de sensores normales, en las cuales

no hay procesado de la información y se trata de un sistema pasivo que traslada la información

al centro de procesado.

2.4.- Representación de datos adquiridos mediantes la red de sensores

Una vez que se tienen los datos obtenidos por los nodos de la red de sensores, es necesario

trabajar con ellos y representarlos de forma comprensible. Existe software preparado para

este fin, la mayoría distribuido por los propios fabricantes junto con el hardware de la red.

Pero ésta no es la única posibilidad. Microsoft y Google ofrecen un servicio de publicación de

datos y representación de los mismos, de forma que dicho servicio es accesible fácilmente

desde cualquier lugar del mundo. Así, de nuevo, se observa la convergencia de estas nuevas

redes con Internet.

Por otra parte, existen lenguajes de programación de alto nivel (como C#, Java, Visual Basic) que permiten diseñar aplicaciones software abiertas al fin deseado y a la medida del hardware seleccionado.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

29

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

30

3.- Componentes y escenario de la solución adoptada

La solución adoptada para este sistema, va desde la elección de los dispositivos de la red de

sensores inalámbrica (nodos), pasando por la tipología de dicha red, así como el estándar de

comunicación que se va usar. Y terminando por el objetivo de este proyecto que es el diseño

de una aplicación que recoja toda esa información en tiempo real de forma amigable para el

usuario.

Los dispositivos escogidos para la implementación de la red de sensores inalámbrica son los

Waspmote de Libelium, ya que es el material a que ha cedido el Departamento de Ingeniería

de Sistemas y Automática. Y para realizar la aplicación software que permita visualizar los

datos adquiridos mediante la red desplegada, se ha escogido el lenguaje C#, ya que, Visual C#

.NET es un lenguaje de programación seguro y orientado a objetos, que combina la potencia

de Visual C y Visual C++ con la sencillez funcional de las herramientas de desarrollo de

aplicaciones modernas y rápidas, permitiendo desarrollar software .NET para Microsoft

Windows, la web y un gran rango de dispositivos.

3.1.- Elección de dispositivos para la implementación de la WSN

3.1.1.- Descripción del Waspmote

3.1.1.1.- Especificaciones hardware

Los nodos que han sido utilizados para la implementación de la red de sensores inalámbrica,

son los Waspmote que proporciona el fabricante Libelium. Figura 21.

Figura 21: Nodos sensores Waspmote de la empresa LIBELIUM.

Este dispositivo se basa en una arquitectura modular con la idea de integrar únicamente los

módulos que se necesiten en cada dispositivo y ser capaces de cambiarlos y ampliarlos según

las necesidades. Se pueden integrar módulos XBee de Digi y módulos GSM/GPRS para realizar

comunicaciones inalámbricas. Además de módulos GPS para conocer la localización. También

cuenta con módulos sensoriales para obtener información del medio. Así como de módulos de

almacenamiento con SD Memory Card para realizar un registro de información obtenida del

medio.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

31

A parte de los módulos sensoriales que se le pueden acoplar a Waspmote, éste dispone de un

sensor interno integrado de temperatura que utiliza para recalibrarse (DS3231SN de Maxim) y

un acelerómetro (LIS3LV02DL de STMicroelectronics). Como se observan en las figuras 22 y 23.

Las especificaciones hardware que presenta el Waspmote son las siguientes:

• Microcontrolador: ATmega1281

• Frecuencia: 8MHz

• SRAM: 8KB

• EEPROM: 4KB

• FLASH: 128KB

• SD Card: 2GB

• Real Time Clock (RTC): DS3231SN de Maxim.

• Peso: 20gr

• Dimensiones: 73.5 x 51 x 13 mm

• Rango de Temperatura: [-20ºC, +65ºC].

En las siguientes imágenes, figuras 21 y 22, se puede observar los distintos módulos de dicho

dispositivo:

Figura 22: Componentes principales en Waspmote - Cara superior.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

32

Figura 23: Componentes principales en Waspmote - Cara inferior.

3.1.1.2.- Configuración hardware de funcionalidades del Wapmote

En el waspmote disponemos de tres jumpers para activar/desactivar ciertas funcionalidades,

en la figura 24 se puede apreciar la localización de dichos jumpers.

Figura 24: Jumpers de configuración en Waspmote.

La descripción de los jumpers:

• Programming Jumper: La programación de la placa sólo es posible si este jumper está

colocado.

• RSSI Enable Jumper: Si el jumper está colocado, está habilitada la función de indicación

por leds de RSSI.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

33

• Hibernate Enable Jumper: Si el jumper no está colocado, deshabilitamos la

programación de Waspmote. El modo de funcionamiento Hibernate requiere quitar

este jumper durante el comienzo del programa por primera vez.

3.1.1.3.- Arquitectura y sistema del Waspmote

La arquitectura de Waspmote se basa en el microcontrolador ATMEGA 1281 de Atmel. Esta

unidad de procesado arranca ejecutando el “bootloader” que se dedica a cargar en memoria

los programas compilados y almacenados previamente en la memoria FLASH, con la finalidad

de que el programa principal que se ha creado pueda finalmente comenzar su ejecución o

espera 62 ms antes de ejecutar la primera instrucción por si se da el caso de que se estuviera

cargando un nuevo programa compilados.

Una vez que tenemos un programa cargado en el microcontrolador, el funcionamiento de

Waspmote se basa en el código que se ha cargado. La estructura de los códigos se divide en 2

partes fundamentales: un parte denominada setup y una parte llamada loop. Ambas partes del

código tienen un comportamiento secuencial, ejecutándose las instrucciones en el orden

establecido.

• La parte llamada setup es la primera parte del código que se ejecuta, haciéndolo sólo

una vez al iniciar el código. En esta parte es recomendable incluir la inicialización de los

módulos que se vayan a utilizar, así como parte del código que sólo interesa que se

ejecute al iniciarse Waspmote.

• La parte denominada loop es un bucle que se ejecuta continuamente, formando un

bucle infinito. Debido al comportamiento de esta parte del código es recomendable la

utilización de las interrupciones para realizar acciones con Waspmote.

En el código de los programas también se pueden declarar otras funciones las cuales sólo se

ejecutarán cuando sean llamadas por el código incluido en la parte de setup o loop.

Cuando Waspmote es reseteado o encendido desde el estado OFF el código comienza de

nuevo desde la función setup y posteriormente la función loop.

3.1.1.4.- Modos de funcionamientos del Waspmote

Waspmote tiene cuatro modos de funcionamiento, según la imagen siguiente (figura 25):

• ON: modo normal de funcionamiento. El consumo en este estado es de 9mA.

• Sleep: El programa principal se detiene, el microcontrolador pasa a un estado de

latencia, del que puede ser despertado por todas las interrupciones asíncronas y por la

interrupción síncrona generada por el Watchdog. El intervalo de duración de este

estado va de 32ms a 8s. El consumo en este estado es de 62μA.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

34

Figura 25: Modo funcionamiento sleep.

• Deep Sleep: El programa principal se detiene, el microcontrolador pasa a un estado de

latencia del que puede ser despertado por todas las interrupciones asíncronas y por la

interrupción síncrona lanzada por el RTC. El intervalo de este ciclo puede ir de 8

segundos a minutos, horas, días. El consumo en este estado es de 62μA.

Figura 26: Modo funcionamiento deep sleep

• Hibernate: El programa principal se detiene, el microcontrolador y todos los módulos

de Waspmote quedan completamente desconectados. La única forma de volver a

activar el dispositivo es a través de la alarma previamente programada en el RTC

(interrupción síncrona). El intervalo de este ciclo puede ir de 8 segundos a minutos,

horas, días. Al quedar el dispositivo totalmente desconectado de la batería principal el

RTC es alimentado a través de una batería auxiliar de la que consume 0,7μA.

Figura 27: Modo funcionamiento hibernate

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

35

Consumo Micro Ciclo

ON 9mA ON - Sleep 62μA ON 32ms - 8s Deep Sleep 62μA ON 8s - min/horas/días Hibernate 0,7μA OFF 8s - min/horas/días

Tabla 1: Consumo del waspmote en diferentes estados de funcionamiento.

3.1.1.5.- Entorno de desarrollo del Waspmote

El IDE (Integrated Development Environment) utilizado para programar Waspmote que se va a

utilizar es el compilador de la plataforma Arduino, siguiendo el mismo estilo de librerías y

funcionamiento.

El IDE-Waspmote incluye todas las librerías del API necesarias para compilar los programas.

El compilador IDE - Waspmote se divide en cuatro partes fundamentales que se pueden ver en

la siguiente figura 28.

Figura 28: Partes del IDE - Waspmote.

• La primera parte es el menú donde se permite la configuración de parámetros generales como el puerto serie seleccionado.

• La segunda parte es un menú de botones que permiten compilar, abrir, guardar o cargar en la placa el código seleccionado.

• La tercera parte contiene el código principal que se cargará en Waspmote y la cuarta parte nos muestra los posibles errores de compilación o carga, así como los mensajes de éxito si el proceso se lleva a cabo satisfactoriamente.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

36

El panel de botones del IDE - Waspmote permite realizar ciertas funciones como abrir un

código previamente guardado, crear uno nuevo o cargar el código en la placa. En la siguiente

figura 29 se puede ver el panel y las funciones de cada botón.

Figura 29: Panel de botones del IDE - Waspmote.

Una vez que se ha abierto correctamente el programa se debe cambiar alguna configuración

para que se carguen correctamente los programas en Waspmote.

En la pestaña ‘Tools/Board’ se debe seleccionar la placa Waspmote. Para ello se selecciona la

opción ‘Wasp v01’.

En la pestaña ‘Tools/Serial Port’ se debe seleccionar el USB en el que se ha conectado

Waspmote al ordenador.

Una vez que se tiene configurados estos dos parámetros podemos cargar un programa en

Waspmote.

El siguiente paso es cargar el programa en Waspmote. Para ello se debe tener conectado el

mote mediante el USB al ordenador y pinchar en el botón ‘upload’. Al pinchar en este botón,

se empezará a compilar el programa. Cuando el programa se ha compilado correctamente

aparece un mensaje en la parte inferior de la ventana indicando este suceso. Si por el contrario

se produce algún fallo, aparecerán mensajes de color rojo indicando los fallos en el código.

Cuando se ha terminado de compilar, se procede a cargar el código en Waspmote.

Cuando el programa se haya cargado correctamente aparece un mensaje en la ventana de

Waspmote indicando ‘Done Uploading’. Si por el contrario se produce algún problema durante

la carga aparecerán mensajes de color rojo indicando los fallos durante la carga.

3.1.1.6.- Librerías de código para Waspmote

Libelium tiene desarrollado una API (Application Programming Interface) para facilitar la

programación de aplicaciones utilizando Waspmote. Esta API engloba todos los módulos que

se integran en Waspmote, así como el manejo de otras funcionalidades como las

interrupciones o los diferentes estados energéticos. La API se ha desarrollado en C/C++.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

37

3.1.2.- Descripción del Transceptor

3.1.2.1.- Módulos de comunicación inalámbrica

Para la interfaz de comunicación inalámbrica, Waspmote integra los módulos XBee de Digi en

bandas de frecuencia libre ISMB (Industrial Scientific Medical Band).

Existen siete posibles módulos XBee distribuidos por Libelium para su integración con

Waspmote, y son los siguientes que aparecen en la tabla 2.

Modelo Protocolo Frecuencia txPower Sensibilidad Rango

XBee-802.15.4 802.15.4 2.4GHz 1mW -92dB 500m XBee-802.15.4-Pro 802.15.4 2.4GHz 100mW -100dBm 7000m XBee-ZB ZigBee-Pro 2.4GHz 2mW -96dBm 500m XBee-ZB-Pro ZigBee-Pro 2.4GHz 50mW -102dBm 7000m XBee-868 RF 868MHz 315mW -112dBm 12km XBee-900 RF 900MHz 50mW -100dBm 10Km XBee-XSC RF 900MHz 100mW -106dBm 12Km

Tabla 2: Módulos XBee de Digi que son compatibles con waspmote.

Por otra parte, el módulo transceptor elegido es el siguiente: XBee – ZB – PRO - series 2.

Debido que es el que ha ofrecido el departamento para la realización de este trabajo.

Modelo Protocolo Frecuencia txPower Sensibilidad Rango*

XBee-ZB-Pro ZigBee-Pro 2.4GHz 50mW -102dBm 7000m

Tabla 3: Módulos XBee de Digi que se va a usar en el proyecto.

Una imagen de dicho chipset es la siguiente:

Figura 30: Panel de botones del IDE - Waspmote.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

38

Los módulos XBee-ZB cumplen con el estándar ZigBee-PRO v2007 que define hasta la capa de

aplicación, permitiendo gestionar al completo una red. A las funcionalidades aportadas por

ZigBee, los módulos XBee añaden ciertas funcionalidades como:

• Descubrimiento de nodos: se añaden unas cabeceras de forma que se pueden

descubrir otros nodos dentro de la misma red. Permite enviar un mensaje de

descubrimiento de nodos, de forma que el resto de nodos de la red responden

indicando sus datos (Node Identifier, @MAC, @16 bits, RSSI).

• Detección de paquetes duplicados: Esta funcionalidad no se establece en el estándar y

es añadida por los módulos XBee.

3.1.2.2.- Configuración de los tranceptores Digi

Por otra parte tenemos otra herramienta para la configuración de los dispositivos

transceptores utilizados por waspmote que son del fabricante Digi.

Antes de empezar con la configuración del módulo XBee tenemos que instalar el programa X-

CTU. Aunque existen más programas en el mercado para la configuración del XBee, hemos

escogido este porque es el que utiliza el fabricante, la firma Digi International.

Para llevar a cabo este procedimiento, se tiene que usar el adaptador a usb (gateway) que

proporciona libelium.

Una vez, que se tiene montado el módulo Xbee en el adaptador usb de libelium, se enchufa

éste al PC. El programa X-CTU reconocerá el puerto al cual esté asociado, tal y como aparece

en la figura 31:

Figura 31: Panel de configuración del X-CTU.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

39

A continuación, después de añadir el dispositivo, se debe señalar en la ventana "Select Com

Port", seleccionamos Enable API, y se pulsa el botón "Test/Query" para saber el firmware, la

versión y la dirección MAC del XBee. Aparecerá una ventana como la que se muestra en la

siguiente imagen (Figura 32):

Figura 32: Comprobación de firmware del módulo XBee.

Una vez comprobado la versión del firmware del módulo XBee, se actualizará y/o se

configurará éste si procede. (Antes de nada hay que configurar los parámetros para la

comunicación serie que aparecen en la derecha de la imagen anterior, tal y como están en la

figura 32).

Una vez comprobado lo anterior, procedemos a la actualización del Firmware de los módulos

XBee. Para cambiar de firmware, hay que enchufar el adaptador usb sin montar el módulo

XBee. Luego se selecciona la pestaña "Modem Configuration” y en el recuadro de la izquierda

donde aparece “Modem:” se elige el protocolo que soporta el módulo XBee, en el recuadro del

medio “Function Set” se escoge la función de dicho módulo y el firmware se selecciona en el

recuadro de la derecha donde aparece “Version” eligiendo la que se quiere en ese momento.

Una vez realizado todo esto, se pulsa el botón Write y esperamos a que aparezca una ventana

que nos indica que se realice un reset. Se pulsa el botón reset y se mantiene pulsado hasta que

se monte la pastilla XBee el adaptador usb.

Por otra parte, para llevar a cabo la configuración de los módulos XBee, en el programa X-CTU

se selecciona la pestaña "Modem Configuration” y se configuran parámetros teniendo en

cuenta si es COORDINATOR, ROUTER o END DEVICES.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

40

En nuestro caso se tienen cuatro módulos XBee los cuales están configurados uno como

COORDINATOR API (XBP24-ZB, versión 2164) y los otros tres como ROUTER API (XBP24-ZB

versión 2364). A continuación se mostrarán los parámetros que se le han grabado a cada uno.

• Configuración del COORDINATOR API (XBee con dirección MAC: 0013A2004060758E)

Este módulo se ha configurado con los siguientes parámetros:

Networking

PAN ID 102030405060708

Scan Channel 1FFE

Scan Duration 3

ZigBee Stack Profile 0

Node Join Time FF

Addressing

Destination Address High 0

Destination Address Low FFFF

RF Interfacing

Power Level 4

Power Mode 1

Security

Encryption Enable Disabled

Serial Interfacing

Baude Rate 5

Parity 0

Stop Bits 0

DIO7 Configuration 1

DIO6 Configuration 0

API Enable 2

API Output Mode 0

Tabla 4: Configuración del módulos XBee coordinator

Todos los demás parámetros se dejan con el valor que tienen por defecto

• Configuración del ROUTER API (XBee con dirección MAC =

00:13:A2:00:40:60:75:DA/E3/DF)

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

41

Estos dos módulos se han configurado con los siguientes parámetros:

Networking

PAN ID 102030405060708

Scan Channel 1FFE

Scan Duration 3

ZigBee Stack Profile 0

Node Join Time FF

Addressing

Destination Address High 0

Destination Address Low 0

RF Interfacing

Power Level 4

Power Mode 1

Security

Encryption Enable Disabled

Serial Interfacing

Baude Rate 5

Parity 0

Stop Bits 0

DIO7 Configuration 1

DIO6 Configuration 0

API Enable 2

API Output Mode 0

Tabla 5: Configuración del módulos XBee router.

Todos los demás parámetros se dejan con el valor que tienen por defecto.

3.1.3.- Topología de la Red

En esta red de sensores inalámbricos se hace uso del protocolo 802.15.4, y por lo tanto, las

topologías en las que se pueden usar estos módulos son: estrella y árbol.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

42

Para nuestro caso se usa una topología de red en estrella, donde solo aparece un coordinator y

tres router (Figura 33). La razón por la que se usa esta topología, es porque toda la información

que se recoge desemboca en el coordinator y se pasa directamente a un PC.

Figura 33: topología en estrella Coordinator-Router.

• Coordinator: El dispositivo que realiza la función de Coordinator permitirá obtener los

datos que circulan por la red sensorial en un PC o dispositivo con un puerto USB

estándar, a través de Waspmote Gateway (Figura 34).

Figura 34: Módulo XBee montado en un Waspmote Gateway y conectado a un PC.

Que actuará como un “puente de datos o puerta de acceso” entre la red sensorial y el

equipo receptor. Este equipo receptor se encargará de almacenar o utilizar los datos

recibidos en función de las necesidades de la aplicación en concreto (Es el objetivo del

proyecto).

• Router: Estos dispositivos que realizan la función de Router recogerán toda la

información del medio a través de sus sensores y enviará estos datos al dispositivo que

realiza la función de Gateway.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

43

Figura 35: Waspmotes como router enviando información al Gateway conectado a un PC.

3.2.- Elección de herramientas y requisitos para el desarrollo de una aplicación para Windows de adquisición y gestión de datos

En cuanto a herramientas para desarrollar una aplicación software con el propósito que

conlleva este proyecto, existe gran diversidad de lenguajes de programación convenientes

para que funcionen bajo Windows. Tanto C como C++ son lenguajes de programación de

propósito general. Todo puede programarse con ellos, desde sistemas operativos y

compiladores hasta aplicaciones de bases de datos y procesadores de texto, pasando por

juegos, aplicaciones a medida, etc.

Para un desarrollo más fácil de aplicaciones Windows aparecieron herramientas de desarrollo

visual, cuyos exponentes más conocidos son Borland Delphi, de Inprise, y Visual Basic, de

Microsoft.

La escritura de aplicaciones con herramientas de este tipo se basa en el uso de componentes o

controles prefabricados. Así, la creación de la interfaz de usuario deja de ser un trabajo tedioso

y el programador puede centrarse en el núcleo del programa. Estos entornos de desarrollo

visual también facilitan operaciones habituales en Windows, como la comunicación con otras

aplicaciones, el uso de cuadros de diálogo comunes, la gestión de bases de datos, etc. Cada

elemento de un programa, sea visual o no, viene representado por un componente.

Para el fin de este proyecto, la herramienta de desarrollo visual que se va a utilizar es Visual

C#.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

44

Se ha escogido el lenguaje C#, ya que, Visual C# .NET es un lenguaje de programación seguro y

orientado a objetos, que combina la potencia de Visual C y Visual C++ con la sencillez funcional

de las herramientas de desarrollo de aplicaciones modernas y rápidas, permitiendo desarrollar

software .NET para Microsoft Windows, la web y un gran rango de dispositivos. Posee una

sintaxis que se asemeja a C++, un entorno de desarrollo flexible (IDE) y ofrece la posibilidad de

desarrollar soluciones para una gran gama de plataformas y dispositivos.

La interfaz de usuario debe proveer la funcionalidad necesaria para una buena comunicación

entre el hombre y la máquina. Un buen diseño agiliza el uso de una aplicación, tanto al

visualizar aquella información más importante, como al realizar aquellas tareas más habituales

con sólo unos pocos clicks de ratón. El diseño de la interfaz debe realizarse de manera que esta

resulte simple e intuitiva de utilizar.

Lo primero que deberá realizar la aplicación será establecer, de forma totalmente

transparente al usuario, una tubería para obtener los datos del dispositivo. Para ello se han

utilizado un conjunto de funciones que permiten comunicarse con el periférico (wapsmote) a

través del puerto serie. Una vez se empieza a recibir datos desde la wsn se procesan los

paquetes y se muestra por un monitor creado en la aplicación que muestra la información de

los paquetes de las distintas motas, de forma ordenada y clasificada.

Otras funcionalidades que deberá implementar la aplicación una vez que obtiene la

información será:

• Generar y mostrar gráficas con los datos capturados por los waspmotes.

• Mostrar en todo momento los parámetros del enlace de comunicación de la red.

Generar un fichero con todos los datos de la captura realizada.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

45

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

46

4.- Implementación de Red Sensores Inalámbrica mediante

Waspmote

4.1. – Solución Adoptada

Como solución se ha optado por tres nodos de red y un gateway Waspmote del fabricante

Libelium y sus correspondientes módulos XBee PRO Series 2 de Digi (ya descrita en el apartado

3.1).

Estos tres nodos se han configurado para que ahorren el máximo de energía posible para

recoger información de los nodos durante el mayor periodo de tiempo posible y enviarla al

Gateway, y éste a su vez mandarla a la aplicación del PC a través de puerto serie.

Debido a que estamos usando la primera versión Waspmote v1.1 de Libelium, tenemos unas

limitaciones al configurar en modo ahorro (Deep Sleep) una mota. Al usar el waspmote en

modo de funcionamiento Deep Sleep, el nodo puede entrar en modo activo despertándolo con

cualquier interrupción que se le programe de las librerías que aporta Libelium. Pero nunca se

podrá despertar mediante una interrupción que genere el módulo XBee indicando que ha

recibido un paquete desde el coordinador. Ya que, en la versión Waspmote v1.1 no se ha

implementado esta función.

Por este motivo, no se ha implementado la comunicación bidireccional entre una mota de la

WSN y la aplicación que recoge toda la información de la red de sensores inalámbrica.

Por lo tanto, se ha decido que la red de sensores solo envíe la información recogida al

coordinador y éste a su vez se la pase a la aplicación del PC diseñada a tal propósito.

De este modo tendremos monitorizado toda la información que se recoge del medio donde

esté alojada la red de sensores.

4.1.1.- Tipos de tramas de comunicación

Los módulos XBee de Digi tienen un protocolo para comunicarse con los dispositivos

Waspmote o con cualquier otro dispositivo, llamado API Operation. Esto consiste en enviar un

formato de trama a través de la UART de la siguiente manera:

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

47

Figura 36: Formato Trama de tranceptores de Digi.

En la figura 36 se puede observar que la trama está compuesta por un campo que ocupa un

byte y desempeña la función de delimitador indicando el comienzo de una trama (carácter

0x7E). Seguidamente aparece un campo de dos bytes que indica la longitud que tendrá el

campo precedido que es el Frame Data (No incluye el Checksum). Seguidamente al campo de

longitud aparece el campo Frame Data, dónde irá almacenado la información de la trama al

completo y por último el campo Chesksum que ocupa un byte.

El campo Frame Data está formado por el cmdID que ocupa un byte e indica el tipo de mensaje

que llevará el campo siguiente cmdData. El cmdData contiene el mensaje que se envía en la

trama.

En la siguiente tabla se puede observar los diferentes tipos de mensajes que se pueden utilizar:

API Frame Names API ID

AT Command 0x08

AT Command – Queue Parameter Value 0x09

ZigBee Transmit Resquet 0x10

Explicit Addressing ZigBee Command Frame 0x11

Remote Command Request 0x17

Create Source Route 0x21

AT Command Response 0x88

Modem Status 0x8A

ZigBee Transmit Status 0x8B

ZigBee Receive Packet (AO=0) 0x90

ZigBee Explicit Rx Indicator (AO=1) 0x91

ZigBee IO Dta Sample Rx Indicator 0x92

XBee Sensor Read Indicator (AO=0) 0x94

Node Identification Indicator (AO=0) 0x95

Remote Command Response 0x97

Over-the-Air Firmware Update Status 0xA0

Route Record Indicator 0xA1

Many-to-One Route Request Indicator 0xA3

Tabla 6: Valores y nombres de las API Frame.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

48

Las tramas que se van usar para la comunicación entre los nodos y la aplicación para el usuario

serán las siguientes: AT Command (0x08) y AT Command Response (0x88), para la

comunicación entre la aplicación del PC y el dispositivo coordinador de la red de sensores

inalámbrica que hace la función de gateway; Zigbee Transmit Request (0x10) y ZigBee Receive

Packet (0x90), se utilizarán para el envío de tramas de datos desde los nodos de la red a la

aplicación que recopila la información que recoge la WSN.

• Las tramas AT Command y AT Command Response, se utilizan para conocer los

parámetros de la red mediante la comunicación por puerto serie entre la aplicación del

PC y el coordinador. Estas tramas tiene el siguiente formato.

AT Command

Campos de la Trama Tamaño Ejemplo Descripción

Start Delimiter 1 Byte 0x7E Indicador de comienzo de trama. Length 2 Byte 0x00, 0x04 Números de bytes entre el campo Length y Checksum.

Frame Type 1 Byte 0x08 Tipo de trama Frame ID 1 Byte 0x52 Subsecuencia para comunicación entre host y device. Si es

0 no se envía ACK. AT Command 2 Byte 0x43 (C)

0x48 (H) Nombre del comando. Dos caracteres ASCII para identificar el AT Command

Parameter Value (Opcional)

Si no presenta parámetro indica que el comando es para lectura de dicho parámetro. Si no es para establecerlo

Checksum 1 Byte 0x0D Es la operación 0xFF – la suma de todos los byte entre Length y Checksum.

Tabla 7: Trama AT Command.

Los comandos que se utilizan en este proyecto son los siguientes:

ü CH (0x43, 0x48): Este comando de dos caracteres ASCII, se llama Operating

Channel y sirve para leer el número del canal usado en la red para transmitir y

recibir.

ü DB (0x44, 0x42): Este comando representa el RSSI Received Signal Strength. Y

se utiliza para obtener la intensidad de señal recibida del último paquete

recibido.

ü OP (0x4F, 0x50): Este comando se utiliza para saber el Operating Extended

PAN ID que se está usando en la red. Para este comando hay que poner a 0 el

campo de trama Parameter Value para hacer la lectura.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

49

AT Command Response

Campos de la Trama Tamaño Ejemplo Descripción

Start Delimiter 1 Byte 0x7E Indicador de comienzo de trama.

Length 2 Byte 0x00, 0x06 Números de bytes entre el campo Length y Checksum. Frame Type 1 Byte 0x88 Tipo de trama

Frame ID 1 Byte 0x01 Subsecuencia para comunicación entre host y device. Si es 0 no se envía ACK.

AT Command 2 Byte 0x44 (D) 0x42 (B)

Nombre del comando. Dos caracteres ASCII para identificar el AT Command

Command Status

1 Byte

0x00

0 = OK 1 = ERROR 2 = Invalid Command 3 = Invalid Parameter 4 = Tx Failure

Command Data En este campo aparece el dato que se ha requerido. Si no presenta parámetro es porque en la trama AT Command se estableció.

Checksum 1 Byte 0xA1 Es la operación 0xFF – la suma de todos los byte entre Length y Checksum.

Tabla 8: Trama AT Command Response.

• Las tramas Zigbee Transmit Request y ZigBee Receive Packet, se utilizarán para el envío

de tramas de datos desde los nodos de la red a la aplicación que recopila la

información que recoge la WSN.

Zigbee Transmit Request

Campos de la Trama

Tamaño Ejemplo Descripción

Start Delimiter 1 Byte 0x7E Indicador de comienzo de trama. Length 2 Byte 0x00, 0x16 Números de bytes entre el campo Length y Checksum.

Frame Type 1 Byte 0x10 Tipo de trama Frame ID 1 Byte 0x01 Subsecuencia para comunicación entre host y device. Si es 0 no se

envía ACK. 64-bit Destination Address

8 Byte

0x00,0x13,0xA2,0x00, 0x40,0x60,0x75,0xDA

Se establece la dirección MAC del dispositivo destino. También se pueden poner las siguientes direcciones: 0x0000000000000000 coordinator y 0x000000000000FFFF Broadcast

16-bits Destination Address

2 Byte

0xFF, 0xFE

Se establece la dirección de red si es conocida o 0xFFFE que es la dirección de broadcast

Broadcast Radius

1 Byte

0x00

Establece el número de saltos permitidos del paquete. Si es 0 se establece el máximo números de saltos.

Options

1 Byte

0x00

Opciones para la Tx 0x20 - Habilita APS 0x40 - Usa el tiempo máximo Tx

RF Data N Bytes Campo para introducir los datos que se quieren enviar

Checksum 1 Byte 0x0D Es la operación 0xFF – la suma de todos los byte entre Length y Checksum.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

50

Tabla 9: Trama Zigbee Transmit Request.

En el campo de trama para introducir los datos podemos incluir las siguientes subtramas para

introducir los datos que se quieren enviar:

ü Trama de Datos: Como bien indica su nombre en esta trama se empaquetan los

datos recogidos por los sensores del Waspmote, como la temperatura del RTC, la

posición que indica el acelerómetro, el nivel de batería y la secuencia de la trama.

(Los campos vacíos son espacios).

Ejemplo de trama de Datos en el campo RF Data x : -262 , y : -138 , z : 1023 t e m p : 18 b a t : 59 n : 1

Tabla 10: Formato Trama de Datos.

ü Trama Indicación Batería Baja: Esta trama avisa al usuario a través de la aplicación

que nodo se está quedando sin energía, para que se pueda llevar a cabo el cambio

de batería. (Los campos vacíos son espacios).

Ejemplo de trama de Batería Baja en el campo RF Data

S i n b a t e r i a

Tabla 11: Formato Trama de Indicación Batería Baja.

ü Trama Indicación Nodo Caído: Esta trama avisa al usuario a través de la aplicación

que nodo se ha caído de donde estaba instalado (ya sea un mástil o alguna

estructura en la cual el nodo esté a un nivel por encima del suelo) para que se

pueda llevar a cabo la reinstalación del nodo. (Los campos vacíos son espacios).

Ejemplo de trama de Nodo Caído en el campo RF Data H e c a i d o

Tabla 12: Formato Trama de Indicación Nodo Caído.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

51

ZigBee Receive Packet

Campos de la Trama

Tamaño Ejemplo Descripción

Start Delimiter 1 Byte 0x7E Indicador de comienzo de trama. Length 2 Byte 0x00, 0x11 Números de bytes entre el campo Length y Checksum.

Frame Type 1 Byte 0x90 Tipo de trama 64-bit Destination Address

8 Byte

0x00,0x13,0xA2,0x00, 0x40,0x60,0x75,0xDA

Se establece la dirección MAC del dispositivo destino. También se pueden poner las siguientes direcciones: 0x0000000000000000 coordinator y 0x000000000000FFFF Broadcast

16-bits Destination Address

2 Byte

0x7D, 0x84

Se establece la dirección de red si es conocida o 0xFFFE que es la dirección de broadcast

Receive Options

1 Byte

0x01

0x01 - Packet Acknowledged 0x02 - Packet was a broadcast packet 0x20 - Packet encrypted with APS encryption

Receive Data N Bytes Campo de los datos que se reciben

Checksum 1 Byte 0x0D Es la operación 0xFF – la suma de todos los byte entre Length y Checksum.

Tabla 13: Trama ZigBee Receive Packet.

En el campo Receive Data de la trama explicada en la tabla anterior se obtienen las subtramas

de Indicación Nodo Caído, Trama Indicación Batería Baja y Trama de Datos.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

52

4.1.2.- Diagrama de estados de los nodos Waspmote

En la siguiente figura se puede observar un esquema del diagrama de estados que cumple los

nodos waspmote que componen la red de sensores inalámbrica:

Figura 37: Diagrama de estado de un nodo Waspmote.

Ahora se irá explicando cada estado de dicho diagrama.

• Estado 0: En este estado se declaran una serie de variables y se utilizan unas funciones

que ya vienen declaradas de las librerías de waspmote para inicializar y establecer los

módulos a usar de la placa waspmote de Libelium y del tranceptor de XBee de Digi. Se

inicializa el RTC, el acelerómetro y el módulo que mide la energía, así como sus

interrupciones. Además se inicializa el XBee .

• Estado 1: En este estado se implementa la activación de la interrupción tanto de los

módulos acelerómetro, RTC y Batería Baja.

En este estado el Waspmote permanece dormido el tiempo establecido (50 segundos),

una vez que se despierta, trata las interrupciones que hayan ocurrido. Las

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

53

interrupciones se pueden dar porque venza el temporizador establecido por el RTC, si

hay caída libre o si la batería es baja.

En este estado, se respecta el tiempo del temporizador, una vez que que este vence se

chequean las banderas de interrupción que se hayan activados y se tratan una a una

las interrupciones.

• Estado 2: En el estado 2, se entra cuando el temporizador vence, es decir, cuando el

RTC lanza una interrupción. Se procesan los datos de los sensores, se monta una trama

de datos y se envían y se vuelve al estado 1.

• Estado 3: Al estado 3 se accede en el momento que se detecta que la bandera de

interrupción correspondiente al acelerómetro se activa por una caída libre del nodo.

Se ensambla una trama de aviso de que el nodo ha caído y se envía al coordinador

volviendo al estado 1.

• Estado 4: El estado número 4, corresponde al estado en el que se activa la bandera de

interrupción debida al aviso de batería baja. Cuando se da esta situación se ensambla

una trama de aviso de batería baja identificando al nodo que le corresponde y se envía

al coordinador volviendo al estado 1.

4.1.3.- Código utilizado en los Waspmote

El código que ha se utilizado para programar los nodos de la red de sensores inalámbrica es el

siguiente:

#define THRESHOLD 2.2

packetXBee* paq_sent;

int secuencia=0;

char aux[250];

//Parámetros de configuración para crear una red

uint8_t PANID[8]={0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};

//Dirección mac del coordinator

uint8_t direccion[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

void setup()

{

//Encendemos RTC

RTC.ON();

RTC.setTime("00:00:00:00:00:00:00");

//Encendemos Accelerometro

ACC.ON();

//Establecemos interrupción de batería baja

PWR.setLowBatteryThreshold(THRESHOLD);

enableInterrupts(BAT_INT);

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

54

//Inicialización XBee ZigBee

xbee.init(ZIGBEE,FREQ2_4G,NORMAL);

//Encendemos XBee

xbee.ON();

}

void loop()

{

//Establecimiento de interrupcion de caida libre

ACC.setFF();

//Va a dormir desconectando todos los modulos despues de 13 segundos, Waspmote despierta gracias a la alarma del RTC

PWR.deepSleep("00:00:00:13",RTC_OFFSET,RTC_ALM1_MODE5,ALL_OFF);

//Encendemos RTC de nuevo

RTC.ON();

//Despues de despertar se chequean las banderas de interrupcion

treatInterrupt();

}

//Función para realizar el chequeo de las interrupciones ocurridas

void treatInterrupt()

{

//Waspmote despierta cuando la alarma RTC vence

if( intFlag & RTC_INT )

{

despierta_modulo_xbee();

//Realizamos el proceso para enviar una trama compactamos los datos que vamos a enviar

sprintf(aux," x:%d,y:%d,z:%d temp:%d bat:%d n:%d "

,ACC.getX(),ACC.getY(),ACC.getZ(),RTC.getTemperature(),PWR.getBatteryLevel(),secuencia);

//Enviar trama

send_frame(aux);

//Incrementa la secuncia de trama de datos

secuencia=secuencia+1;

//Limpiamos la interrupcion

intFlag &= ~(RTC_INT);

}

// Waspmote despierta cuando accelerometro detecta caida libre

if( intFlag & ACC_INT )

{

despierta_modulo_xbee();

//Realizamos el proceso para enviar una trama de aviso de caiída o movimiento del mote

sprintf(aux," He caido ");

//Enviar trama

send_frame(aux);

//Limpiamos la interrupcion

intFlag &= ~(ACC_INT);

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

55

}

//Waspmote despierta cuando la bateria es baja

if( intFlag & BAT_INT )

{

disableInterrupts(BAT_INT);

despierta_modulo_xbee();

//Realizamos el proceso para enviar una trama de aviso de caiída o movimiento del mote

sprintf(aux," Sin bateria ");

//Enviar trama

send_frame(aux);

//Limpiamos la interrupcion

intFlag &= ~(BAT_INT);

}

}

//Función para enviar un paquete

void send_frame(char *aux)

{

//Montamos el paquete a enviar

paq_sent=(packetXBee*) calloc(1,sizeof(packetXBee));

paq_sent->mode=UNICAST;

paq_sent->MY_known=0;

paq_sent->packetID=0x52;

paq_sent->opt=0;

xbee.hops=0;

xbee.setDestinationParams(paq_sent, direccion, aux, MAC_TYPE, DATA_ABSOLUTE);

//Enviamos el paquete

xbee.sendXBee(paq_sent);

free(paq_sent);

paq_sent = NULL;

}

//Función para despertar al módulo XBee

void despierta_modulo_xbee()

{

//Inicializamos XBee ZigBee

xbee.init(ZIGBEE,FREQ2_4G,NORMAL);

//Encendemos XBee

xbee.ON();

delay(150);

xbee.wake();

delay(13000);

}

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

56

En el código aparecen los siguientes elementos

• En la primera parte del código, se realiza la declaración de variables globales como el paquete que se va a usar, la secuencia y un array auxiliar para montar los paquetes, así como el umbral de nivel de tensión para definir el estado de batería baja.

• El siguiente bloque que nos encontramos el setup donde se inicializan y establecen los periféricos que se van a utilizar, como el RTC, el acelerómetro, el nivel de aviso de batería baja y el trancesptor.

• En el bloque loop se implementa el objetivo del código que sería dormir al waspmote durante un tiempo y una vez despierto comprobar si se ha dado alguna interrupción, y mandar un paquete de datos.

• La función void treatInterrupt() tratamiento de interrupciones, comprueba la interrupción que se da en eesa iteración del código y ejecuta lo que proceda.

• Función de envio de trama. Esta función como su nombre indica procesa la información que corresponde, ensambla un paquete y lo envía.

• Función que despierta el módulo XBee. Esta función inicia al XBee después de haber sido despertado el waspmote.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

57

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

58

5.- DESCRIPCIÓN FUNCIONAL Y DE IMPLEMENTACIÓN DEL

SOFTWARE

La interfaz de usuario debe proveer la funcionalidad necesaria para una buena comunicación

entre el hombre y la máquina. Un buen diseño agiliza el uso de una aplicación, tanto al

visualizar aquella información más importante, como al realizar aquellas tareas más habituales

con sólo unos pocos clicks de ratón. El diseño de la interfaz debe realizarse de manera que esta

resulte simple e intuitiva de utilizar.

Lo primero que deberá realizar la aplicación será establecer, de forma totalmente

transparente al usuario, una tubería para obtener los datos del dispositivo. Para ello Microsoft

.NET contiene una clase con un conjunto de funciones que manejan el puerto serie y que

permiten comunicarse con el Waspmote coordinador a través de una interfaz serie. Una vez se

tienen datos de la red de sensores inalámbrica WSN (temperatura, posición y nivel de batería)

se quiere que la aplicación muestre continuamente dichos datos.

Otras funcionalidades que deberá implementar la aplicación son:

• Mostrar los datos obtenidos a través de la WSN.

• Capturar datos, creando un fichero que los contenga.

• Mostrar información relevante como el estado de la red y de sus nodos

• Generar y mostrar gráficas con los datos capturados.

5.1.- Organización del software en C#

En este apartado se describe de forma funcional la organización del software. Primero se

describe de forma general el diagrama de flujos y después el diagrama de clases que gobiernan

el comportamiento de la aplicación que tomará y procesará los datos de la red de sensores

inalámbrica.

5.1.1.- Diagrama de flujo

El funcionamiento general de la aplicación software viene descrito por el diagrama de flujos de

la figura 38. A continuación se describe el funcionamiento de dicha aplicación.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

59

Figura 38: Diagrama de Estados General

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

60

Ahora se pasa a realizar una explicación del diagrama de flujo de la figura 38.

La aplicación comienza en el punto inicio donde se abre y carga la aplicación, se configura el

puerto serie de comunicación y se abre dicho puerto. Inmediatamente después se comprueba

que el puerto no esté cerrado. Si este está cerrado, se queda esperando hasta que este sea

abierto.

En el caso de que no está cerrado se pasa al siguiente estado donde se montan cuatro tramas

de control para saber el estado de la red de sensores inalámbrica. Una vez que han sido

montadas se pasa al estado donde se envían dichas tramas.

Una vez que han sido enviadas dichas tramas pasamos al estado de escucha del puerto. En

este punto se chequea si se ha cerrado el puerto, si no es así se vuelve al estado de escucha. Si

por el contrario se decide cerrar el puerto, se pasa al estado de finalización del puerto y se

cierra la aplicación finalizando el programa.

En el caso de que no se decida cerrar el puerto, se comprueba si hay actividad de recepción. Si

no hubiera ninguna actividad se continuaría en dicho estado hasta que se recibiera algo.

Cuando el programa detecta actividad en el puerto de comunicación, parsea la trama y analiza

el paquete que se ha recibido. Una vez analizado, se comprueba si dicha trama es buena, si no

fuese así, se volvería al estado de escucha del puerto serie descartando la trama recibida.

En el caso que la trama es buena, se volvería a realizar otra comprobación para clasificar la

trama en un paquete de datos o de control.

En el caso de que la trama fuese de datos, se obtendrían los campos de interés y se pasarían a

la interfaz gráfica (GUI) que aplicaría a la información de datos de la aplicación para que el

usuario pudiera apreciarla.

Por otra parte, si la trama recibida fuera de control, está información se pasarían a la interfaz

gráfica (GUI) que aplicaría a la información de control de la red de la aplicación, para que el

usuario pudiera observarla.

Una vez, llegado al punto donde se pasa la información a la GUI se volvería al estado de

escucha del puerto.

5.1.2.- Diagrama de clases El funcionamiento general de la aplicación software viene descrito por el diagrama de flujos de

la figura 39. A continuación se describe cada estado así como sus transiciones.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

61

Figura 39: Diagrama de clases de la App.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

62

5.1.3.- Instalador de la App

Para la aplicación diseñada se le ha creado un instalador para que sea más cómoda la

distribución de este software.

Lo primero que hay que realizar es agregar un nuevo proyecto a la solución que tenemos. Para

ello, hacemos click con el botón derecho en la solución en el explorador de soluciones y se

selecciona Agregar > Nuevo proyecto.

Figura 40: Pantalla Visual Studio.

Al hacer esto se mostrará la siguiente pantalla (Figura 41) para elegir un nuevo proyecto y se

selecciona un proyecto en: Otros Tipos de proyectos > Instalación e Implementación >

Instalador de Visual Studio > Proyecto de Instalación. El nombre del proyecto de Setup es

Setup_UGM (Utilidad de Gestión de Motas).

Figura 41: Menú Agregar proyecto Visual Studio.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

63

Al seleccionar el nuevo proyecto se mostrará la pantalla siguiente (Figura 42):

Figura 42: Menú de archivos solución Setup.

En esta figura 42 se ve un árbol de exploración que es el “Sistema de archivos en el equipo de

destino”, esto se puede visualizar como el equipo en donde se va a instalar nuestra aplicación

la cual muestra tres carpetas las cuales se explican a continuación.

• Carpeta de Aplicación: Aquí se colocan todos los archivos necesarios para que nuestra

aplicación pueda correr. Es decir, el resultado principal de la aplicación desarrollada en

C#, más el icono que representa a dicha solución y el documento de ayuda para la

aplicación.

• Escritorio del Usuario: Se coloca todo lo que se necesita que aparezca en el Escritorio

del Usuario Final: Aquí solo se coloca el acceso directo a la solución desarrollada en C#.

• Menú Programas del Usuario: Aquí se coloca el acceso directo a la solución

desarrollada. Lo que se pone en este lugar se muestra en “Inicio > Todos los

programas” del equipo de final.

Se selecciona y se hace click en Carpeta de Aplicación > Agregar > Resultados del Proyecto,

como en la figura 43.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

64

Figura 43: Propiedades de archivos solución Setup.

Nos aparecerá la siguiente pantalla figura 44.

Figura 44: Menú para agregar el resultado del proyecto.

Y se selecciona lo que se va a colocar en la Carpeta de la Aplicación que en este caso es el

Resultado Principal que contiene los archivos DLL y EXE generados por el proyecto que se ha

creado.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

65

Con esto ya está lista la carpeta de aplicación. Ahora se configura la Carpeta Escritorio del

Usuario en la cual se agrega un acceso directo al Resultado Principal de la aplicación (exe).

Se selecciona la Carpeta Escritorio del usuario y se hace un click derecho en la parte central de

la pantalla y se selecciona “Crear acceso nuevo acceso directo” tal como se muestra en la

pantalla siguiente (figura 45):

Figura 45: Menú de la carpeta de escritorio.

Al hacer esto aparece la siguiente pantalla (figura 46) que es para escoger que va hacer

referencia al nuevo acceso directo.

Figura 46: Menú para seleccionar elemento en el proyecto.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

66

Para lo cual se selecciona la carpeta de la aplicación y se elige Resultado Principal de la

Aplicación, después se pulsa en aceptar.

Hecho esto se edita el Acceso Directo y se le cambia el nombre y el icono que se mostrará. Por

último se selecciona la Carpeta Menú Programas del Usuario y se hace un click derecho en ella

y se selecciona Agregar > Carpeta, esto se hace para agregar una nueva carpeta para que

aparezca en Todos los programas del usuario final.

Figura 47: Menú de la carpeta menú de programas.

Se le cambia el nombre a la carpeta creada recientemente a Utilidad Gestión Consola, se

selecciona y pulsando con el botón derecho en la parte central de la pantalla para agregar

nuevamente un acceso directo tal y como se hizo en la Carpeta Escritorio del Usuario.

Después de se realiza lo mismo que se realizó en la Carpeta Escritorio del Usuario y se

configura el acceso directo para que haga referencia al Resultado Principal del Proyecto.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

67

Figura 48: Menú para seleccionar elemento en el proyecto.

Ya se tiene configurado que archivos van incluidos en el instalador.

Ahora queda configurar el proyecto setup para que pueda ser instalado en cualquier equipo

Windows. Para ello, en el explorador de soluciones se selecciona el proyecto de instalación y

se accede a sus propiedades.

Después de hacer esto aparecerá la siguiente pantalla (figura 49), y se pulsa sobre el botón

requisitos previos de la instalación.

Figura 49: Páginas de propiedades de Setup_UGM.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

68

Haciendo click en Requisitos Previos, aparecerá la siguiente pantalla (figura 50) en donde se

especificará cuáles son los requerimientos que necesita la aplicación para funcionar en el

equipo de destino.

Los requisitos que se ha escogidos para esta aplicación son las siguientes:

• .Net Framework 4 (x86 y x64).

• .Net Framework 3.5 SP1.

• Windows Installer 3.1 y 4.5.

Figura 50: Requisitos previos del proyecto Setup_UGM.

Hasta aquí se ha terminado de configurar el proyecto de instalación.

Al final se genera el archivo de setup. Es importante señalar que generar el archivo de setup es

diferente a generar la solución, este se tiene que hacer de forma separada, para esto

seleccionamos Generar > Generar Setup_UGM.

Ya generado el setup lo podemos encontrar en la carpeta “.Setup_UGM\Debug” ahí se

encuentran dos elementos de setup del proyecto de instalación, uno es .exe y el otro es .msi y

funcionan de la misma manera.

Se puede acceder directamente a estos archivos para probar el instalador.

Se ejecuta el Instalador, que ha quedado de la siguiente forma:

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

69

Figura 51: Instalador de la aplicación Utilidad Gestión Motas.

Figura 52: Directorio donde se alojará la aplicación.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

70

Figura 53: Confirmación de la instalación.

Figura 54: Instalando Utilidad de gestión de motas.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

71

Figura 55: Instalación completada.

Figura 56: Icono de la aplicación Utilidad Gestión Motas.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

72

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

73

6.- CONCLUSIONES Haciendo recapitulación del documento, vemos cómo se ha detallado el completo funcionamiento de la aplicación desarrollada y de la red de sensores implementada. También se han introducido los conceptos teóricos en los que se basa el desarrollo de esta aplicación y se ha dado una visión cercana del conjunto del código de la aplicación. En el apartado final del documento también se han esbozado las posibles líneas futuras de desarrollo del proyecto que, espero, no acaben aquí. No obstante, el autor del mismo está sopesando el liberar la aplicación con el fin de que la aplicación pueda seguir creciendo, desarrollándose y siendo de utilidad a cualquier usuario que lo necesite. A modo de curiosidad, en el desarrollo de esta aplicación se han invertido los siguientes tiempos:

Concepto Días efectivos Horas/día media Total horas

Desarrollo aplicación

115 2 230

Memoria 32 1 32

Total global - - 262

Tabla 14: Horas invertidas.

En caso de realizar el encargo del desarrollo del proyecto al completo a un ingeniero de

nuestra empresa, el coste del mismo hubiese sido el siguiente:

Concepto Horas Coste horas Total coste

Desarrollo aplicación 230 19 € 4370 €

Memoria 32 19 € 608 €

Total global - - 4978 €

Tabla 15: Coste del proyecto.

(Coste horas teniendo en cuenta que el salario mínimo de un ingeniero s/ convenio de Oficinas

Técnicas es de 25600 €/año y el calendario anual consta de 1800 horas. Costes laborales +30%

de seguridad social.)

En todo proyecto se marcan unos requisitos mínimos y un plazo de ejecución que tienen que cumplirse. En este proyecto, dados los requisitos y el plazo de ejecución, se han implementado todos los requisitos pero no han permitido extenderse demasiado en añadir extras.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

74

A continuación se detallan alguno de estos extras para su posterior inclusión como ampliación de este proyecto, bien a través de PFC o bien a través de desarrollo por terceros de esta aplicación.

• Implementación de más sensores como gps para saber la localización terrestre de cada elemento de la red de sensores inalámbrica.

• Implementación de un enlace de actuación sobre la red de sensores inalámbrica, ya que no se ha podido implementar de forma sencilla debido a las prestaciones en hardware limitadas de la primera versión de Waspmote de Libelium.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

75

7.-Bibliografía

[1] Digi International Inc. “XBee®/XBee-PRO® ZB RF Modules”, Manual, ZibgBee RF Modules by

Digi International.

[2] Qilian Liang, Wei Wang, Jiasong Mu, Jing Liang, Baoju Zhanfg, Yiming Pi, Chenglin Zhao.

“Communications, Signal Processing, and Systems”, The 2012 Proceedings of the International

Conference on Communications, Signal Processing, and Systems. PART III. Springer 2012.

[3] Yingshu Li, My T. Thai, Weili Wu. “Wireless Sensor Networks and Applications”, Springer

2008.

[4] Subhas Chandra Mukhopadhyay, Joe-Air Jiang. “Wireless Sensor Networks and Ecological

Monitoring”. Springer 2013.

[5] Faisal Karim Shaikh, Bhawani Shankar Chowdhry, Habib M. Ammari, Muahammad Aslam

Uqaili, Asadullah Shah. “Wireless Sensor Networks for Developing Countries”. First

International Conference, WSN4DC 2013 Jamshoro, Pakistan. Springer April 2013.

[6] IEEE Std 802.15.1-2005 – IEEE Standard for Information technology – Telecommunications

and information exchange between systems – Local and metropolitan area networks – Specific

requirements Part 15.1: Wireless Medium Access Control (MAC) and Physical Layer (PHY)

Specifications for Wireless Personal Area Networks (W Pans)

[7] IEEE 802.11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY)

Specifications.

[8] IEEE 802.15.4-2006 IEEE Standard for Information technology--Telecommunications and

information exchange between systems--Local and metropolitan area networks-- Specific

requirements Part 15.4: Wireless Medium Access Control (MAC) and Physical Layer (PHY)

Specifications for Low Rate Wireless Personal Area Networks (LR-WPANs)

[10] ZigBee Alliance. http://www.zigbee.org/

[11] HART Communications Foundation. http://www.hartcomm.org/

[12] UC Berkeley Smart Dust Project. www.dustnetworks.com

[13] IEEE International Conference on Pervasive Computing and Communications. San Diego –

California – Marzo 18-22, 2013. http://www.percom.org/2013/

[14] Delin, Kevin. "Sensor Webs in the Wild". Wireless Sensor Networks: A Systems

Perspective. Artech House. 2005.

[15] Libelium. “Waspmote Guía Técnica”. Versión del documento: v1.6 - 08/2011 © Libelium

Comunicaciones Distribuidas S.L.

[16] Microsoft .NET Framework. http://www.microsoft.com/net/

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

76

[17] Douglas Bell, Mike Parr. “C# para estudiantes”, Naucalpan de Juárez. Pearson Educación

2011.

[18] Ceballos Sierra, Francisco Javier. “Microsoft C#: curso de programación”, Paracuellos del

Jarama (Madrid). Ra-Ma, 2006.

[19] Helbert Schildt. “Fundamentos de C# 3.0”, México D.F. McGraw-Hill 2010.

[20] http://www.digi.com

[21] http://www.xbow.com/

[22] http://www.btnode.ethz.ch/

[23] http://www.sunspotworld.com/

[24] http://nanork.org/

[25] http://www.arduino.cc/

[26] http://www.libelium.com/es/

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

77

APÉNDICE A: AYUDA APLICACIÓN “Utilidad gestión motas”

Este documento sirve de guía al usuario para utilizar la aplicación. Se hará una explicación paso

a paso de desde el inicio de la aplicación hasta el que el usuario desee cerrarla.

Una vez la aplicación Utilidad gestión motas ha sido instalada la abrimos y aparecerá una

interfaz como la que se muestra en la figura 57:

Figura 57: Interfaz gráfica de la aplicación Utilidad Gestión Motas.

Se puede observar que el puerto está cerrado. Antes que nada, configuramos la aplicación

para el funcionamiento. Establecemos el número de eventos que queremos capturar antes de

mostrar por pantalla. Es decir, elegimos el número de tramas que se quieren obtener antes de

comenzar la captura, como aparece en la figura 58:

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

78

Figura 58: Elección de eventos de captura.

Lo siguiente que habría que hacer es clickear en el menú configuración y establecer la

comunicación con el puerto serie. Esto se puede ver en la siguiente imagen (figura 59):

Figura 59: Configuración de puerto serie.

Una vez configurado el puerto serie, lo siguiente es pulsar en Archivos->Nueva captura.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

79

Figura 60: Activación de la aplicación para comenzar la captura.

En la figura 61 se puede ver una primera captura de información de la red de sensores

inalámbricos. Donde aparece una ventana con tantas pestañas como nodos detectados en la

red, así como la pestaña llamada general donde aparece la información de todas las motas,

según el orden de llegada. En la pestaña General tenemos la columna Mota origen,

Temperatura, Nivel batería, Localización y Secuencia. Además al pie de la pestaña General

aparece información relevante sobre los parámetros del enlace con la red inalámbrica de

sensores y del número total de tramas recibidas.

Figura 61: Captura de información de la red de sensores inalámbrica.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

80

En las pestañas referentes a una mota en particular, se puede encontrar la siguiente

información: la Dirección MAC, Temperatura, Nivel de batería, Localización y Secuencia.

Además de la cantidad de tramas recibidas por dicha mota.

Se puede ver en la siguiente imagen (figura 62):

Figura 62: Campos de la trama de datos de la red de sensores.

Más arriba si se pulsa sobre la pestaña Histórico aperecerán unas gráficas que representan la

temperatura (la de la izquierda) y el nivel de batería (la de la derecha). Se puede observar en la

figura 63:

Figura 63: Gráficas de representación de temperatura y nivel de batería.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

81

Otra peculiaridad que ofrece la aplicación, es que cuando ocurre un evento en la red tal que

una mota tiene poco nivel de batería o se ha caído de donde está ubicada aparece un símbolo

de warning en la parte inferior de la pestaña General dentro de la pestaña Monitor, indicando

que ha ocurrido un evento de información, como se puede observa en la figura 64:

Figura 64: Aviso de warning.

Para saber que ha ocurrido hay que clickear sobre la pestaña Información y aparecerá el

mensaje de información correspondiente a evento ocurrido. Se puede ver mostrado en la

siguiente imagen (figura 65):

Figura 65: Información del warning.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

82

Si queremos conseguir un fichero log tenemos que clickear en Archivo->Generar archivo log.

Figura 66: Generación de un fichero log.

Y aparecerá la opción de guardar un archivo excel con toda la información recogida de la red

de sensores inalámbricos. Se puede ver en las siguientes dos imágenes (figura 67 y 68):

Figura 67: Confirmación para generar un fichero log.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

83

Figura 68: Fichero Excel con todas las tramas recogidas.

Una vez generado el fichero excel que recoge todas las tramas recopiladas por la aplicación se

finaliza la captura de información de la red. Y podemos limpiar lo que aparece en la pantalla

pulsando Archivo->Limpiar elementos. En la figura 69 se puede observar:

Figura 69: Limpieza de la información en la interfaz gráfica de la aplicación.

Para acceder al manual de ayuda de dicha aplicación hay que pulsar Ayuda->Sobre … aparecerá

una ventana emergente con información del diseñador además de un botón ayuda que si es

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

84

pulsado se abrirá un documento indicado paso a paso cómo funciona la aplicación. Se puede

observar en la siguiente imagen (figura 70):

Figura 70: Opción de ayuda de la aplicación.

Por otra parte la aplicación contiene otra utilidad que es un terminal de comunicación serie

para visualizar mensajes. Clickando en Configuración>Utilidad consola aparecerá la siguiente

aplicación:

Figura 71: Aplicación consola.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

85

APÉNDICE B: DIAGRAMAS DE CLASES

Figura 72: Diagrama de clases de la App

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

86

APÉNDICE C: CÓDIGO DE LA APLICACIÓN EN C#

En este apéndice se mostrará el código realizado por el diseñador en los archivos que contiene

la solución del proyecto en Visual Studio.

Program.cs

using System;

using System.Collections.Generic;

using System.Windows.Forms;

namespace SimpleSerial

{

static class Program

{

/// <summary>

/// El punto principal de entrada para la aplicación.

/// </summary>

[STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new Gateway());

}

}

}

Gateway.cs

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Threading;

using System.IO.Ports;

using System.Windows.Forms.DataVisualization.Charting;

using SerialPortListener.Serial;

using SerialPortListener;

using System.IO;

using Microsoft.Office.Interop.Excel;

using Microsoft.Office.Core;

using System.Diagnostics;

using System.Runtime.InteropServices;

using System.Reflection;

namespace SimpleSerial

{

/// <summary>

/// Clase que contiene la parte principal de la aplicación donde se maneja el puerto serie de la recepción de los datos de

/// las motas, el tratamiento, identificación y clasificación de los datos recibidos, las generación de un fichero EXCEl

/// con los datos registrados, y la gestión de las motas de la wireless sensor networks.

/// </summary>

public partial class Gateway : Form

{

#region Definiciones variables

List<string> elementosSinFiltrar;

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

87

List<Trama> tramasSesionActual;

List<Trama> conjuntoTramasTotalesIdentificadas;

Dictionary<string, Mota> motasDetectadasSesion;

WriteMota gestorEscrituraMota;

PropiedadesEnlace propiedadesEnlace;

double valorActualGrafica_x = 0;

DatosPuerto datosPuertoActual;

SerialPortManager _spManager;

ushort contadorEventos = 0;

ushort contadorEventosInterno = 0;

List<char[]> bufferCaracteresRecibidos;

bool vistaActualGrafica = false;

public event EventHandler<ModificacionConjuntoMotas> NuevaModificacionConjuntoMotas;

public List<DatosGrafica> ultimoDatosGrafica;

DatosGrafica datosGraficaActualDelegado;

List<string> listaNombresGrafica;

List<InformacionMensajes> infoMensajes;

#region Variables Excel

Microsoft.Office.Interop.Excel.Application objetoExcel;

Microsoft.Office.Interop.Excel.Workbooks conjuntoLibros;

Microsoft.Office.Interop.Excel.Workbook libro;

Microsoft.Office.Interop.Excel.Sheets hojas;

Microsoft.Office.Interop.Excel.Worksheet hojaActual;

Microsoft.Office.Interop.Excel.CellFormat celdaActual;

#endregion

#region Delegados

Delegate delegadoImpresion;

Delegate delegadoInsercionNuevasTabs;

Delegate delegadoEstadoPuerto;

Delegate delegadoLimpiezaForm;

Delegate actividadPuerto;

Delegate delegadoInclusionElementoGrafica;

Delegate impresionGrafica;

Delegate impresionPropiedadesEnlace;

Delegate avisoInformacionEnlace;

Trama tramaActualImpresion = null;

string tituloNuevaMota;

TabPage tabMotaNuevaDetectada;

bool estadoDelPuerto = false;

bool flagActividadPuerto = false;

#endregion

#endregion

#region Carga y descarga de la aplicacion

public Gateway()

{

InitializeComponent();

this.elementosSinFiltrar = new List<string>();

this.conjuntoTramasTotalesIdentificadas = new List<Trama>();

this.tramasSesionActual = new List<Trama>();

motasDetectadasSesion = new Dictionary<string, Mota>();

actividadPuerto = Delegate.CreateDelegate(typeof(System.EventHandler), this, "metodoDelegadoLedAcividad");

gestorEscrituraMota = new WriteMota();

this.propiedadesEnlace = new PropiedadesEnlace();

this.datosPuertoActual = new DatosPuerto();

this.bufferCaracteresRecibidos = new List<char[]>();

this.ultimoDatosGrafica = new List<DatosGrafica>();

this.listaNombresGrafica = new List<string>();

this.infoMensajes = new List<InformacionMensajes>();

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

88

#region Delegados

delegadoImpresion = Delegate.CreateDelegate(typeof(System.EventHandler), this,

"metodoDelegadoImpresionPantallaPrincipal_Secundarias");

delegadoInsercionNuevasTabs = Delegate.CreateDelegate(typeof(System.EventHandler), this,

"metodoDelegadoInsercionNuevaMota");

delegadoEstadoPuerto = Delegate.CreateDelegate(typeof(System.EventHandler), this, "metodoDelegadoEstadoPuerto");

delegadoLimpiezaForm = Delegate.CreateDelegate(typeof(System.EventHandler), this, "metodoDelegadoLimpiezaForm");

delegadoInclusionElementoGrafica = Delegate.CreateDelegate(typeof(System.EventHandler), this,

"metodoDelegadoInclusionElementoGrafica");

impresionGrafica = Delegate.CreateDelegate(typeof(System.EventHandler), this, "metodoDelegadoImpresionGrafica");

impresionPropiedadesEnlace = Delegate.CreateDelegate(typeof(System.EventHandler), this,

"metodoDelegadoImpresionPropiedadesEnlace");

avisoInformacionEnlace = Delegate.CreateDelegate(typeof(System.EventHandler), this, "metodoAvisoInformacionEnlace");

#endregion

puertoSerieToolStripMenuItem.DropDownItemClicked += new

ToolStripItemClickedEventHandler(puertoSerieToolStripMenuItem_DropDownItemClicked);

velocidadBaudiosToolStripMenuItem.DropDownItemClicked += new

ToolStripItemClickedEventHandler(velocidadBaudiosToolStripMenuItem_DropDownItemClicked);

NuevaModificacionConjuntoMotas += new

EventHandler<ModificacionConjuntoMotas>(Form1_NuevaModificacionConjuntoMotas);

}

/// <summary>

/// Método para cerrar la App tanto pulsando la "x" como seleccionando salir.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento FormClosingEventArgs.</param>

private void Form1_FormClosing(object sender, FormClosingEventArgs e)

{

if (serialPort1.IsOpen)

serialPort1.Close();

}

/// <summary>

/// Método llamado al cargar la aplicación. Contendrá funcionalidad de inicialización.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs</param>

private void Form1_Load(object sender, EventArgs e)

{

if (serialPort1.IsOpen)

{

this.label7.Text = "Abierto";

}

else

{

this.label7.Text = "Cerrado";

}

this.pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;

this.pictureBox1.Image = this.imageList1.Images[0];

this.estadoDelPuerto = false;

this.comboBox1.SelectedIndex = 3;

var elemento = this.comboBox1.Items[3];

int numIntentosSelected = 0;

Int32.TryParse(elemento.ToString(), out numIntentosSelected);

this.contadorEventos = (ushort)numIntentosSelected;

}

#endregion

#region Recepcion de trama por puerto serie

/// <summary>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

89

/// Función que recoge el flujo de datos que entra por el puerto serie.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento erialDataReceivedEventArgs.</param>

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)

{

flagActividadPuerto = true;

this.Invoke(actividadPuerto);

this.contadorEventosInterno++;

char[] tramaRecibida = new char[this.serialPort1.BytesToRead];

for (int i = 0; i < tramaRecibida.Length; i++)

{

tramaRecibida[i] = (char)this.serialPort1.ReadByte();

}

//Se almacena en el buffer el contenido de la trama recibida, para liberar rápidamente al gestor

this.bufferCaracteresRecibidos.Add(tramaRecibida);

if (this.contadorEventosInterno >= this.contadorEventos && !this.backgroundWorker1.IsBusy)

{

this.contadorEventosInterno = 0;

this.backgroundWorker1.RunWorkerAsync();

}

}

#endregion

#region Delegados de impresion

/// <summary>

/// Imprime por pantalla de la App el aviso de warning de un mota.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoAvisoInformacionEnlace(object sender, EventArgs e)

{

foreach (InformacionMensajes info in this.infoMensajes)

{

string str;

str = DateTime.Today.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + " MAC origen: " + info.dirMac + ";

Mensaje: " + info.tipoMensaje.ToString() + "\n\r";

this.textBoxMensajes.AppendText(str + "\n");

}

this.infoMensajes.Clear();

infoProvider.SetError(this.labelInformacion, "Eventos de información de enlace.");

}

/// <summary>

/// Limpia los datos registrados en la pestaña general donde se registra los datos recibidos de la WSN.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoLimpiezaForm(object sender, EventArgs e)

{

foreach (TabPage tabla in tabControl2.TabPages)

{

if (!tabla.Text.Equals("General"))

{

DataGridView vista = (DataGridView)tabla.Controls[0];

vista.Rows.Clear();

}

}

}

/// <summary>

/// Muestra en en la App parámetros del enlace de comunicación de la WSN.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

90

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoImpresionPropiedadesEnlace(object sender, EventArgs e)

{

// Se actualizan todos los elementos relacionados con el enlace

if (this.propiedadesEnlace.RSSI == 0)

{

this.label5.Text = this.propiedadesEnlace.RSSI.ToString() + " dBm";

}

else

{

this.label5.Text = "- " + this.propiedadesEnlace.RSSI.ToString() + " dBm";

}

this.label12.Text = this.propiedadesEnlace.canal.ToString();

this.label13.Text = this.propiedadesEnlace.motasPendientes.ToString();

this.label10.Text = this.propiedadesEnlace.PANID;

}

/// <summary>

/// Plasma los datos de una mota en la pestañas correspondiente a dicha mota.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoImpresionPantallaPrincipal_Secundarias(object sender, EventArgs e)

{

if (this.tramasSesionActual.Count > 0)

this.limpiarElementosToolStripMenuItem.Enabled = true;

Mota[] motas = new Mota[10];

this.motasDetectadasSesion.Values.CopyTo(motas, 0);

Mota motaActual = null;

this.motasDetectadasSesion.TryGetValue(this.tramaActualImpresion.direccionOrigen, out motaActual);

string nombreMota = "Unknown";

if (motaActual != null)

nombreMota = motaActual.nombreMota;

this.dataGridView_hojaPrincipal.Rows.Add(nombreMota, this.tramaActualImpresion.temperatura.ToString(),

this.tramaActualImpresion.nivelBateria.ToString(), this.tramaActualImpresion.coordenada.ToString(),

this.tramaActualImpresion.secuencia.ToString());

int cont = 0;

foreach (Mota mota in this.motasDetectadasSesion.Values)

{

cont += (ushort)mota.listaTramasSesionActual.Count;

}

this.textBox2.Text = cont.ToString();

this.dataGridView_hojaPrincipal.FirstDisplayedScrollingRowIndex = this.dataGridView_hojaPrincipal.Rows.Count - 1;

this.dataGridView_hojaPrincipal.Refresh();

ushort indice = 0;

foreach (TabPage tabla in tabControl2.TabPages)

{

if (!tabla.Text.Equals("General"))

{

motaActual = motas[indice];

DataGridView vista = (DataGridView)tabla.Controls[0];

foreach (Trama trama in motaActual.listaTramasSesionActual)

{

if (!trama.flagTramaMostrada)

{

vista.Rows.Add(motaActual.direccionMAC, trama.temperatura.ToString(), trama.nivelBateria.ToString(),

trama.coordenada.ToString(), trama.secuencia.ToString());

trama.flagTramaMostrada = true;

}

}

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

91

tabla.Controls[1].Text = motaActual.listaTramasSesionActual.Count.ToString();

vista.Refresh();

indice++;

}

}

}

/// <summary>

/// Muestra el estado del puerto serie en la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoEstadoPuerto(object sender, EventArgs e)

{

string texto = string.Empty;

texto = (estadoDelPuerto ? "Abierto" : "Cerrado");

this.label7.Text = texto;

}

/// <summary>

/// Añade pestañas como motas detectadas en la WSN con la información recolectada de cada mota.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoInsercionNuevaMota(object sender, EventArgs e)

{

#region Grid

tabMotaNuevaDetectada.UseVisualStyleBackColor = true;

DataGridView nuevoGrid = new DataGridView();

nuevoGrid.Size = new Size(555, 150);

nuevoGrid.Location = new System.Drawing.Point(40, 27);

nuevoGrid.ColumnCount = 5;

nuevoGrid.ColumnHeadersVisible = true;

// Set the column header style.

DataGridViewCellStyle columnHeaderStyle = new DataGridViewCellStyle();

FontFamily fm = this.label1.Font.FontFamily;

columnHeaderStyle.BackColor = Color.Beige;

columnHeaderStyle.Font = new System.Drawing.Font(fm, this.label1.Font.Size, System.Drawing.FontStyle.Regular);

nuevoGrid.ColumnHeadersDefaultCellStyle = columnHeaderStyle;

nuevoGrid.RowHeadersVisible = false;

// Set the column header names.

nuevoGrid.Columns[0].Name = "Dirección MAC";

nuevoGrid.Columns[0].MinimumWidth = 145;

nuevoGrid.Columns[0].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[0].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[1].Name = "Temperatura";

nuevoGrid.Columns[1].MinimumWidth = 100;

nuevoGrid.Columns[1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[1].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[2].Name = "Nivel bateria";

nuevoGrid.Columns[2].MinimumWidth = 100;

nuevoGrid.Columns[2].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[2].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[3].Name = "Localizacion";

nuevoGrid.Columns[3].MinimumWidth = 120;

nuevoGrid.Columns[3].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[3].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[4].Name = "Secuencia";

nuevoGrid.Columns[4].MinimumWidth = 120;

nuevoGrid.Columns[4].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;

nuevoGrid.Columns[4].HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;

tabMotaNuevaDetectada.Controls.Add(nuevoGrid);

System.Windows.Forms.TextBox cajaTexto = new System.Windows.Forms.TextBox();

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

92

cajaTexto.Size = new System.Drawing.Size(74, 20);

cajaTexto.Location = new System.Drawing.Point(430, 195);

tabMotaNuevaDetectada.Controls.Add(cajaTexto);

System.Windows.Forms.Label etiqueta = new System.Windows.Forms.Label();

etiqueta.Text = "Total número de tramas:";

etiqueta.Location = new System.Drawing.Point(303, 198);

etiqueta.Size = new System.Drawing.Size(121, 13);

tabMotaNuevaDetectada.Controls.Add(etiqueta);

#endregion

tabControl2.TabPages.Add(tabMotaNuevaDetectada);

}

/// <summary>

/// Se ilumina un led en la App indicando la actividad del puerto serie - rojo inactivo, verde activo.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoLedAcividad(object sender, EventArgs e)

{

if (flagActividadPuerto)

{

this.pictureBox1.Image = this.imageList1.Images[1];

}

else

{

//Thread.Sleep(1000);

this.pictureBox1.Image = this.imageList1.Images[0];

}

}

#endregion

#region Tratamientos

/// <summary>

/// Se realiza el primer filtrado de paquetes que se reciben por el puerto serie delimitando el comienzo y el final

/// de cada paquete.

/// </summary>

/// <param name="tramaRecibidaByte">Contiene un flujo de datos recibidos por el puerto serie.</param>

/// <param name="elementosSinFiltrar">Lista que almacena las tramas identificadas en el flujo de datos

/// tramaRecibidaByte.</param>

public void primerTratamientoDatosRecibidos(char[] tramaRecibidaByte, List<string> elementosSinFiltrar)

{

char[] trama1 = tramaRecibidaByte;

string trama = string.Empty;

trama = trama1.ToString();

for (int i = 0; i < trama1.Length; i++)

{

trama += trama1[i];

}

try

{

while (true)

{

int primerIndice = trama.IndexOf('~') + 1;

if (!(trama.Length < primerIndice + 1) && primerIndice != -1)

{

// Se delimita por el principio de la trama y se elimina

// hasta el byte que indica la longitud del paquete

trama = trama.Substring(primerIndice + 1);

int segundoIndice = 0;

// Se delimita el final de cada trama si procede

segundoIndice = trama.IndexOf('~');

// Se comprueba si se recibe un flujo de tramas o solo una

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

93

if (segundoIndice != -1)

{

// Se substrae del flujo un paquete

string candidata = trama.Substring(0, segundoIndice);

elementosSinFiltrar.Add(candidata);

trama = trama.Substring(segundoIndice);

}

else

{

elementosSinFiltrar.Add(trama);

break;

}

}

else

break;

}

}

catch (ArgumentException exc)

{

}

}

/// <summary>

/// Se realiza un segundo filtrado identificando si las tramas recibidas son de datos, de control o de información.

/// </summary>

/// <param name="elementosSinFiltrar">Lista que almacena las tramas identificadas en el flujo de datos

/// tramaRecibidaByte.</param>

/// <param name="listaTramasSesionActual">Lista que almacena los tipos de tramas identificadas como datos en

/// elementosSinFiltrar.</param>

private void segundoTratamientoDatosRecibidos(List<string> elementosSinFiltrar, List<Trama> listaTramasSesionActual)

{

try

{

foreach (string datosEnBruto in elementosSinFiltrar)

{

int longitud_trama = Convert.ToByte(datosEnBruto[0]);

int FrameType = Convert.ToByte(datosEnBruto[1]);

//Comprobamos que es una trama de Datos

if ((longitud_trama > 35) && (FrameType == 0x90))

{

Trama tramaNueva = this.identificaAtributosTrama(datosEnBruto);

if (tramaNueva.esTramaValida())

{

this.tramasSesionActual.Add(tramaNueva);

// Se identifican a las nuevas motas

if (!this.motasDetectadasSesion.ContainsKey(tramaNueva.direccionOrigen))

{

string nombreMota = "Mota" + (motasDetectadasSesion.Values.Count + 1).ToString("00");

this.motasDetectadasSesion.Add(tramaNueva.direccionOrigen, new Mota(tramaNueva.direccionOrigen,

nombreMota));

tituloNuevaMota = nombreMota;

tabMotaNuevaDetectada = new TabPage(tituloNuevaMota);

this.Invoke(delegadoInsercionNuevasTabs);

}

// Añado a la nueva mota la trama recibida:

Mota motaActual;

this.motasDetectadasSesion.TryGetValue(tramaNueva.direccionOrigen, out motaActual);

if (motaActual != null)

motaActual.listaTramasSesionActual.Add(tramaNueva);

if (this.propiedadesEnlace.propiedadesEnlaceCapturadas)

{

this.gestorEscrituraMota.WriteTramaControl(WriteMota.TramasControl.RSSI);

Thread.Sleep(500);

this.Invoke(impresionPropiedadesEnlace);

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

94

}

}

}

//Comprobamos que es una trama de Info

if (((longitud_trama < 35) && (longitud_trama > 17)) && (FrameType == 0x90))

{

Trama_Info tramaInfoNueva = this.identificaAtributosTramaInfo(datosEnBruto);

if (tramaInfoNueva.esTramaInfoValida())

{

bool evento = false;

if (tramaInfoNueva.info1.Equals("He caido"))

{

evento = true;

this.infoMensajes.Add(new

InformacionMensajes(InformacionMensajes.TipoMensaje.Caido,tramaInfoNueva.direccionOrigen));

}

if (tramaInfoNueva.info2.Equals("Sin bateria"))

{

evento = true;

this.infoMensajes.Add(new

InformacionMensajes(InformacionMensajes.TipoMensaje.Bateria,tramaInfoNueva.direccionOrigen));

}

if(evento)

this.Invoke(avisoInformacionEnlace);

}

}

//Comprobamos que es una trama de Control

if ((longitud_trama < 10) && (FrameType == 0x88))

{

Trama_Control tramaControlNueva = this.identificaAtributosTramaControl(datosEnBruto);

if (tramaControlNueva.esTramaControlValida())

{

this.propiedadesEnlace.lecturaCanalCapturada |= Trama_Control.Equals(tramaControlNueva,

WriteMota.TramasControl.Canal);

this.propiedadesEnlace.lecturaMotasPendientesCapturada |= Trama_Control.Equals(tramaControlNueva,

WriteMota.TramasControl.MotasPendientesUnion);

this.propiedadesEnlace.lecturaRSSI |= Trama_Control.Equals(tramaControlNueva,

WriteMota.TramasControl.RSSI);

if ((this.propiedadesEnlace.lecturaCanalCapturada)&&((tramaControlNueva.ATCommand[0] ==

'C')&&(tramaControlNueva.ATCommand[1] == 'H')))

{

this.propiedadesEnlace.canal = tramaControlNueva.CommandData;

this.Invoke(impresionPropiedadesEnlace);

}

if ((this.propiedadesEnlace.lecturaMotasPendientesCapturada)&&((tramaControlNueva.ATCommand[0] ==

'N')&&(tramaControlNueva.ATCommand[1] == 'C')))

{

this.propiedadesEnlace.motasPendientes = tramaControlNueva.CommandData;

this.Invoke(impresionPropiedadesEnlace);

}

if ((this.propiedadesEnlace.lecturaRSSI) && ((tramaControlNueva.ATCommand[0] == 'D') &&

(tramaControlNueva.ATCommand[1] == 'B')))

{

this.propiedadesEnlace.RSSI = tramaControlNueva.CommandData;

this.Invoke(impresionPropiedadesEnlace);

}

}

}

//Comprobamos que es una trama de Control1

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

95

if (((longitud_trama < 17) && (longitud_trama > 10)) && (FrameType == 0x88))

{

Trama_Control1 tramaControl1Nueva = this.identificaAtributosTramaControl1(datosEnBruto);

if (tramaControl1Nueva.esTramaControl1Valida())

{

this.propiedadesEnlace.lecturaPANIDCapturada |= true;

this.propiedadesEnlace.PANID = tramaControl1Nueva.CommandData1;

this.Invoke(impresionPropiedadesEnlace);

}

}

this.propiedadesEnlace.propiedadesEnlaceCapturadas |= this.propiedadesEnlace.lecturaPANIDCapturada &&

this.propiedadesEnlace.lecturaCanalCapturada && this.propiedadesEnlace.lecturaMotasPendientesCapturada;

}

}

catch (IndexOutOfRangeException ex)

{

}

}

/// <summary>

/// Capta los campos importantes de la trama de datos y lo pasa a los tab que y a las gráficas de la App.

/// </summary>

/// <param name="tramasSesionActual">Lista que almacena los tipos de tramas identificadas como datos en

/// elementosSinFiltrar.</param></param>

/// <param name="tramasSesion">Lista que almacena los datos identificados en las tramas de datos.</param>

private void tercerTratamientoDatosRecibidos(List<Trama> tramasSesionActual, List<Trama> tramasSesion)

{

this.ultimoDatosGrafica.Clear();

// Se añaden al historico las nuevas

tramasSesionActual.ForEach(t => tramasSesion.Add(t));

// Tengo que añadir tan solo aquellos ultimos eventos de grafica

foreach(Trama trama in this.tramasSesionActual)

{

Mota mota;

this.motasDetectadasSesion.TryGetValue(trama.direccionOrigen, out mota);

if (mota != null)

{

this.ultimoDatosGrafica.Add(new

DatosGrafica(trama.temperatura,trama.fechaRx,trama.nivelBateria,mota.nombreMota));

}

}

NuevaModificacionConjuntoMotas(this, new ModificacionConjuntoMotas(this.ultimoDatosGrafica));

}

#endregion

#region Identificación Tramas

/// <summary>

/// Identifica una trama de datos.

/// </summary>

/// <param name="datosBruto">Elemento de la lista elementosSinFiltrar</param>

/// <returns>Devuelve OK si es una trama de datos.</returns>

Trama identificaAtributosTrama(string datosBruto)

{

try

{

string direccionOrigen;

string direccionOrigen_Aux= string.Empty;

string direccionOrigen_Aux1 = string.Empty;

Punto3D coordenada;

float temperatura;

float nivelBateria;

int secuencia;

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

96

string[] datos1 = datosBruto.Split(' ');

direccionOrigen = datos1[0].Substring(2, 8);

char[] charValue = direccionOrigen.ToCharArray();

//tenemos los 8 bytes de la direccion mac uno por uno.

foreach (char letter in charValue)

{

// Convierte el numero expresado en base-16 a un entero.

byte value = Convert.ToByte(letter);

// Toma el caracter correspondiente a valor entero.

string stringValue = String.Format("{0:X2}",value);

direccionOrigen_Aux = direccionOrigen_Aux + ":" + stringValue;

}

direccionOrigen_Aux1 = direccionOrigen_Aux.Substring(1, 23);

coordenada = new Punto3D(datos1[1]);

temperatura = (float)Convert.ToDouble(datos1[2].Split(':')[1]);

nivelBateria = (float)Convert.ToDouble(datos1[3].Split(':')[1]);

secuencia = (int)Convert.ToInt16(datos1[4].Split(':')[1]);

return new Trama(DateTime.Now, direccionOrigen_Aux1, coordenada, temperatura, nivelBateria, secuencia);

}

catch (Exception)

{

}

return new Trama(DateTime.Now,"Error", new Punto3D(), 0, 0, 0);

}

/// <summary>

/// Identifica una trama de información.

/// </summary>

/// <param name="datosBruto">Elemento de la lista elementosSinFiltrar</param>

/// <returns>Devuelve OK si es una trama de información.</returns>

Trama_Info identificaAtributosTramaInfo(string datosBruto)

{

try

{

string direccionOrigen;

string direccionOrigen_Aux = string.Empty;

string direccionOrigen_Aux1;

string info1 = string.Empty;

string info2 = string.Empty;

string[] datos1 = datosBruto.Split(' ');

direccionOrigen = datos1[0].Substring(2, 8);

char[] charValue = direccionOrigen.ToCharArray();

//tenemos los 8 bytes de la direccion mac uno por uno.

foreach (char letter in charValue)

{

// Convierte el numero expresado en base-16 a un entero.

byte value = Convert.ToByte(letter);

// Toma el caracter correspondiente a valor entero.

string stringValue = String.Format("{0:X2}", value);

direccionOrigen_Aux = direccionOrigen_Aux + ":" + stringValue;

}

direccionOrigen_Aux1 = direccionOrigen_Aux.Substring(1, 23);

if (datos1[1].Equals("He"))

info1 = datos1[1] + " " + datos1[2];

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

97

if (datos1[1].Equals("Sin"))

info2 = datos1[1] + " " + datos1[2];

return new Trama_Info(direccionOrigen_Aux1, info1, info2);

}

catch (Exception)

{

}

return new Trama_Info("Error", "Error", "Error");

}

/// <summary>

/// Identifica una trama de control.

/// </summary>

/// <param name="datosBruto">Elemento de la lista elementosSinFiltrar</param>

/// <returns>Devuelve OK si es una trama de control.</returns>

Trama_Control identificaAtributosTramaControl(string datosBruto)

{

try

{

// Convertimos el string en un char array

char[] aux = datosBruto.ToCharArray(0, datosBruto.Length);

char[] ATCommand = new char[2];

char CommandStatus = 'A';

char parameter = '\0';

// Comando respuesta con el canal de trabajo

if ((aux[3] == 'C') && (aux[4] == 'H'))

{

ATCommand[0] = aux[3];

ATCommand[1] = aux[4];

CommandStatus = aux[5];

parameter = aux[6];

}

// Comando respuesta con el RSSI

else if ((aux[3] == 'D') && (aux[4] == 'B'))

{

ATCommand[0] = aux[3];

ATCommand[1] = aux[4];

CommandStatus = aux[5];

parameter = aux[6];

}

// Comando respuesta con el numero de motas penientes de unirse a la red

else if ((aux[3] == 'N') && (aux[4] == 'C'))

{

ATCommand[0] = aux[3];

ATCommand[1] = aux[4];

CommandStatus = aux[5];

parameter = aux[6];

}

return new Trama_Control(ATCommand, CommandStatus, parameter);

}

catch (Exception aec)

{

}

char[] Error = { 'E', 'r', 'r', 'o', 'r' };

return new Trama_Control(Error, '\0', '\0');

}

/// <summary>

/// Identifica una trama de control PAN_ID.

/// </summary>

/// <param name="datosBruto">Elemento de la lista elementosSinFiltrar</param>

/// <returns>Devuelve OK si es una trama de control PAN_ID.</returns>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

98

Trama_Control1 identificaAtributosTramaControl1(string datosBruto)

{

try

{

// Convertimos el string en un char array

char[] aux = datosBruto.ToCharArray(0, datosBruto.Length);

char[] ATCommand = new char[2];

char CommandStatus = 'A';

char[] parameter = new char[8];

string panid = string.Empty;

//Comando respuesta con el PAN_ID de la red

if ((aux[3] == 'O') && (aux[4] == 'P'))

{

ATCommand[0] = aux[3];

ATCommand[1] = aux[4];

CommandStatus = aux[5];

for (int i = 0; i < 8; i++)

{

parameter[i] = aux[i + 6];

}

//tenemos los bytes del PAN ID.

foreach (char letter in parameter)

{

// Convierte el numero expresado en base-16 a un entero.

byte value = Convert.ToByte(letter);

// Toma el caracter correspondiente a valor entero.

string stringValue = String.Format("{0:X2}", value);

panid = panid + stringValue;

}

}

return new Trama_Control1(ATCommand, CommandStatus, panid);

}

catch (Exception aec)

{

}

char[] Error = { 'E', 'r', 'r', 'o', 'r' };

string error = "Error";

return new Trama_Control1(Error, '\0', error);

}

#endregion

#region Nueva captura, parar, etc.

/// <summary>

/// Permite comenzar a la App una nueva captura de paquetes de la WSN.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void nuevaCapturaToolStripMenuItem_Click(object sender, EventArgs e)

{

try

{

this.serialPort1.DataReceived += serialPort1_DataReceived;

tramasSesionActual.Clear();

if (!this.controlLogicoPuerto(true))

{

MessageBox.Show("Ha ocurrido algun error al abrir el puerto. Vuelva a intentarlo.", "Apertura del puerto serie",

MessageBoxButtons.OK,MessageBoxIcon.Information);

this.estadoDelPuerto = false;

this.label7.Text = "Cerrado";

this.pictureBox1.Image = this.imageList1.Images[0];

this.nuevaCapturaToolStripMenuItem.Enabled = true;

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

99

this.pararCapturaActualToolStripMenuItem.Enabled = false;

this.dataGridView_hojaPrincipal.Enabled = false;

this.serialPort1.DataReceived += null;

}

else

{

this.getPropiedadesRed();

this.listaNombresGrafica.Clear();

}

}

catch (Exception er)

{

MessageBox.Show("No se ha podido abrir el puerto. Inserte el receptor. Mensaje interno: "+ er.Message, "Advertencia",

MessageBoxButtons.OK, MessageBoxIcon.Information);

this.dataGridView_hojaPrincipal.Enabled = false;

this.nuevaCapturaToolStripMenuItem.Enabled = true;

this.pararCapturaActualToolStripMenuItem.Enabled = false;

estadoDelPuerto = false;

this.Invoke(delegadoEstadoPuerto);

}

}

/// <summary>

/// Permite terminar a la App una captura de paquetes de la WSN que se está llevando a cabo.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void pararCapturaActualToolStripMenuItem_Click(object sender, EventArgs e)

{

this.serialPort1.DiscardInBuffer();

this.serialPort1.DataReceived -= serialPort1_DataReceived;

this.controlLogicoPuerto(false);

}

/// <summary>

/// Sirve para salir de la App.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void salirToolStripMenuItem_Click(object sender, EventArgs e)

{

this.serialPort1.DataReceived -= serialPort1_DataReceived;

if (serialPort1.IsOpen)

serialPort1.Close();

System.Windows.Forms.Application.Exit();

}

/// <summary>

/// Permite limpiar de la pantalla de la App toda la información registrada hasta el momento.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void limpiarElementosToolStripMenuItem_Click(object sender, EventArgs e)

{

if (conjuntoTramasTotalesIdentificadas.Count > 0)

{

this.SuspendLayout();

if (serialPort1.IsOpen)

{

serialPort1.Close();

estadoDelPuerto = false;

this.Invoke(delegadoEstadoPuerto);

this.nuevaCapturaToolStripMenuItem.Enabled = true;

this.pararCapturaActualToolStripMenuItem.Enabled = false;

this.dataGridView_hojaPrincipal.Enabled = false;

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

100

}

this.textBox2.Text = "0";

this.elementosSinFiltrar.Clear();

this.tramasSesionActual.Clear();

this.conjuntoTramasTotalesIdentificadas.Clear();

this.motasDetectadasSesion.Clear();

TabPage aux = new TabPage();

aux = this.tabControl2.TabPages[0];

this.tabControl2.TabPages.Clear();

this.tabControl2.TabPages.Add(aux);

this.Refresh();

this.PerformLayout();

this.limpiarElementosToolStripMenuItem.Enabled = false;

this.dataGridView_hojaPrincipal.Rows.Clear();

}

}

#endregion

#region Background workers

/// <summary>

/// Permite a la aplicación realizar todo el procesamiento de datos mientras sigue recibiendo paquetes por puerto serie.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento DoWorkEventArgs</param>

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)

{

if (this.backgroundWorker1.CancellationPending == true)

{

e.Cancel = true;

}

else

{

this.tramasSesionActual.Clear();

this.elementosSinFiltrar.Clear();

int dimension = 0;

this.bufferCaracteresRecibidos.ForEach(array => dimension += array.Length);

char[] bufferChar = new char[dimension];

int contadorInternoAux = 0;

foreach (char[] array in this.bufferCaracteresRecibidos)

{

array.CopyTo(bufferChar, contadorInternoAux);

contadorInternoAux += array.Length;

}

//bufferChar <-- Contiene todos los caracteres de los ultimos "contadorEventos"

this.primerTratamientoDatosRecibidos(bufferChar, this.elementosSinFiltrar);

this.segundoTratamientoDatosRecibidos(this.elementosSinFiltrar, this.tramasSesionActual);

this.tercerTratamientoDatosRecibidos(this.tramasSesionActual, this.conjuntoTramasTotalesIdentificadas);

this.bufferCaracteresRecibidos.Clear();

e.Result = true;

}

}

/// <summary>

/// Realiza la impresión de los datos procesado en la App mientras la App recogía paquetes por puerto serie.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento RunWorkerCompletedEventArgs</param>

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

{

flagActividadPuerto = false;

this.Invoke(actividadPuerto);

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

101

List<Trama> copia = new List<Trama>(this.tramasSesionActual);

foreach (Trama trama in copia)

{

this.tramaActualImpresion = trama;

this.Invoke(delegadoImpresion);

}

}

#endregion

/// <summary>

/// Envía tramas de control para obtener información de las propiedades de enlaces con la WSN.

/// </summary>

private void getPropiedadesRed()

{

this.propiedadesEnlace.propiedadesEnlaceCapturadas = false;

this.propiedadesEnlace.lecturaCanalCapturada = false;

this.propiedadesEnlace.lecturaPANIDCapturada = false;

this.propiedadesEnlace.lecturaMotasPendientesCapturada = false;

this.gestorEscrituraMota.WriteTramaControl(WriteMota.TramasControl.PANID);

Thread.Sleep(500);

this.gestorEscrituraMota.WriteTramaControl(WriteMota.TramasControl.Canal);

Thread.Sleep(500);

this.gestorEscrituraMota.WriteTramaControl(WriteMota.TramasControl.MotasPendientesUnion);

Thread.Sleep(500);

this.gestorEscrituraMota.WriteTramaControl(WriteMota.TramasControl.RSSI);

Thread.Sleep(500);

}

/// <summary>

/// Método pra controlar la logica del puerto serie.

/// </summary>

/// <param name="estadoPuerto">Booleano que indica el estado del puerto.</param>

/// <returns>devuelve el estado del puerto TRUE o FALSE</returns>

private bool controlLogicoPuerto(bool estadoPuerto)

{

try

{

if (estadoPuerto) // Queremos abrirlo

{

this.serialPort1.PortName = this.datosPuertoActual.nombrePuerto;

this.serialPort1.BaudRate = this.datosPuertoActual.tasaBaudios;

if (!this.serialPort1.IsOpen)

this.serialPort1.Open();

this.estadoDelPuerto = true;

this.label7.Text = "Abierto";

this.pictureBox1.Image = this.imageList1.Images[1];

this.nuevaCapturaToolStripMenuItem.Enabled = false;

this.pararCapturaActualToolStripMenuItem.Enabled = true;

this.dataGridView_hojaPrincipal.Enabled = true;

this.serialPort1.DataReceived += serialPort1_DataReceived;

this.gestorEscrituraMota.referenciaPuerto = (SerialPort)this.serialPort1;

this.propiedadesEnlace.clear();

this.Invoke(impresionPropiedadesEnlace);

}

else // Queremos cerralo

{

if (this.serialPort1.IsOpen)

{

this.serialPort1.DiscardInBuffer();

this.serialPort1.Close();

}

this.estadoDelPuerto = false;

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

102

this.label7.Text = "Cerrado";

this.pictureBox1.Image = this.imageList1.Images[0];

this.nuevaCapturaToolStripMenuItem.Enabled = true;

this.pararCapturaActualToolStripMenuItem.Enabled = false;

this.dataGridView_hojaPrincipal.Enabled = false;

this.serialPort1.DataReceived -= serialPort1_DataReceived;

this.gestorEscrituraMota.referenciaPuerto = null;

this.datosPuertoActual.nombrePuerto = string.Empty;

this.datosPuertoActual.tasaBaudios = 0;

this.propiedadesEnlace.clear();

this.Invoke(impresionPropiedadesEnlace);

}

return true;

}

catch (Exception)

{

try { this.serialPort1.Close(); }

catch { }

this.estadoDelPuerto = false;

return false;

}

}

#region Manejadores eventos click y EXCEL

/// <summary>

/// Se configura desde la App e indica el numero de paqutes que queremos almacenar antes de tratarlos.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void comboBox1_SelectedValueChanged(object sender, EventArgs e)

{

int selectedIndex = comboBox1.SelectedIndex;

Object selectedItem = comboBox1.SelectedItem;

int numIntentosSelected = 0;

Int32.TryParse(selectedItem.ToString(), out numIntentosSelected);

this.contadorEventos = (ushort)numIntentosSelected;

}

/// <summary>

/// Genera un archivo EXCEL para contener todos los datos registrado de la WSN.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void generarArchivoLogToolStripMenuItem_Click(object sender, EventArgs e)

{

try

{

this.serialPort1.DiscardInBuffer();

this.serialPort1.DataReceived -= serialPort1_DataReceived;

this.controlLogicoPuerto(false);

}

catch(Exception){}

SaveFileDialog dialogoExcelGuardar = new SaveFileDialog();

dialogoExcelGuardar.DefaultExt = "xls";

dialogoExcelGuardar.Title = "Seleccione la ruta deseada para guardar el archivo de inspección";

dialogoExcelGuardar.FileName = "sesion_" + DateTime.Now.Day + "_" + DateTime.Now.Month.ToString("00") + "_" +

DateTime.Now.Year.ToString();

dialogoExcelGuardar.Filter = "Archivos Excel (*.xls)|*.xls";

if (dialogoExcelGuardar.ShowDialog() == DialogResult.OK)

{

string mensajeExcepcion;

if(!this.guardarArchivoInspeccion(Path.GetFullPath(dialogoExcelGuardar.FileName), out mensajeExcepcion))

MessageBox.Show("Ha ocurrido algún error generando el archivo de Excel. Mensaje interno: " +

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

103

mensajeExcepcion,"Excel - Error",MessageBoxButtons.OK,MessageBoxIcon.Error);

else

MessageBox.Show("El archivo de sesión ha sido generado correctamente.","Excel - Archivo de

sesión",MessageBoxButtons.OK,MessageBoxIcon.Information);

}

}

/// <summary>

/// Escribe el archivo EXCEL con toda la información recogida por la App indicado si se ha realizado con éxito o no.

/// </summary>

/// <param name="rutaArchivo">Recibe la ruta donde se quiere alojar el archivo.</param>

/// <param name="mensajeExcepcion">Mensaje que indica el estado del archivo generado.</param>

/// <returns>Indica si el archivo ha sido guardado con éxito o no.</returns>

private bool guardarArchivoInspeccion(string rutaArchivo, out string mensajeExcepcion)

{

mensajeExcepcion = string.Empty;

bool retorno = false;

try

{

#region Libro

objetoExcel = new Microsoft.Office.Interop.Excel.Application();

objetoExcel.DisplayAlerts = false;

conjuntoLibros = (Microsoft.Office.Interop.Excel.Workbooks)objetoExcel.Workbooks;

Microsoft.Office.Interop.Excel.Worksheet hojaCaratula;

libro = objetoExcel.Workbooks.Add(System.Reflection.Missing.Value);

hojas = libro.Worksheets;

hojaCaratula = this.libro.Worksheets.Add();

#endregion

#region Caratula

hojaActual = (Microsoft.Office.Interop.Excel.Worksheet)hojas.get_Item(1);

hojaActual.Name = "Caratula";

// Proceso de escritura en fichero

Microsoft.Office.Interop.Excel.Range rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[2, 2];

rango.Font.Size = 10;

hojaActual.Cells[2, 2] = "Titulo";

hojaActual.Cells[2, 2].Columns.AutoFit();

hojaActual.Cells[2, 3] = "Archivo de log de sesión de motas";

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[3, 2];

rango.Font.Size = 10;

hojaActual.Cells[3, 2] = "Fecha";

hojaActual.Cells[3, 3] = DateTime.Now.GetDateTimeFormats()[12];

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[5, 2];

rango.Font.Bold = true;

rango.Font.Size = 10;

rango.Interior.ColorIndex = 15;

hojaActual.Cells[5, 2] = "Fecha registro";

hojaActual.Cells[5, 2].Columns.AutoFit();

hojaActual.Cells[5, 2].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[5, 3];

rango.Font.Bold = true;

rango.Font.Size = 10;

rango.Interior.ColorIndex = 15;

hojaActual.Cells[5, 3] = "Hora registro";

hojaActual.Cells[5, 3].Columns.AutoFit();

hojaActual.Cells[5, 3].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[5, 4];

rango.Font.Bold = true;

rango.Font.Size = 10;

rango.Interior.ColorIndex = 15;

hojaActual.Cells[5, 4] = "Dirección MAC";

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

104

hojaActual.Cells[5, 4].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[5, 5];

rango.Font.Bold = true;

rango.Font.Size = 10;

rango.Interior.ColorIndex = 15;

hojaActual.Cells[5, 5] = "Posicion XYZ";

hojaActual.Cells[5, 5].Columns.AutoFit();

hojaActual.Cells[5, 5].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[5, 6];

rango.Font.Bold = true;

rango.Font.Size = 10;

rango.Interior.ColorIndex = 15;

hojaActual.Cells[5, 6] = "Temperatura";

hojaActual.Cells[5, 6].Columns.AutoFit();

hojaActual.Cells[5, 6].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[5, 7];

rango.Font.Bold = true;

rango.Font.Size = 10;

rango.Interior.ColorIndex = 15;

hojaActual.Cells[5, 7] = "Bateria";

hojaActual.Cells[5, 7].Columns.AutoFit();

hojaActual.Cells[5, 7].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[5, 8];

rango.Font.Bold = true;

rango.Font.Size = 10;

rango.Interior.ColorIndex = 15;

hojaActual.Cells[5, 8] = "Numero secuencia";

hojaActual.Cells[5, 8].Columns.AutoFit();

hojaActual.Cells[5, 8].HorizontalAlignment = Microsoft.Office.Interop.Excel.XlHAlign.xlHAlignCenter;

#endregion

#region Insercion tramas

int contadorActualFila = 6;

foreach (Trama trama in this.conjuntoTramasTotalesIdentificadas)

{

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[contadorActualFila, 2];

rango.Font.Size = 10;

hojaActual.Cells[contadorActualFila, 2] = trama.fechaRx.Date.ToShortDateString();

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[contadorActualFila, 3];

rango.Font.Size = 10;

hojaActual.Cells[contadorActualFila, 3] = trama.fechaRx.Hour + ":" + trama.fechaRx.Minute + ":" +

trama.fechaRx.Second;

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[contadorActualFila, 4];

rango.Font.Size = 10;

hojaActual.Cells[contadorActualFila, 4] = trama.direccionOrigen.ToString();

hojaActual.Cells[contadorActualFila, 4].Columns.AutoFit();

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[contadorActualFila, 5];

rango.Font.Size = 10;

hojaActual.Cells[contadorActualFila, 5] = trama.coordenada.ToString();

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[contadorActualFila, 6];

rango.Font.Size = 10;

hojaActual.Cells[contadorActualFila, 6] = trama.temperatura.ToString();

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[contadorActualFila, 7];

rango.Font.Size = 10;

hojaActual.Cells[contadorActualFila, 7] = trama.nivelBateria.ToString();

rango = (Microsoft.Office.Interop.Excel.Range)hojaActual.Cells[contadorActualFila, 8];

rango.Font.Size = 10;

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

105

hojaActual.Cells[contadorActualFila, 8] = trama.secuencia.ToString();

contadorActualFila++;

}

#endregion

try

{

((Microsoft.Office.Interop.Excel.Worksheet)this.objetoExcel.ActiveWorkbook.Sheets[2]).Delete();

((Microsoft.Office.Interop.Excel.Worksheet)this.objetoExcel.ActiveWorkbook.Sheets[2]).Delete();

}

catch (Exception) { }

this.libro.SaveAs(rutaArchivo, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal,

Type.Missing, Type.Missing, false, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive,

Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

this.libro.Close(false, Missing.Value, Missing.Value);

if (celdaActual != null)

Marshal.FinalReleaseComObject(celdaActual);

if (hojaActual != null)

Marshal.FinalReleaseComObject(hojaActual);

if (hojas != null)

Marshal.FinalReleaseComObject(hojas);

if (conjuntoLibros != null)

Marshal.FinalReleaseComObject(conjuntoLibros);

if (this.libro != null)

Marshal.FinalReleaseComObject(this.libro);

if (this.objetoExcel != null)

Marshal.ReleaseComObject(this.objetoExcel);

retorno = true;

}

catch (Exception exc)

{

mensajeExcepcion = exc.Message;

retorno = false;

}

return retorno;

}

#endregion

#region Pagina de graficas

/// <summary>

/// Carga los datos en las gráficas si clickeamos en la pestaña de graficos.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento ModificacionConjuntoMotas</param>

void Form1_NuevaModificacionConjuntoMotas(object sender, ModificacionConjuntoMotas e)

{

//Si estoy en vista grafica

if (this.vistaActualGrafica)

{

foreach (DatosGrafica datos in e.MotasSesionActual)

{

this.datosGraficaActualDelegado = datos;

this.Invoke(delegadoInclusionElementoGrafica);

}

}

}

/// <summary>

/// Genera las curvas en las gráficas de la App.

/// </summary>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

106

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoInclusionElementoGrafica(object sender, EventArgs e)

{

this.graficaTemperatura.SuspendLayout();

valorActualGrafica_x += 1;

if (!this.listaNombresGrafica.Contains(this.datosGraficaActualDelegado.nombreMota))

{

this.graficaTemperatura.Series.Add(this.datosGraficaActualDelegado.nombreMota);

this.graficaBateria.Series.Add(this.datosGraficaActualDelegado.nombreMota);

this.listaNombresGrafica.Add(this.datosGraficaActualDelegado.nombreMota);

}

this.graficaTemperatura.Series[this.datosGraficaActualDelegado.nombreMota].Points.AddXY(valorActualGrafica_x,

this.datosGraficaActualDelegado.temperatura);

this.graficaTemperatura.Series[this.datosGraficaActualDelegado.nombreMota].ChartType = SeriesChartType.FastLine;

this.graficaTemperatura.Series[this.datosGraficaActualDelegado.nombreMota].XAxisType = AxisType.Secondary;

this.graficaBateria.Series[this.datosGraficaActualDelegado.nombreMota].Points.AddXY(valorActualGrafica_x,

this.datosGraficaActualDelegado.bateria);

this.graficaBateria.Series[this.datosGraficaActualDelegado.nombreMota].ChartType = SeriesChartType.FastLine;

this.graficaBateria.Series[this.datosGraficaActualDelegado.nombreMota].XAxisType = AxisType.Secondary;

}

/// <summary>

/// Imprime la gráfica en la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

void metodoDelegadoImpresionGrafica(object sender, EventArgs e)

{

this.graficaTemperatura.ResumeLayout();

}

/// <summary>

/// Detecta el evento de clickear en la pestaña "Histórico" dónde están las gráficas de la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

private void tabControl1_Click(object sender, EventArgs e)

{

//this.controlLogicoPuerto(false);

}

/// <summary>

/// Actualiza las gráficas de la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

private void tabPage4_Enter(object sender, EventArgs e)

{

this.vistaActualGrafica = true;

}

/// <summary>

/// Deja de actualizar las gráficas de la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

private void tabPage4_Leave(object sender, EventArgs e)

{

this.vistaActualGrafica = false;

this.ultimoDatosGrafica.Clear();

}

#endregion

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

107

#region Relacionado con configuracion puerto serie y consola

/// <summary>

/// Se encarga de al hacer click sobre configuración, rellenar el panel con la información de dispositivos

/// conectados actualmente, y determinar la velocidad de ellos, para que el usuario pueda clickarla.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

private void configuracionToolStripMenuItem_Click(object sender, EventArgs e)

{

//Aqui relleno la lista de elemntos que tengo, y los relleno.

if (!this.datosPuertoActual.abierto && this.datosPuertoActual.nombrePuerto.Equals(string.Empty))

{

this.puertoSerieToolStripMenuItem.DropDownItems.Clear();

string[] devicesList = System.IO.Ports.SerialPort.GetPortNames();

foreach (string cadena in devicesList)

this.puertoSerieToolStripMenuItem.DropDownItems.Add(cadena);

}

}

/// <summary>

/// Permite seleccionar el nombre del puerto al que queremos conectarnos.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento ToolStripItemClickedEventArgs.</param>

void puertoSerieToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)

{

if (!e.ClickedItem.Text.Equals(string.Empty))

{

foreach (ToolStripDropDownItem item in this.puertoSerieToolStripMenuItem.DropDownItems)

((ToolStripMenuItem)item).Checked = false;

this.datosPuertoActual.nombrePuerto = e.ClickedItem.Text;

((ToolStripMenuItem)e.ClickedItem).Checked = true;

this.velocidadBaudiosToolStripMenuItem.DropDownItems.Clear();

this._spManager = new SerialPortManager();

List<int> baudRatesList = this._spManager.getBaudrateList(e.ClickedItem.Text);

foreach (int baudRate in baudRatesList)

{

this.velocidadBaudiosToolStripMenuItem.DropDownItems.Add(baudRate.ToString());

}

this._spManager = null;

}

}

/// <summary>

/// Permite seleccionar la tasa de velocidad de transmisión del puerto al que nos conectamos.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento ToolStripItemClickedEventArgs.</param>

void velocidadBaudiosToolStripMenuItem_DropDownItemClicked(object sender, ToolStripItemClickedEventArgs e)

{

if (!e.ClickedItem.Text.Equals(string.Empty))

{

foreach (ToolStripDropDownItem item in this.velocidadBaudiosToolStripMenuItem.DropDownItems)

((ToolStripMenuItem)item).Checked = false;

this.datosPuertoActual.tasaBaudios = Int32.Parse(e.ClickedItem.Text);

((ToolStripMenuItem)e.ClickedItem).Checked = true;

}

}

#region Aplicacion de consola

/// <summary>

/// Nos permite abrir una consola desde la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

108

/// <param name="e">Evento EventArgs.</param>

private void utilidadConsolaToolStripMenuItem_Click(object sender, EventArgs e)

{

if (this.serialPort1.IsOpen)

this.controlLogicoPuerto(false);

(new Consola()).ShowDialog();

}

#endregion

#endregion

/// <summary>

/// Libera los errorProvider del evento generado por tabPage2_Enter.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

private void tabPage2_Enter(object sender, EventArgs e)

{

this.infoProvider.Clear();

}

/// <summary>

/// Método que da información de la App, redirecciona a un manual de ayuda y muetra información sobre el creador.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

private void sobreToolStripMenuItem_Click(object sender, EventArgs e)

{

(new AcercaDe()).ShowDialog();

}

}

#region Clases auxiliares /// <summary> /// Clase que contiene los datos del puerto serie actual. /// </summary> public class DatosPuerto { public string nombrePuerto; public int tasaBaudios; public bool abierto; /// <summary> /// Método para recoger los datos del puerto serie actual. /// </summary> public DatosPuerto() { this.nombrePuerto = string.Empty; this.tasaBaudios = 0; this.abierto = false; } } /// <summary> /// Clase que recoge los datos de los sensores de las motas de la red para representarlos en una gráfica. /// </summary> public class DatosGrafica { public float temperatura; public DateTime horaEvento; public float bateria; public string nombreMota; /// <summary> /// Método que recoge los datos de los sensores de las motas de la red para representarlos en una gráfica. /// </summary> /// <param name="t">Temperatura.</param>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

109

/// <param name="t1">Tiempo transcurrido.</param> /// <param name="bat">Nivel de batería.</param> /// <param name="nombre">Nombre del sensor del que se recogen los datos.</param> public DatosGrafica(float t, DateTime t1, float bat,string nombre) { this.temperatura = t; this.horaEvento = t1; this.bateria = bat; this.nombreMota = nombre; } } /// <summary> /// Clase para indicar las propiedades del enlace inalámbrico entre el coordinador y las motas. /// </summary> public class PropiedadesEnlace { public bool propiedadesEnlaceCapturadas; public bool lecturaCanalCapturada; public bool lecturaPANIDCapturada; public bool lecturaRSSI; public bool lecturaMotasPendientesCapturada; public int canal; public string PANID; public int motasPendientes; public int RSSI; /// <summary> /// Método que indica y almacena los datos recogidos de las propiedades del enlace inalámbrico /// entre el coordinador y las motas para que sean representados en la App. /// </summary> public PropiedadesEnlace() { this.propiedadesEnlaceCapturadas = false; this.lecturaCanalCapturada = false; this.lecturaPANIDCapturada = false; this.lecturaMotasPendientesCapturada = false; this.lecturaRSSI = false; this.canal = 0; this.PANID = string.Empty; this.motasPendientes = 0; this.RSSI = 0; } /// <summary> /// Método que limpia los datos recogidos de las propiedades del enlace en la App. /// </summary> internal void clear() { this.canal = 0; this.PANID = string.Empty; this.motasPendientes = 0; this.RSSI = 0; } } /// <summary> /// Clase que contiene y clasifica la información de los mensaje de información.

/// </summary>

public class InformacionMensajes

{

public enum TipoMensaje{Bateria,Caido,Unknown};

public TipoMensaje tipoMensaje;

public string dirMac;

/// <summary>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

110

/// Método que indica que el mensaje de información recibido es desconocido.

/// </summary>

public InformacionMensajes()

{

this.tipoMensaje = TipoMensaje.Unknown;

this.dirMac = string.Empty;

}

/// <summary>

/// Método que indica el mensaje de información recibido.

/// </summary>

/// <param name="_tipo">Tipo de mansaje de información.</param>

/// <param name="_dirMac">Dirección MAC del emisor del mensaje.</param>

public InformacionMensajes(TipoMensaje _tipo, string _dirMac)

{

this.tipoMensaje = _tipo;

this.dirMac = _dirMac;

}

}

#endregion

}

Trama.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace SimpleSerial

{

/// <summary>

/// Clase para definir y obtener los campos de información de la trama de datos.

/// </summary>

public class Trama

{

public string direccionOrigen;

public Punto3D coordenada;

public DateTime fechaRx;

public float temperatura;

public float nivelBateria;

public int secuencia;

public bool flagTramaMostrada = default(bool);

/// <summary>

/// Método para recoger los campos de datos de la trama de datos.

/// </summary>

/// <param name="fechaRecepcion">Se recoge la fecha de la recepcion de la trama recibida.</param>

/// <param name="direccionMAC">Se recoge la dirección MAC de la mota que envía la trama.</param>

/// <param name="coord">Se capta el punto 3D.</param>

/// <param name="temp">Se capta la temperatura.</param>

/// <param name="bate">Se toma el nivel de batería de la mota.</param>

/// <param name="sec_mia">Se capta el número de la secuancia de la trama.</param>

public Trama(DateTime fechaRecepcion, string direccionMAC, Punto3D coord, float temp, float bate, int sec_mia)

{

this.fechaRx = fechaRecepcion;

this.direccionOrigen = direccionMAC;

this.coordenada = coord;

this.temperatura = temp;

this.nivelBateria = bate;

this.secuencia = sec_mia;

}

/// <summary>

/// Método para comprobar la validez de una trama de datos.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

111

/// </summary>

/// <returns>Devuelve si trama es valida o no.</returns>

public bool esTramaValida()

{

return (!this.direccionOrigen.Equals(string.Empty) && !this.secuencia.Equals(default(int)));

}

}

/// <summary>

/// Clase para definir el campo de la información del acelerómetro del waspmote en la trama de datos.

/// </summary>

public class Punto3D

{

float x;

float y;

float z;

/// <summary>

/// Método para convertir a float el string que contiene los puntos x,y,z de la información del acelerómetro.

/// </summary>

/// <param name="cadena">string que contiene la información del punto 3D.</param>

public Punto3D(string cadena)

{

string[] datos = cadena.Split(',');

this.x = (float)(Convert.ToDouble(datos[0].Split(':')[1]));

this.y = (float)(Convert.ToDouble(datos[1].Split(':')[1]));

this.z = (float)(Convert.ToDouble(datos[2].Split(':')[1]));

}

/// <summary>

/// Métodos para obtener el punto x, elñ punto y y el punto z por separado.

/// </summary>

/// <param name="_x">valor float de x.</param>

/// <param name="_y">valor float de y.</param>

/// <param name="_z">valor float de z.</param>

public Punto3D(float _x, float _y, float _z)

{

this.x = _x;

this.y = _y;

this.z = _z;

}

public Punto3D()

{

this.x = 0;

this.y = 0;

this.z = 0;

}

public float X

{

get { return this.x; }

set { this.x = value; }

}

public float Y

{

get { return this.y; }

set { this.y = value; }

}

public float Z

{

get { return this.z; }

set { this.z = value; }

}

/// <summary>

/// Método para convertir a string el punto x,y y z.

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

112

/// </summary>

/// <returns>Devuelve los valores de x,y y z.</returns>

public override string ToString()

{

return "x:" + this.x + "; y:" + this.y +"; z:" + this.z;

}

}

/// <summary>

/// Clase para definir y obtener los campos de las tramas de información.

/// </summary>

public class Trama_Info

{

public string direccionOrigen;

public string info1;

public string info2;

public bool flagTramaMostrada = default(bool);

/// <summary>

/// Método para recoger los campos de la trama de información.

/// </summary>

/// <param name="direccionMAC">Se recoge la dirección MAC de la mota que envía la trama.</param>

/// <param name="informacion1">Se recoge la información batería baja.</param>

/// <param name="informacion2">Se recoge la información trama caída.</param>

public Trama_Info(string direccionMAC, string informacion1, string informacion2)

{

this.direccionOrigen = direccionMAC;

this.info1 = informacion1;

this.info2 = informacion2;

}

/// <summary>

/// Método para comprobar la validez de una trama de información.

/// </summary>

/// <returns>Devuelve si trama es valida o no.</returns>

public bool esTramaInfoValida()

{

return (!this.direccionOrigen.Equals(string.Empty) && ((!this.info1.Equals(string.Empty)) ||

(!this.info2.Equals(string.Empty))));

}

}

/// <summary>

/// Clase para definir y obtener los campos de las tramas de control.

/// </summary>

public class Trama_Control

{

public char[] ATCommand = new char[2];

public char CommandStatus;

public char CommandData;

public bool flagTramaMostrada = default(bool);

/// <summary>

/// Método para recoger los campos de la trama de control.

/// </summary>

/// <param name="ATCommR">Recoge el tipo de trama de control que se recibe.</param>

/// <param name="Status">Recoge el estado de la trama que se ha recibido.</param>

/// <param name="Param">Recoge el datos de interés de la trama de control.</param>

public Trama_Control(char[] ATCommR, char Status, char Param)

{

this.ATCommand[0] = ATCommR[0];

this.ATCommand[1] = ATCommR[1];

this.CommandStatus = Status;

this.CommandData = Param;

}

/// <summary>

/// //Métodos para comprobar la validez de una trama de control

/// </summary>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

113

/// <returns>Devuelve si trama es valida o no.</returns>

public bool esTramaControlValida()

{

return (this.CommandStatus.Equals('\0'));

}

/// <summary>

/// Método para filtrar que tipo de trama de control se ha recibido.

/// </summary>

/// <param name="obj">Objeto tipo Trama_Control.</param>

/// <param name="tramaAComprobar">Se le pasa el tipo de trama a comprobar.</param>

/// <returns>Devuelve verdadero o falso según si la comprobación es cierta o falsa.</returns>

public static bool Equals(object obj, WriteMota.TramasControl tramaAComprobar)

{

bool retorno = false;

Trama_Control trama = (Trama_Control)obj;

if (tramaAComprobar.Equals(WriteMota.TramasControl.MotasPendientesUnion))

{

retorno = (trama.ATCommand[0] == 0x4E) && (trama.ATCommand[1] == 0x43);

}

else if (tramaAComprobar.Equals(WriteMota.TramasControl.Canal))

{

retorno = (trama.ATCommand[0] == 0x43) && (trama.ATCommand[1] == 0x48);

}

else if (tramaAComprobar.Equals(WriteMota.TramasControl.RSSI))

{

retorno = (trama.ATCommand[0] == 0x44) && (trama.ATCommand[1] == 0x42);

}

return retorno;

}

}

/// <summary>

/// Clase para obtener el PAN ID de una trama de control.

/// </summary>

public class Trama_Control1

{

public char[] ATCommand1 = new char[2];

public char CommandStatus1;

public string CommandData1 = string.Empty;

public bool flagTramaMostrada = default(bool);

/// <summary>

/// Método para recoger los campos de la trama de control.

/// </summary>

/// <param name="ATCommR">Recoge el tipo de trama de control que se recibe.</param>

/// <param name="Status">Recoge el estado de la trama que se ha recibido.</param>

/// <param name="PAN_ID">Recoge el datos de interés de la trama de control1.</param>

public Trama_Control1(char[] ATCommR, char Status, string PAN_ID)

{

this.ATCommand1[0] = ATCommR[0];

this.ATCommand1[1] = ATCommR[1];

this.CommandStatus1 = Status;

this.CommandData1 = PAN_ID;

}

/// <summary>

/// Método para comprobar la validez de una trama de control.

/// </summary>

/// <returns>Devuelve si trama es valida o no.</returns>

public bool esTramaControl1Valida()

{

return (this.CommandStatus1.Equals('\0'));

}

}

/// <summary>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

114

/// Clase para contabilizar e identificar las motas que hay en la red de sensores inalambrica.

/// </summary>

public class Mota

{

public string direccionMAC;

public string nombreMota;

public List<Trama> listaTramasSesionActual;

/// <summary>

/// Método para recoger los campos que identifican a una mota.

/// </summary>

/// <param name="_direccionMAC">Se recoge la dirección MAC de la mota que envía la trama.</param>

/// <param name="nom">Nombre la mota.</param>

public Mota(string _direccionMAC, string nom)

{

this.direccionMAC = _direccionMAC;

this.nombreMota = nom;

this.listaTramasSesionActual = new List<Trama>();

}

/// <summary>

/// Método para asociar las tramas que envía una mota.

/// </summary>

/// <returns>Mota que ha enviado una trama.</returns>

internal Mota Clone()

{

Mota clonada = new Mota(this.direccionMAC,this.nombreMota);

clonada.listaTramasSesionActual = new List<Trama>();

this.listaTramasSesionActual.ForEach(t => clonada.listaTramasSesionActual.Add(t));

return clonada;

}

}

}

WriteMota.cs

using System;

using System.Text;

using System.Drawing;

using System.IO.Ports;

using System.Windows.Forms;

using System.Collections.Generic;

using System.Diagnostics;

using System.Reflection;

using System.ComponentModel;

namespace SimpleSerial

{

/// <summary>

/// Clase para enviar tramas de control por el puerto serie.

/// </summary>

public class WriteMota

{

public SerialPort referenciaPuerto;

private List<byte[]> tramasControl;

public enum TramasControl { Canal = 0, RSSI, MotasPendientesUnion,PANID};

public WriteMota()

{

this.tramasControl = new List<byte[]>(4);

this.tramasControl.Add(new byte[8] { 0x7E, 0x00, 0x04, 0x08, 0x52, 0x43, 0x48, 0x1A });

this.tramasControl.Add(new byte[8] { 0x7E, 0x00, 0x04, 0x08, 0x52, 0x44, 0x42, 0x1F });

this.tramasControl.Add(new byte[8] { 0x7E, 0x00, 0x04, 0x08, 0x52, 0x4E, 0x43, 0x14 });

this.tramasControl.Add(new byte[9] { 0x7E, 0x00, 0x05, 0x08, 0x52, 0x4F, 0x50, 0x00, 0x06 });

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

115

}

/// <summary>

/// Método para enviar una trama de control por el puerto serie.

/// </summary>

/// <param name="tipoTrama">Tipo de trama que se va a enviar.</param>

public void WriteTramaControl(TramasControl tipoTrama)

{

this.referenciaPuerto.Write(this.tramasControl[(int)tipoTrama], 0, this.tramasControl[(int)tipoTrama].Length);

}

}

}

Consola.cs

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using SerialPortListener.Serial;

using System.IO;

namespace SerialPortListener

{

/// <summary>

/// Clase que contiene propiedades relacionadas con la Consola.

/// </summary>

public partial class Consola : Form

{

SerialPortManager _spManager;

/// <summary>

/// Inicializa la utilidad de consola y el puerto serie establecido.

/// </summary>

public Consola()

{

InitializeComponent();

UserInitialization();

}

/// <summary>

/// Inicializa un puerto serie establecido.

/// </summary>

private void UserInitialization()

{

_spManager = new SerialPortManager();

SerialSettings mySerialSettings = _spManager.CurrentSerialSettings;

serialSettingsBindingSource.DataSource = mySerialSettings;

portNameComboBox.DataSource = mySerialSettings.PortNameCollection;

baudRateComboBox.DataSource = mySerialSettings.BaudRateCollection;

dataBitsComboBox.DataSource = mySerialSettings.DataBitsCollection;

parityComboBox.DataSource = Enum.GetValues(typeof(System.IO.Ports.Parity));

stopBitsComboBox.DataSource = Enum.GetValues(typeof(System.IO.Ports.StopBits));

_spManager.NewSerialDataRecieved += new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved);

this.FormClosing += new FormClosingEventHandler(MainForm_FormClosing);

}

/// <summary>

/// Libera el puerto serie.

/// </summary>

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

116

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento FormClosingEventArgs</param>

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)

{

_spManager.Dispose();

}

/// <summary>

/// Recibe los datos del puerto serie y los muestra en pantalla.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento SerialDataEventArgs</param>

void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)

{

if (this.InvokeRequired)

{

this.BeginInvoke(new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved), new object[] { sender,

e });

return;

}

int maxTextLength = 1000;

if (tbData.TextLength > maxTextLength)

tbData.Text = tbData.Text.Remove(0, tbData.TextLength - maxTextLength);

// Convierte los datos en caracteres ASCII recibidos a datos de texto

string str = Encoding.ASCII.GetString(e.Data);

tbData.AppendText(str);

tbData.ScrollToCaret();

}

/// <summary>

/// Maneja el "empezar a escuchar" con el botón de evento click

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void btnStart_Click(object sender, EventArgs e)

{

_spManager.StartListening();

}

/// <summary>

/// Maneja el "terminar la escuchar" con el botón de evento click

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void btnStop_Click(object sender, EventArgs e)

{

_spManager.StopListening();

}

/// <summary>

/// Para la escucha del puerto serie en la utilidad de consola y la cierra.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void button1_Click(object sender, EventArgs e)

{

_spManager.StopListening();

}

/// <summary>

/// Limpia los datos de la pantalla de la utilidad de consola.

/// </summary>

/// <param name="sender">Objeto sender</param>

/// <param name="e">Evento EventArgs</param>

private void button2_Click(object sender, EventArgs e)

{

tbData.Clear();

}

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

117

}

}

SerialPortManager.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO.Ports;

using System.Reflection;

using System.ComponentModel;

using System.Threading;

using System.IO;

using System.Windows.Forms;

namespace SerialPortListener.Serial

{

/// <summary>

/// Controlador para los datos de puerto serie.

/// </summary>

public class SerialPortManager : IDisposable

{

/// <summary>

/// Manegador de los puertos series que hay instalado en el equipo.

/// </summary>

public SerialPortManager()

{

// Encontrar los puertos series instalados en el equipo

_currentSerialSettings.PortNameCollection = SerialPort.GetPortNames();

_currentSerialSettings.PropertyChanged += new

System.ComponentModel.PropertyChangedEventHandler(_currentSerialSettings_PropertyChanged);

// Si se detectan puertos series, seleccionamos el primero encontrado

if (_currentSerialSettings.PortNameCollection.Length > 0)

_currentSerialSettings.PortName = _currentSerialSettings.PortNameCollection[0];

}

~SerialPortManager()

{

Dispose(false);

}

#region Fields

private SerialPort _serialPort;

private SerialSettings _currentSerialSettings = new SerialSettings();

private string _latestRecieved = String.Empty;

public event EventHandler<SerialDataEventArgs> NewSerialDataRecieved;

#endregion

#region Properties

/// <summary>

/// Obtiene o establece la configuración del puerto serie actual.

/// </summary>

public SerialSettings CurrentSerialSettings

{

get { return _currentSerialSettings; }

set { _currentSerialSettings = value; }

}

#endregion

#region Event handlers

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

118

/// <summary>

/// Emite una nueva consulta en baudios si se cambia el puerto serie.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento PropertyChangedEventArgs.</param>

void _currentSerialSettings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)

{

if (e.PropertyName.Equals("PortName"))

UpdateBaudRateCollection();

}

/// <summary>

/// Recibe datos del puerto serie.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento SerialDataReceivedEventArgs.</param>

void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)

{

int dataLength = _serialPort.BytesToRead;

byte[] data = new byte[dataLength];

int nbrDataRead = _serialPort.Read(data, 0, dataLength);

if (nbrDataRead == 0)

return;

if (NewSerialDataRecieved != null)

NewSerialDataRecieved(this, new SerialDataEventArgs(data));

}

#endregion

#region Methods

/// <summary>

/// Se conecta a un puerto serie definido a través de la configuración actual.

/// </summary>

public void StartListening()

{

try

{

// Cierra el puerto serie si está abierto

if (_serialPort != null && _serialPort.IsOpen)

_serialPort.Close();

// Configuración de los ajustes del puerto serie.

_serialPort = new SerialPort(

_currentSerialSettings.PortName,

_currentSerialSettings.BaudRate,

_currentSerialSettings.Parity,

_currentSerialSettings.DataBits,

_currentSerialSettings.StopBits);

// Se añade un evento y abre el puerto serie para recibir datos.

_serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);

_serialPort.Open();

}

catch (ArgumentException arg)

{

MessageBox.Show("Error: no existe ningún dispositivo serie conectado. Mensaje de la aplicación: " + arg.Message,

"Excepción en la conexión", MessageBoxButtons.OK, MessageBoxIcon.Error);

}

}

/// <summary>

/// Cierra el puerto serie.

/// </summary>

public void StopListening()

{

if (this._serialPort != null)

_serialPort.Close();

}

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

119

/// <summary>

/// Recupera la ectrutura COMMPRP del dispositivo actualmente seleccionado, y extrae la propiedad dwSettableBaud.

/// </summary>

private void UpdateBaudRateCollection()

{

try

{

_serialPort = new SerialPort(_currentSerialSettings.PortName);

_serialPort.Open();

object p = _serialPort.BaseStream.GetType().GetField("commProp", BindingFlags.Instance |

BindingFlags.NonPublic).GetValue(_serialPort.BaseStream);

Int32 dwSettableBaud = (Int32)p.GetType().GetField("dwSettableBaud", BindingFlags.Instance | BindingFlags.NonPublic

| BindingFlags.Public).GetValue(p);

_serialPort.Close();

_currentSerialSettings.UpdateBaudRateCollection(dwSettableBaud);

}

catch (Exception)

{

MessageBox.Show("Ha habido un error intentendo determinar la tasa de baudios del puerto. Por favor, reinicie la

utilidad de consola.", "Error - Velocidad del puerto", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

}

/// <summary>

/// Compara la tasa de baudios del puerto con la establecida

/// </summary>

/// <param name="portName">Cadena de caracteres con el nombre del puerto</param>

/// <returns>Devuelve la gama de velocidades de transmisión para el dispositivo</returns>

public List<int> getBaudrateList(string portName)

{

try

{

_serialPort = new SerialPort(portName);

_serialPort.Open();

object p = _serialPort.BaseStream.GetType().GetField("commProp", BindingFlags.Instance |

BindingFlags.NonPublic).GetValue(_serialPort.BaseStream);

Int32 dwSettableBaud = (Int32)p.GetType().GetField("dwSettableBaud", BindingFlags.Instance | BindingFlags.NonPublic

| BindingFlags.Public).GetValue(p);

_serialPort.Close();

return _currentSerialSettings.UpdateBaudRateCollectionInt(dwSettableBaud);

}

catch (Exception)

{

MessageBox.Show("Ha habido un error intentendo determinar la tasa de baudios del puerto. Por favor, reinicie la

aplicación.", "Error - Velocidad del puerto", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

return null;

}

/// <summary>

/// Llamada para liberar al puerto serie.

/// </summary>

public void Dispose()

{

Dispose(true);

}

/// <summary>

/// Parte del patrón de diseño básico para la implementación de Dispose

/// </summary>

/// <param name="disposing">Booleano para liberación del pueto serie.</param>

protected virtual void Dispose(bool disposing)

{

try

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

120

{

if (disposing)

{

_serialPort.DataReceived -= new SerialDataReceivedEventHandler(_serialPort_DataReceived);

}

if (_serialPort != null)

{

if (_serialPort.IsOpen)

_serialPort.Close();

_serialPort.Dispose();

}

}

catch (Exception) { }

}

#endregion

}

/// <summary>

/// EventArgs utilizado para enviar bytes recibidos por el puerto serie.

/// </summary>

public class SerialDataEventArgs : EventArgs

{

public SerialDataEventArgs(byte[] dataInByteArray)

{

Data = dataInByteArray;

}

public byte[] Data;

}

}

SerialSettings.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO.Ports;

using System.ComponentModel;

namespace SerialPortListener.Serial

{

/// <summary>

/// Clase que contiene propiedades relacionadas a un puerto serie

/// </summary>

public class SerialSettings : INotifyPropertyChanged

{

public event PropertyChangedEventHandler PropertyChanged;

string _portName = "";

string[] _portNameCollection;

int _baudRate = 4800;

BindingList<int> _baudRateCollection = new BindingList<int>();

Parity _parity = Parity.None;

int _dataBits = 8;

int[] _dataBitsCollection = new int[] { 5, 6, 7, 8 };

StopBits _stopBits = StopBits.One;

#region Properties

/// <summary>

/// El puerto a usar (por ejemplo, COM1).

/// </summary>

public string PortName

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

121

{

get { return _portName; }

set

{

if (!_portName.Equals(value))

{

_portName = value;

SendPropertyChangedEvent("PortName");

}

}

}

/// <summary>

/// La velocidad de transmisión.

/// </summary>

public int BaudRate

{

get { return _baudRate; }

set

{

if (_baudRate != value)

{

_baudRate = value;

SendPropertyChangedEvent("BaudRate");

}

}

}

/// <summary>

/// Uno de los valores de paridad.

/// </summary>

public Parity Parity

{

get { return _parity; }

set

{

if (_parity != value)

{

_parity = value;

SendPropertyChangedEvent("Parity");

}

}

}

/// <summary>

/// El valor de bits del dato.

/// </summary>

public int DataBits

{

get { return _dataBits; }

set

{

if (_dataBits != value)

{

_dataBits = value;

SendPropertyChangedEvent("DataBits");

}

}

}

/// <summary>

/// Uno de los valores de los bits de stop.

/// </summary>

public StopBits StopBits

{

get { return _stopBits; }

set

{

if (_stopBits != value)

{

_stopBits = value;

SendPropertyChangedEvent("StopBits");

}

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

122

}

}

/// <summary>

/// Los puertos disponibles en el equipo.

/// </summary>

public string[] PortNameCollection

{

get { return _portNameCollection; }

set { _portNameCollection = value; }

}

/// <summary>

/// Velocidades de transmisión disponibles para puerto serie actual.

/// </summary>

public BindingList<int> BaudRateCollection

{

get { return _baudRateCollection; }

}

/// <summary>

/// Bits de datos disponibles para establecer ajuste.

/// </summary>

public int[] DataBitsCollection

{

get { return _dataBitsCollection; }

set { _dataBitsCollection = value; }

}

#endregion

#region Methods

/// <summary>

/// Actualiza la gama de posibles velocidades de transmisión para el dispositivo.

/// </summary>

/// <param name="possibleBaudRates">Parámetro dwSettableBaud de la estructura COMMPROP</param>

/// <returns>Una lista actualizada de valores</returns>

public void UpdateBaudRateCollection(int possibleBaudRates)

{

const int BAUD_075 = 0x00000001;

const int BAUD_110 = 0x00000002;

const int BAUD_150 = 0x00000008;

const int BAUD_300 = 0x00000010;

const int BAUD_600 = 0x00000020;

const int BAUD_1200 = 0x00000040;

const int BAUD_1800 = 0x00000080;

const int BAUD_2400 = 0x00000100;

const int BAUD_4800 = 0x00000200;

const int BAUD_7200 = 0x00000400;

const int BAUD_9600 = 0x00000800;

const int BAUD_14400 = 0x00001000;

const int BAUD_19200 = 0x00002000;

const int BAUD_38400 = 0x00004000;

const int BAUD_56K = 0x00008000;

const int BAUD_57600 = 0x00040000;

const int BAUD_115200 = 0x00020000;

const int BAUD_128K = 0x00010000;

_baudRateCollection.Clear();

if ((possibleBaudRates & BAUD_075) > 0)

_baudRateCollection.Add(75);

if ((possibleBaudRates & BAUD_110) > 0)

_baudRateCollection.Add(110);

if ((possibleBaudRates & BAUD_150) > 0)

_baudRateCollection.Add(150);

if ((possibleBaudRates & BAUD_300) > 0)

_baudRateCollection.Add(300);

if ((possibleBaudRates & BAUD_600) > 0)

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

123

_baudRateCollection.Add(600);

if ((possibleBaudRates & BAUD_1200) > 0)

_baudRateCollection.Add(1200);

if ((possibleBaudRates & BAUD_1800) > 0)

_baudRateCollection.Add(1800);

if ((possibleBaudRates & BAUD_2400) > 0)

_baudRateCollection.Add(2400);

if ((possibleBaudRates & BAUD_4800) > 0)

_baudRateCollection.Add(4800);

if ((possibleBaudRates & BAUD_7200) > 0)

_baudRateCollection.Add(7200);

if ((possibleBaudRates & BAUD_9600) > 0)

_baudRateCollection.Add(9600);

if ((possibleBaudRates & BAUD_14400) > 0)

_baudRateCollection.Add(14400);

if ((possibleBaudRates & BAUD_19200) > 0)

_baudRateCollection.Add(19200);

if ((possibleBaudRates & BAUD_38400) > 0)

_baudRateCollection.Add(38400);

if ((possibleBaudRates & BAUD_56K) > 0)

_baudRateCollection.Add(56000);

if ((possibleBaudRates & BAUD_57600) > 0)

_baudRateCollection.Add(57600);

if ((possibleBaudRates & BAUD_115200) > 0)

_baudRateCollection.Add(115200);

if ((possibleBaudRates & BAUD_128K) > 0)

_baudRateCollection.Add(128000);

SendPropertyChangedEvent("BaudRateCollection");

}

/// <summary>

/// Actualiza la gama de posibles velocidades de transmisión para el dispositivo

/// </summary>

/// <param name="possibleBaudRates">Parámetro dwSettableBaud de la estructura COMMPROP</param>

/// <returns>Una lista actualizada de valores</returns>

public List<int> UpdateBaudRateCollectionInt(int possibleBaudRates)

{

List<int> _baudRateCollection = new List<int>();

const int BAUD_075 = 0x00000001;

const int BAUD_110 = 0x00000002;

const int BAUD_150 = 0x00000008;

const int BAUD_300 = 0x00000010;

const int BAUD_600 = 0x00000020;

const int BAUD_1200 = 0x00000040;

const int BAUD_1800 = 0x00000080;

const int BAUD_2400 = 0x00000100;

const int BAUD_4800 = 0x00000200;

const int BAUD_7200 = 0x00000400;

const int BAUD_9600 = 0x00000800;

const int BAUD_14400 = 0x00001000;

const int BAUD_19200 = 0x00002000;

const int BAUD_38400 = 0x00004000;

const int BAUD_56K = 0x00008000;

const int BAUD_57600 = 0x00040000;

const int BAUD_115200 = 0x00020000;

const int BAUD_128K = 0x00010000;

if ((possibleBaudRates & BAUD_075) > 0)

_baudRateCollection.Add(75);

if ((possibleBaudRates & BAUD_110) > 0)

_baudRateCollection.Add(110);

if ((possibleBaudRates & BAUD_150) > 0)

_baudRateCollection.Add(150);

if ((possibleBaudRates & BAUD_300) > 0)

_baudRateCollection.Add(300);

if ((possibleBaudRates & BAUD_600) > 0)

_baudRateCollection.Add(600);

if ((possibleBaudRates & BAUD_1200) > 0)

_baudRateCollection.Add(1200);

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

124

if ((possibleBaudRates & BAUD_1800) > 0)

_baudRateCollection.Add(1800);

if ((possibleBaudRates & BAUD_2400) > 0)

_baudRateCollection.Add(2400);

if ((possibleBaudRates & BAUD_4800) > 0)

_baudRateCollection.Add(4800);

if ((possibleBaudRates & BAUD_7200) > 0)

_baudRateCollection.Add(7200);

if ((possibleBaudRates & BAUD_9600) > 0)

_baudRateCollection.Add(9600);

if ((possibleBaudRates & BAUD_14400) > 0)

_baudRateCollection.Add(14400);

if ((possibleBaudRates & BAUD_19200) > 0)

_baudRateCollection.Add(19200);

if ((possibleBaudRates & BAUD_38400) > 0)

_baudRateCollection.Add(38400);

if ((possibleBaudRates & BAUD_56K) > 0)

_baudRateCollection.Add(56000);

if ((possibleBaudRates & BAUD_57600) > 0)

_baudRateCollection.Add(57600);

if ((possibleBaudRates & BAUD_115200) > 0)

_baudRateCollection.Add(115200);

if ((possibleBaudRates & BAUD_128K) > 0)

_baudRateCollection.Add(128000);

return _baudRateCollection;

}

/// <summary>

/// Envia un evento PropertyChanged

/// </summary>

/// <param name="propertyName">Nombre de la propiedad cambiada</param>

private void SendPropertyChangedEvent(String propertyName)

{

if (PropertyChanged != null)

PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

}

#endregion

}

}

ModificacionConjuntoMotas.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace SimpleSerial

{

/// <summary>

/// Clase que prepara el conjunto de motas que hay en la red de para representar sus datos en gráficas.

/// </summary>

public class ModificacionConjuntoMotas : EventArgs

{

List<DatosGrafica> datosUltimosGrafica;

/// <summary>

/// Método que actualiza los últimos datos que aparecen en las gráficas.

/// </summary>

/// <param name="listaMotasAPintar">Se pasa una lista con las motas que hay que representar en las gráficas.</param>

public ModificacionConjuntoMotas(List<DatosGrafica> listaMotasAPintar)

{

this.datosUltimosGrafica = listaMotasAPintar;

}

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

125

/// <summary>

/// Obtiene la sesión actual de motas que hay en la Wireless Sensor Networks

/// </summary>

public List<DatosGrafica> MotasSesionActual

{

get

{

return this.datosUltimosGrafica;

}

}

}

}

AcercaDe.cs

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Diagnostics;

using System.IO;

namespace SimpleSerial

{

/// <summary>

/// Clase que indica la información de la aplicación y los datos del diseñador de la App.

/// </summary>

public partial class AcercaDe : Form

{

public AcercaDe()

{

InitializeComponent();

}

/// <summary>

/// Método que te redirecciona al correo electrónico del creador de la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento LinkLabelLinkClickedEventArgs.</param>

private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)

{

try

{

Process.Start("mailto:" + "[email protected]" + "?subject=" + "Communication Gateway - Contacto" + "&body=" +

"");

}

catch (Exception ex)

{

MessageBox.Show("Error", "No ha sido posible inicializar la aplicación de correo. Mensaje interno: " + ex.Message,

MessageBoxButtons.OK, MessageBoxIcon.Information);

}

}

/// <summary>

/// Método que abre un documento de auçyuda de la App.

/// </summary>

/// <param name="sender">Objeto sender.</param>

/// <param name="e">Evento EventArgs.</param>

private void button2_Click(object sender, EventArgs e)

{

string rutaArchivo = Path.Combine(Application.StartupPath, "Resources", "Apendice_A.pdf");

DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA

126

try

{

Process.Start(rutaArchivo);

}

catch (Exception ex)

{

MessageBox.Show("Error", "No ha sido posible mostrar el archivo de ayuda. Mensaje interno: " + ex.Message,

MessageBoxButtons.OK, MessageBoxIcon.Information);

}

}

}

}