PFC Guillermo José Núñez Sánchez

Anuncio
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
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
1
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
2
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
3
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
.
4
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
5
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
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.
7
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
• 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.
8
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
9
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
10
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
•
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
11
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
12
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
13
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
14
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
15
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
16
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
17
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
18
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
19
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
20
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
•
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
21
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
22
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
23
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
24
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
25
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
26
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
•
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.
27
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
28
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
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.
30
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
31
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
32
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
•
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.
33
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
34
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
ON
Sleep
Deep Sleep
Hibernate
Consumo
9mA
62μA
62μA
0,7μA
Micro
ON
ON
ON
OFF
Ciclo
32ms - 8s
8s - min/horas/días
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.
35
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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++.
36
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
XBee-802.15.4
XBee-802.15.4-Pro
XBee-ZB
XBee-ZB-Pro
XBee-868
XBee-900
XBee-XSC
Protocolo
802.15.4
802.15.4
ZigBee-Pro
ZigBee-Pro
RF
RF
RF
Frecuencia
2.4GHz
2.4GHz
2.4GHz
2.4GHz
868MHz
900MHz
900MHz
txPower
1mW
100mW
2mW
50mW
315mW
50mW
100mW
Sensibilidad
-92dB
-100dBm
-96dBm
-102dBm
-112dBm
-100dBm
-106dBm
Rango
500m
7000m
500m
7000m
12km
10Km
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
XBee-ZB-Pro
Protocolo
ZigBee-Pro
Frecuencia
2.4GHz
txPower
50mW
Sensibilidad
-102dBm
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.
37
Rango*
7000m
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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 XCTU. 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.
38
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
39
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
Scan Channel
102030405060708
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
00:13:A2:00:40:60:75:DA/E3/DF)
API
40
(XBee
con
dirección
MAC
=
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
41
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
42
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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#.
43
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
44
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
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:
46
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
AT Command
AT Command – Queue Parameter Value
ZigBee Transmit Resquet
Explicit Addressing ZigBee Command Frame
Remote Command Request
Create Source Route
AT Command Response
Modem Status
ZigBee Transmit Status
ZigBee Receive Packet (AO=0)
ZigBee Explicit Rx Indicator (AO=1)
ZigBee IO Dta Sample Rx Indicator
XBee Sensor Read Indicator (AO=0)
Node Identification Indicator (AO=0)
Remote Command Response
Over-the-Air Firmware Update Status
Route Record Indicator
Many-to-One Route Request Indicator
Tabla 6: Valores y nombres de las API Frame.
47
API ID
0x08
0x09
0x10
0x11
0x17
0x21
0x88
0x8A
0x8B
0x90
0x91
0x92
0x94
0x95
0x97
0xA0
0xA1
0xA3
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
Start Delimiter
Length
Frame Type
Frame ID
Tamaño
1 Byte
2 Byte
1 Byte
1 Byte
Ejemplo
0x7E
0x00, 0x04
0x08
0x52
AT Command
2 Byte
0x43 (C)
0x48 (H)
Parameter Value
(Opcional)
Checksum
1 Byte
0x0D
Descripción
Indicador de comienzo de trama.
Números de bytes entre el campo Length y Checksum.
Tipo de trama
Subsecuencia para comunicación entre host y device. Si es
0 no se envía ACK.
Nombre del comando. Dos caracteres ASCII para identificar
el AT Command
Si no presenta parámetro indica que el comando es para
lectura de dicho parámetro. Si no es para establecerlo
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.
48
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
AT Command Response
Campos de la Trama
Start Delimiter
Length
Frame Type
Frame ID
Tamaño
1 Byte
2 Byte
1 Byte
1 Byte
Ejemplo
0x7E
0x00, 0x06
0x88
0x01
AT Command
2 Byte
0x44 (D)
0x42 (B)
Command Status
1 Byte
0x00
1 Byte
0xA1
Command Data
Checksum
Descripción
Indicador de comienzo de trama.
Números de bytes entre el campo Length y Checksum.
Tipo de trama
Subsecuencia para comunicación entre host y device. Si es
0 no se envía ACK.
Nombre del comando. Dos caracteres ASCII para identificar
el AT Command
0 = OK
1 = ERROR
2 = Invalid Command
3 = Invalid Parameter
4 = Tx Failure
En este campo aparece el dato que se ha requerido. Si no
presenta parámetro es porque en la trama AT Command
se estableció.
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
Start Delimiter
Length
Frame Type
Frame ID
64-bit Destination
Address
Tamaño
1 Byte
2 Byte
1 Byte
1 Byte
8 Byte
Ejemplo
Descripción
0x7E
0x00, 0x16
0x10
0x01
Indicador de comienzo de trama.
Números de bytes entre el campo Length y Checksum.
Tipo de trama
Subsecuencia para comunicación entre host y device. Si es 0 no se
envía ACK.
0x00,0x13,0xA2,0x00, Se establece la dirección MAC del dispositivo destino. También se
0x40,0x60,0x75,0xDA pueden poner las siguientes direcciones: 0x0000000000000000
coordinator y 0x000000000000FFFF Broadcast
Se establece la dirección de red si es conocida o 0xFFFE que es la
0xFF, 0xFE
dirección de broadcast
16-bits
Destination
Address
2 Byte
Broadcast Radius
1 Byte
0x00
Options
1 Byte
0x00
RF Data
Checksum
N Bytes
1 Byte
0x0D
Establece el número de saltos permitidos del paquete. Si es 0 se
establece el máximo números de saltos.
Opciones para la Tx
0x20 - Habilita APS
0x40 - Usa el tiempo máximo Tx
Campo para introducir los datos que se quieren enviar
Es la operación 0xFF – la suma de todos los byte entre Length y
Checksum.
49
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
:
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.
50
1
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
ZigBee Receive Packet
Campos de la
Trama
Start Delimiter
Length
Frame Type
Tamaño
64-bit Destination
Address
8 Byte
1 Byte
2 Byte
1 Byte
Ejemplo
Descripción
0x7E
0x00, 0x11
0x90
0x00,0x13,0xA2,0x00,
0x40,0x60,0x75,0xDA
16-bits
Destination
Address
2 Byte
0x7D, 0x84
Receive Options
1 Byte
0x01
Receive Data
Checksum
N Bytes
1 Byte
0x0D
Indicador de comienzo de trama.
Números de bytes entre el campo Length y Checksum.
Tipo de trama
Se establece la dirección MAC del dispositivo destino.
También se pueden poner las siguientes direcciones:
0x0000000000000000 coordinator y
0x000000000000FFFF Broadcast
Se establece la dirección de red si es conocida o 0xFFFE
que es la dirección de broadcast
0x01 - Packet Acknowledged
0x02 - Packet was a broadcast packet
0x20 - Packet encrypted with APS encryption
Campo de los datos que se reciben
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.
51
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
52
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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);
53
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
//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);
54
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
}
//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);
}
55
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
56
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
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.
58
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
Figura 38: Diagrama de Estados General
59
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
60
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
Figura 39: Diagrama de clases de la App.
61
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
62
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
63
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
64
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
65
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
66
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
67
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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:
68
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
Figura 51: Instalador de la aplicación Utilidad Gestión Motas.
Figura 52: Directorio donde se alojará la aplicación.
69
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
Figura 53: Confirmación de la instalación.
Figura 54: Instalando Utilidad de gestión de motas.
70
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
Figura 55: Instalación completada.
Figura 56: Icono de la aplicación Utilidad Gestión Motas.
71
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
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
Desarrollo
aplicación
Memoria
Total global
Días efectivos
115
Horas/día media
2
Total horas
230
32
-
1
-
32
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
Desarrollo aplicación
Memoria
Total global
Horas
230
32
-
Coste horas
19 €
19 €
-
Total coste
4370 €
608 €
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.
73
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
74
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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/
75
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
[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/
76
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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:
77
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
78
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
79
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
80
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
81
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
82
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
83
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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.
84
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
APÉNDICE B: DIAGRAMAS DE CLASES
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
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;
86
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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>();
87
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
#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>
88
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// 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.
89
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// </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;
}
}
90
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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();
91
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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
92
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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);
93
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
}
}
}
//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
94
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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;
95
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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];
96
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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>
97
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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;
98
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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;
99
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
}
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);
100
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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;
101
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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: " +
102
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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";
103
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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;
104
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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>
105
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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
106
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
#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>
107
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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>
108
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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>
109
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// 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.
110
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// </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.
111
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// </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>
112
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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>
113
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// 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 });
114
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
}
/// <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>
115
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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();
}
116
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
}
}
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
117
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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();
}
118
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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
119
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
{
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
120
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
{
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");
}
121
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
}
}
/// <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)
122
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
_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);
123
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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;
}
124
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
/// <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:" + "g.nun.san@gmail.com" + "?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");
125
DISEÑO DE APLICACIÓN EN C# PARA GESTIÓN DE RED DE SENSORES INALÁMBRICA
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);
}
}
}
}
126
Descargar