Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la...

78
Raúl Hernáez Ojeda María Vico Pascual Martínez-Losa Facultad de Ciencia y Tecnología Grado en Ingeniería Informática 2015-2016 Título Director/es Facultad Titulación Departamento TRABAJO FIN DE GRADO Curso Académico Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es

Transcript of Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la...

Page 1: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

Raúl Hernáez Ojeda

María Vico Pascual Martínez-Losa

Facultad de Ciencia y Tecnología

Grado en Ingeniería Informática

2015-2016

Título

Director/es

Facultad

Titulación

Departamento

TRABAJO FIN DE GRADO

Curso Académico

Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin

Autor/es

Page 2: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

© El autor© Universidad de La Rioja, Servicio de Publicaciones, 2016

publicaciones.unirioja.esE-mail: [email protected]

Implementación de un SDK para la plataforma ConnectCore 6 y el frameworkXamarin, trabajo fin de grado

de Raúl Hernáez Ojeda, dirigido por María Vico Pascual Martínez-Losa (publicado por la Universidad de La Rioja), se difunde bajo una Licencia

Creative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0 Unported. Permisos que vayan más allá de lo cubierto por esta licencia pueden solicitarse a los

titulares del copyright.

Page 3: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

Facultad de Ciencia y Tecnología

TRABAJO FIN DE GRADO

Grado en Ingeniería Informática

Implementación de un SDK para la plataforma ConnectCore

6 y el framework Xamarin

Alumno:

Raúl Hernáez Ojeda

Tutores:

María Vico Pascual Martínez Losa

Logroño, junio, 2016

Page 4: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

1

Digi International, Inc. ha desarrollado en Java un conjunto de APIs para sistemas embebidos que extienden la funcionalidad del propio kit de Android. Ahora se pretende que dichas APIs también estén disponibles en C# mediante Xamarin Platform. Este proyecto consiste en establecer un puente JNI (Java Native Interface) sobre las clases del JAR de Android y encapsular las llamadas en forma wrappers. Con las APIs resultantes podremos crear una aplicación que simule un caso de uso real de los periféricos e interfaces industriales de un ConnectCore 6.

Digi International, Inc. has developed a set of Java APIs to access many peripherals and interfaces present in most embedded systems. The challenge is now to make them available in the C# language with the help of Xamarin Platform. This project involves building a JNI (Java Native Interface) bridge to the Android JAR and encapsulating these calls in wrappers. The resulting APIs will allow us to create an application that works with the ConnectCore 6 hardware and all its interfaces.

Page 5: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

2

RESUMEN ..............................................................................................................................................................................................................1

ÍNDICE ..................................................................................................................................................................................................................... 2

1. INTRODUCCIÓN ..................................................................................................................................................................................... 3

1.2. No todo es Java .............................................................................................................................................................................. 4

1.3. Objetivos .............................................................................................................................................................................................. 4

2. ANÁLISIS ..................................................................................................................................................................................................... 5

2.1. Requisitos funcionales .......................................................................................................................................................... 5

2.2. Requisitos no funcionales .................................................................................................................................................. 6

3. ESTUDIO DE VIABILIDAD ................................................................................................................................................................ 6

3.1. Los engranajes de Xamarin ............................................................................................................................................... 6

3.2. Las APIs de Digi............................................................................................................................................................................... 7

3.3. Conclusiones ................................................................................................................................................................................... 8

4. PLANIFICACIÓN ..................................................................................................................................................................................... 9

4.1. Alcance .................................................................................................................................................................................................. 9

4.2. Cronograma ...................................................................................................................................................................................... 11

4.3. Planes adicionales ................................................................................................................................................................... 13

5. DESARROLLO DEL SDK ................................................................................................................................................................. 16

5.1. SPI API ................................................................................................................................................................................................... 16

5.2. GPIO API .............................................................................................................................................................................................. 23

6. SEGUIMIENTO Y CONTROL (I) ................................................................................................................................................ 30

7. REVISIÓN DEL SDK ..........................................................................................................................................................................28

8. APLICACIÓN DE EJEMPLO .......................................................................................................................................................... 32

9. SEGUIMIENTO Y CONTROL (II) ............................................................................................................................................... 42

10. APLICACIÓN DE EJEMPLO (II) ................................................................................................................................................. 44

11. SEGUIMIENTO Y CONTROL (III) ............................................................................................................................................. 48

12. CONCLUSIONES ................................................................................................................................................................................ 50

13. BIBLIOGRAFÍA ...................................................................................................................................................................................... 52

Anexo 1: diagramas de clases......................................................................................................................................................... 53

Anexo 2: funcionamiento de ACWs en Xamarin ........................................................................................................... 64

Anexo 3: datos de osciloscopio..................................................................................................................................................... 65

Anexo 4: diagrama de casos de uso ......................................................................................................................................... 67

Anexo 5: descripción de casos de uso .................................................................................................................................... 68

Anexo 6: pruebas unitarias ................................................................................................................................................................ 71

Anexo 7: actas de reunión .................................................................................................................................................................. 73

Page 6: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

3

1. Aunque cueste creerlo, Android era un sistema operativo para móviles prácticamente desconocido cuando, en 2005, Google lo compró. El crecimiento fue imparable desde entonces: en 2014, ya se había hecho con aproximadamente el 35% del mercado en el sector de la telefonía móvil, y a día de hoy consolida su liderazgo acaparando casi el 60% de la cuota. Como suele ser habitual, el baile de cifras varía de forma considerable1 según la fuente de la que provenga, pero hay una cuestión clara, y es que la plataforma del androide verde supone una opción bastante suculenta para los desarrolladores.

Desde 2009, Google proporciona un kit de desarrollo software (más conocido por sus siglas en inglés; SDK) que posibilita la creación de aplicaciones para su sistema operativo. La mayor parte de estas aplicaciones están escritas en Java, el cual mantiene una lucha constante por el primer puesto de popularidad en el índice Tiobe2. No sabemos quién tiene que agradecerle qué a quién, pero sí podemos decir que la relación que mantiene Android con Java parece, al menos de momento, de simbiosis perfecta.

No es de extrañar que, a medida que el éxito de un producto aumenta, éste tenga que adaptarse para cubrir nuevas necesidades tecnológicas. En el caso de Android, lo que en un principio fue concebido como un sistema operativo para dispositivos móviles, se ha extendido a videoconsolas, televisiones, relojes de pulsera, automóviles e incluso sistemas embebidos. Y es aquí donde precisamente entran en juego la empresa Digi International Inc. y la motivación de este proyecto.

Aunque los datos dibujen un panorama bastante alentador para Android, su uso en el ámbito de los sistemas embebidos sigue suponiendo un desafío. La versión estándar de Android no proporciona APIs (Application Programming Interfaces) para acceder a los periféricos e interfaces industriales3 presentes en la mayoría de estos sistemas. Es por ello que tanto desarrolladores de firmware como de software deben ponerse manos a la obra e implementar su propio código, lo cual no es del todo trivial. Esta tarea requiere conocimiento específico sobre la arquitectura interna de Linux.

Actualmente, Digi International Inc. ofrece una capa de abstracción de alto nivel que permite acceder a varias interfaces industriales. Dicha capa recibe el nombre de APIX (o APIs de Digi), y da soporte a un total de nueve interfaces. Cualquier usuario que disponga de estas APIs y del hardware adecuado (en concreto, un ConnectCore 64) podrá beneficiarse de la nueva funcionalidad. Las oportunidades de negocio que brindan los sistemas embebidos son amplias y tan variadas que van desde el sector energético hasta la medicina, pasando por el simple entretenimiento, la domótica y las fuerzas de seguridad. Foruno Electric, una empresa japonesa que distribuye electrónica naval, utiliza el

1 Estos son los datos que se desprenden de las estadísticas que gestionan NetMarketShare y StatCounter, dos de las empresas más importantes analizando el mercado. Otras consultoras, como Gartner e IDC (International Data Corporation), sitúan la cuota global de Android en torno al 85% desde 2015. KantarWordPanel, por su parte, realiza una comparativa por países donde la cuota supera el 70% en Europa, pero disminuye hasta el 55% en Estados Unidos. 2 El índice Tiobe es un indicador de popularidad de lenguajes de programación, cuyos resultados se obtienen a partir de 25 motores de búsqueda. Hoy en día, se considera un estándar de facto a la hora de medir el interés por cada lenguaje. 3 Algunos ejemplos son: GPIO (General Purpose Input Output), SPI (Serial Peripheral Interface), I2C (Inter-Integrated Circuit) y CAN (Controller Area Network). 4 El ConnectCore 6 es una placa computadora fabricada por Digi International Inc. Funciona sobre una versión del núcleo Linux y Android modificada.

Page 7: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

4

ConnectCore 6 en uno de sus radares. La última cámara termográfica de Flir Systems, con sede en Estados Unidos, también se basa en esta tecnología. Y así podríamos continuar con un largo etcétera de aplicaciones.

El término ‘embebido’ hace referencia al carácter modular de estos dispositivos, diseñados para resolver un problema concreto dentro del sistema mayor en el que están integrados. Esto, sin duda, constituye una importante ventaja en costes, portabilidad y mantenimiento respecto a las soluciones industriales tradicionales, lo que permite crear productos más compactos y simplificar su diseño.

1.1. El núcleo de Android, siendo Linux, está escrito en C++, pero el entorno de ejecución es una implementación de máquina virtual de Java llamada ART (Android Runtime). Las aplicaciones se compilan primero a bytecode de Java como ficheros de extensión .class, y luego se convierten a archivos .dex, que son los que la máquina virtual puede entender5. La figura 1 representa este proceso de forma esquematizada.

Figura 1. Compilación de ficheros en Android.

Podríamos afirmar, en vista de lo explicado, que si un desarrollador quiere programar para Android debe pasar obligatoriamente por el aro de Java: nada más lejos de la realidad. Xamarin es una compañía establecida en mayo de 2011 por los mismos ingenieros que crearon Mono, una implementación libre de la plataforma .NET para dispositivos Android, iOS y GNU/Linux.

La alternativa que propone Mono es sencilla: sustituir Java por C#, dejando el resto de la arquitectura intacta. Este no es asunto baladí, ya que C# se encuentra entre los tres lenguajes de programación orientada a objetos más usados del mundo. Además, muchas de las herramientas de Xamarin se integran con Visual Studio (Microsoft adquirió la compañía en marzo de este mismo año), por lo que un desarrollador de .NET tendrá la posibilidad de acercarse a Android sin salir del entorno y el lenguaje que domina.

El funcionamiento de Mono, sin embargo, es mucho más complejo, y se irá detallado progresivamente a lo largo de este proyecto.

1.2. Tal y como hemos indicado en la introducción, Digi International, Inc. ha desarrollado en Java un conjunto de APIs que extienden la funcionalidad del kit estándar de Android. El principal objetivo de este proyecto es crear un SDK que permita a un futuro cliente de Digi programar en C# para sus sistemas embebidos en vez de en Java. El usuario añadirá la

5 Puesto que ART no trabaja directamente con bytecode de Java, es técnicamente incorrecto referirse a él como una máquina virtual de Java. Aun así, es muy común oír esta nomenclatura.

Page 8: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

5

nueva librería a su proyecto y tendrá la sensación de que Android trabaja de forma nativa en C#, ya que estará accediendo a la funcionalidad de Java con total transparencia.

Además, se escribirá una guía de iniciación para que un usuario inexperto sufra el menor número de problemas posibles. Incluirá desde el proceso de instalación de Xamarin hasta un primer contacto con la librería. Finalmente, intentaremos simular un caso de uso real de las APIs del SKD a través de una aplicación de ejemplo.

2. El proyecto se dio a conocer en una reunión que tuvo lugar a finales de octubre de 2015. En ella, se plantearon los objetivos principales del SDK y los requisitos mínimos que debía satisfacer.

2.1. - Estará escrito en C# y se desarrollará a través de la plataforma Xamarin. - El usuario podrá utilizarlo en forma de .dll o similar, y funcionará, como mínimo, en

otros proyectos de Xamarin. Opcional alargar su compatibilidad hacia otros IDEs que utilicen C#, como Unity6.

- Consistirá en un conjunto de APIs para acceder a las interfaces de Digi no soportadas por las APIs de Xamarin. Tomando como referencia la última versión del firmware (Android 5.1), las interfaces a traducir serán nueve:

- GPIO (General Purpose Input Output). - SPI (Serial Peripheral Interface). - Watchdog. - ADC (Analog Digital Converter). - PWM (Pulse Width Modulation). - CAN (Controller Area Network). - I2C (Inter Integrated Circuit). - CPU Temperature. - Serial.

- La funcionalidad disponible en la APIS de C# será exactamente la misma que la de las

APIs de Java. - La parte pública de las APIs de C# será exactamente la misma que la de las APIs de

Java. Esto incluirá: clases, métodos, atributos y excepciones. Se permitirán algunas diferencias menores con tal de adaptarla a las reglas del nuevo lenguaje, por ejemplo:

- Cambio de cabeceras. Los métodos podrán renombrarse siguiendo la convención Microsoft (que siempre empiecen con mayúscula).

- Supresión de getters y setters. Los métodos de tipo GET y SET podrán transformarse en propiedades si se diesen las condiciones necesarias para ello.

- Cada API tendrá su propia miniaplicación de ejemplo, que será exactamente la misma (a nivel funcional) que la que ofrece Digi International Inc. en el SDK de Java.

6 Unity es una de las plataformas para desarrollar videojuegos más completas que existen. El comportamiento de los objetos que componen el videojuego se define con la ayuda de scripts, que pueden estar escritos en C#. Al igual que en Xamarin, el scripting se basa en Mono.

Page 9: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

6

2.2. - La parte pública estará documentada tanto en el código fuente (siguiendo la

convención de .NET) como en un servidor aparte, llamado Confluence7. Las miniaplicaciones de ejemplo de sólo se documentarán en el código fuente.

- Vendrá acompañado de una guía de iniciación destinada a los usuarios que vayan a usar Xamarin y las APIs de Digi por primera vez. La guía estará disponible también en Confluence.

- No se aceptarán grandes penalizaciones de rendimiento respecto a Java. - Deberá programarse de tal forma que se facilite el mantenimiento. Si las APIs de Java

sufren algún cambio, asegurarse de que en C# haya que hacer los mínimos posibles.

3. Todo proyecto informático conlleva cierto grado de incertidumbre que debemos evitar, cuanto antes mejor, buscando información y adquiriendo la formación necesaria. Si el proyecto resulta viable, podremos planificarlo con exactitud (puesto que ya sabemos a qué nos enfrentamos) y tomar decisiones con mayor facilidad.

Tras recoger los requisitos del SDK, iniciamos un estudio de viabilidad que consistió en tres partes:

1. Consultar la documentación de la página web de Xamarin. 2. Estudiar las APIs de Digi. 3. Traducir una miniaplicación de ejemplo aplicando la tecnología que se estudió en

la documentación de Xamarin.

De estas tres partes se concluyó finalmente que sí era posible realizar el proyecto. A continuación, se incluye un resumen de cada una de ellas:

3.1. La documentación de Xamarin es clara a la hora de describir el funcionamiento de la plataforma. Recordando lo que se explicó en la introducción, Xamarin permite escribir aplicaciones Android con C# en vez de con Java. Éste proporciona varios archivos DLL (dynamic-link librarys) en forma de enlaces (bindings) hacia las librerías de Java. El .dll que nos interesa en este caso es Mono.Android, ya que es el que da soporte a casi todos los tipos del JAR de Android.

Sabemos que Mono.Android es el equivalente en C# al JAR de Android, pero ¿cómo consigue Xamarin establecer este enlace? La respuesta es más simple de lo que parece: con llamadas a la JNI (Java Native Interface), un conjunto de interfaces que permiten interactuar con la máquina virtual de Java. De este modo, es posible que los métodos escritos en C# ejecuten código Java; y también al revés, que el código Java ejecute métodos escritos en C#.

7 Confluence es la aplicación web que utiliza Digi International Inc. para gestionar contenido colaborativo, como la documentación elaborada por los distintos equipos de trabajo. Creado por la empresa Attlassian.

Page 10: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

7

Las clases que componen Mono.Android.dll, por tanto, no son más que envoltorios (wrappers) que intentan enmascarar todas esas llamadas a la JNI, pero ofreciendo las mismas cabeceras que el JAR de Android. Con todo, Xamarin distingue dos tipos de wrappers en función del sentido en que se realice la comunicación:

- MCW (Managed Callable Wrappers). Enlaces simples hacia una clase Java o interfaz. Tienen dos objetivos: encapsular las llamadas a la JNI para que el cliente no vea la complejidad subyacente, y posibilitar las relaciones de herencia y de implementación de interfaces. El primer objetivo es estético y de usabilidad. Esto quiere decir que podríamos conseguir lo mismo escribiendo JNI en bruto, sin encapsularlo en clases. Para cumplir el segundo objetivo, sin embargo, los MCWs son obligatorios.

- ACW (Android Callable Wrappers). Se utilizan cuando ART necesita invocar código escrito en C#, ya que no hay forma de que la máquina virtual registre las clases en tiempo de ejecución. Cada vez que Android tiene que ejecutar un método virtual o interfaz que ha sido sobreescrito o implementado en C#, Xamarin debe crear un proxy Java que delegue ese método al tipo C# apropiado. Los proxys Java tienen las mismas clases padre e interfaces Java que su correspondiente tipo C#.

La figura 2 representa la arquitectura de Mono, según la documentación oficial.

Figura 2. Arquitectura de Mono para Android.

3.2. En un primer vistazo a las APIs de Digi, apreciamos que comparten una estructura común:

- Clase de gestión en la que se delega la instanciación del objeto, llamada <nombre>Manager.

- Clase <nombre> del objeto en sí, que coincide con el periférico o interfaz al que da nombre la API.

- Clases de enumeración con constantes. Reúnen valores que resultan útiles para configurar el periférico.

- Interfaz que actúa como listener del objeto.

Page 11: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

8

Todas las APIs que disponen de un listener (5 de 9) aplican un conocido patrón de comportamiento, el patrón observer. El objeto <nombre>, que adquiere el rol de sujeto, posee un estado. Cuando su estado cambia, éste se encarga de informar de forma activa a todos los objetos que hayan decidido suscribirse, llamados observadores. La interfaz I<nombre>Listener incluye un método que tendrán que implementar las clases que deseen recibir notificaciones. Dicho método tiene un parámetro con información sobre la actualización.

También se observa que todas las APIs son independientes entre sí. No hay relaciones de importación (cláusula import) que nos obliguen a traducirlas en un orden determinado. Tampoco hay diferencias notables en cuanto a complejidad o extensión, a excepción del API Serial, que define muchos más métodos y clases que el resto. Además, hay que tener en cuenta que varios métodos no reciben como parámetro objetos y tipos nativos de Android, sino de las propias APIs de Digi. Aunque parezca una obviedad, veremos que terminará influyendo en el diseño.

Las miniaplicaciones de ejemplo, por su parte, se limitan a mostrar una sola ventana con elementos básicos: botones, listas desplegables, imágenes, campos de texto y etiquetas. El usuario comprueba el funcionamiento de la API interactuando con ellos. No hay nada especial que destacar.

3.3. En la última parte del estudio de viabilidad traducimos la miniaplicación de ejemplo del API del GPIO, llamada GPIOSample. Realizamos llamadas a la JNI en bruto (sin wrappers) para comprobar que efectivamente se establecía una comunicación entre C# y Java. Además, descubrimos que el uso de esta tecnología en Xamarin requería una licencia de pago.

3.4. Una vez acabado el estudio de viabilidad, se llegaron a las siguientes conclusiones:

- La creación del SDK de C# seguirá las mismas pautas que sigue Xamarin para hacer el binding de todas las clases Android. Es decir, utilizaremos wrappers ACW y MCW sobre las APIs de Digi.

- Xamarin ofrece una clase para comunicarse con la JNI, llamada JNIEnv. La implementación de los wrappers consistirá prácticamente en utilizar dicha clase.

- Como la especificación e implementación de JNIEnv son específicas de Xamarin, se descarta del todo que la librería funcione en otros IDEs, tal y como habíamos planteado en los requisitos. Ni siquiera compilaría la nueva librería, a menos que en el proyecto se incluyera también Mono.Android. No obstante, se realizará una prueba en Unity para zanjarlo definitivamente.

Page 12: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

9

4. Este proyecto comenzó a desarrollarse el 1 de febrero de 2016, es decir, a principios del segundo semestre. Sin embargo, se llevó a cabo una fase de estudio en la empresa Digi International Inc. durante el período de prácticas del primer semestre, concretamente en la primera quincena de diciembre de 2015.

4.1. A continuación, vamos a definir el alcance del proyecto en función de sus entregables y un EDT (estructura de descomposición del trabajo), el cual corresponde a la figura 3.

Los entregables relacionados con el producto son los siguientes:

- ETFG-11. SDK de todas las APIs de C# y miniaplicaciones de ejemplo. - ETFG-12. Guía rápida de iniciación. - ETFG-13. Aplicación de ejemplo que haga uso de las APIs del SDK.

Entre los entregables de planificación y gestión, están:

- ETFG-21: planificación del proyecto, cuya estructura corresponde a la de esta sección. Contiene el alcance del proyecto, información sobre las tareas a realizar y otros planes adicionales.

- ETFG-22: informe de seguimiento y control del proyecto. Se recogerán el período de ejecución, el tiempo de ejecución y desviaciones de las tareas. Se explicarán las desviaciones significativas.

- ETFG-23: memoria del trabajo de fin de grado. Incluye los documentos ETFG-21 y ETF-22.

Otros entregables:

- ETFG-31: copia en papel de ETFG-23 y tres copias en formato digital (CD). - ETFG-32: presentación con diapositivas del proyecto.

Page 13: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

10

Figura 3. Estructura de descomposición del trabajo (EDT)

1. P

roye

cto

de

fin

de

grad

o

1.1 SDK

1.1.1 Análisis de requisitos

1.1.2 Estudio de viabilidad

1.1.3 Diseño

1.1.4 Implementación

1.1.5 Pruebas

1.2 Manual de usuario

1.3 Gestión

1.3.1 Planificar

1.3.2 Seguimiento y control

1.3.3 Escribir memoria

1.3.4 Reunirse

1.4 Defensa

1.4.1 Crear presentación

1.4.2 Exponer1.5 Aplicación de

ejemplo

Page 14: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

11

4.2. Al computar como 12 créditos ECTS, disponemos de un máximo de 300 horas. La creación del SDK y la guía de iniciación ocuparán 187 y 15 horas, respectivamente, mientras que en las actividades de gestión emplearemos unas 35. Por último, se espera que todo lo relacionado con la defensa del proyecto no supere las 8 horas. Aunque esto sólo hace un total de 245 horas, se espera completar las 300 implementado una aplicación de ejemplo. Planificaremos la aplicación -SECCIÓN: seguimiento y control (I)- tan pronto como sepamos en qué consiste.

La tabla 1 recoge las tareas en las que hemos descompuesto el proyecto, así como una pequeña descripción y el tiempo que les hemos adjudicado. La columna ‘ENT.’ indica si la tarea generará o no alguno de los entregables mencionados arriba. Utilizaremos una metodología incremental en las fases de diseño, implementación y pruebas del SDK. Cada iteración durará una semana y abarcará una de las APIs de Java, además de la miniaplicación de ejemplo. Por tanto, y considerando el número de horas planificadas, podemos dividir las iteraciones según la tabla 2.

Id. NOMBRE DESCRIPCIÓN ENT. ESTIMACIÓN

1.1 Crear SDK Análisis de requisitos, estudio de

viabilidad, diseño, implementación y pruebas

187 h.

1.1.1 Análisis de requisitos

Identificación de requisitos funcionales y no funcionales 1 h.

1.1.2 Estudiar viabilidad

Fase de estudio y verificación de si es posible realizar el proyecto 15 h.

1.1.3 Diseño Elaboración de diagramas de clase para cada API 9 h.

1.1.4 Implementación Elaboración del wrapper y documentación de cada API 153 h.

1.1.5 Pruebas Pruebas de cada API completa y

corrección de errores 9 h.

1.2 Manual de usuario

Elaboración de una guía de iniciación para los usuarios 15 h.

1.3 Gestión Planificación y seguimiento del desarrollo del proyecto 35 h.

1.3.1 Planificación Elaboración de la planificación inicial del proyecto 10 h.

1.3.2 Seguimiento y

control Control del proyecto y elaboración del

informe de seguimiento 5 h.

1.3.3 Escribir memoria

Elaboración de la memoria del proyecto de fin de grado 15 h.

1.3.4 Reunirse Reuniones en la empresa, con el tutor académico y actas 5h

1.4 Defensa Presentación y exposición 8 h.

1.4.1 Crear presentación

Elaboración de presentación con diapositivas 7 h. 30 min.

1.4.2 Exponer Exposición del proyecto frente a la comisión 30 min.

1.5 Aplicación de

ejemplo -

55 h.

Tabla 1. Descripción y asignación de horas de las tareas.

Page 15: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

12

Fase

Diseño Implementación Pruebas Horas/iteración 1h 17h 1h

Tabla 2. Asignación media de horas por iteración.

Al principio, se barajó una metodología SCRUM para no romper el marco de trabajo de la empresa, pero como se seguiría de forma muy poco rígida (hasta el punto de parecer una metodología ágil a secas8), finalmente nos decantamos por esta última.

La razón de no incluir la fase de análisis dentro de las iteraciones es que la captura de requisitos inicial servirá para todas las APIs. Las fases de implementación y pruebas también engloban a la miniaplicación de ejemplo correspondiente. No ocurre lo mismo con la fase de diseño, ya que la miniaplicación tiene que ser exactamente igual que la de Java (tanto a nivel de interfaz gráfica como de organización de clases y métodos) y no hay nada que diseñar.

Por último, se decide ordenar las APIs en base a si presentan o no interfaces. Primero traduciremos dos APIs cortas y sin interfaces, SPI e I2C; luego, GPIO (con una interfaz) y a partir de ahí el orden será aleatorio. De esta forma, nos familiarizaremos con la programación en JNI antes de afrontar un problema más complejo.

El proyecto se desarrollará a lo largo de 21 semanas que vienen marcadas por el calendario académico del curso 2015/2016. La figura 4 muestra gráficamente la nomenclatura que utilizaremos para referirnos a las semanas en los diagramas de Gantt (figura 5) y de hitos (figura 6).

Figura 4. Calendario académico para el curso 2015/2016

8 De haberse implantado SCRUM, el alumno habría adquirido todos los roles: product owner, scrum master y equipo de desarrollo. Tampoco hubo indicios de que la empresa pretendiera realizar las reuniones que caracterizan a esta metodología.

Page 16: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

13

Los principales hitos del proyecto se detallan a continuación:

Presentación del proyecto: S0, primera quincena de diciembre. Finalización del SDK: S11, 13 de abril. Entrega al tutor: S19, entre 6 y 10 de junio. Entrega del proyecto: S21, entre 22 y 24 de junio Defensa del proyecto: a partir de S23, primera quincena de julio.

4.3. La tabla 3 identifica el material que emplearemos en el proyecto y su método de adquisición.

ADQUISICIÓN FORMA VENDEDORES PRINCIPALES

TÉRMINOS

Xamarin Platform Descarga desde la página oficial

Xamarin Licencia INDIE ($25/mes)

APIs de Java para ConnectCore6

Solicitud de permiso en Stash9

Digi International, Inc. Sin contrato

Tabla 3. Plan de adquisiciones.

Por otro lado, la comunicación con la tutora será a través de correo electrónico y pidiendo reuniones cuando sea necesario (plan de comunicaciones). Se deja a un lado el plan de riesgos porque la mayor parte de la incertidumbre se ha eliminado durante el estudio de viabilidad. El trabajo se irá subiendo a Stash para tenerlo siempre disponible en caso de pérdida, y se realizarán copias de seguridad periódicas de este documento en dos dispositivos distintos.

9 Otro producto de Attlassian. Se trata del repositorio de Git al que Digi International .Inc sube todos sus proyectos. Tanto las APIs de Java como las que crearemos se almacenarán ahí.

Page 17: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

14

Figura 5. Diagrama de Gantt.

Page 18: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

15

Figura 6. Diagrama de hitos.

01

23

45

67

89

1011

1213

1415

1617

1819

20

21

22

23

Presentación

♦Fin

alización d

el S

DK

♦En

trega al tutor

♦En

trega del

proyecto

♦D

efensa

Page 19: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

16

5. Por motivos de economía, este apartado sólo recogerá el proceso de desarrollo de dos APIs. Las explicaciones que demos serán aplicables a todas las demás.

5.1. El SPI (Serial Peripheral Interface) es un protocolo de comunicaciones síncrono que utiliza un bus de cuatro líneas para interconectar dispositivos periféricos. Dos de estas líneas transfieren los datos (dato entrante y dato saliente), la tercera es una señal de reloj y la cuarta es una línea selectora o chip select. Los dispositivos conectados al bus pueden ser maestros o esclavos, donde el maestro selecciona un esclavo y comienza el proceso de transmisión/recepción de información.

5.1.1. A estas alturas del proyecto, las fases de análisis y estudio ya han dado suficientes pistas sobre cómo debe enfocarse el diseño de las APIs. Para hacer el binding de las clases Java, optaremos por un equivalente de la parte pública en C#. Eso quiere decir que tendremos el mismo número de clases, con todos sus métodos y atributos públicos disponibles. Estudiando el API Java del SPI, veremos que dispone de lo siguiente:

- Una clase de gestión: SPIManager. Crea objetos de tipo SPI. - La clase SPI. Define métodos explícitos para abrir un dispositivo SPI y leer o

escribir datos en el bus. - Tres clases de enumeración: SPIClockMode, SPIBitOrder y SPIChipSelect.

Enumeran las posibles opciones de configuración de la línea de reloj, el orden de los bits de los mensajes y la línea selectora, respectivamente. El modo de reloj se determina a partir de dos bits: CPOL (polaridad de reloj) y CPHA (fase de reloj), por lo que SPIClockMode da hasta cuatro combinaciones.

- Una clase auxiliar: SPIConfig. Abstrae la configuración del bus apoyándose en las clases de enumeración.

A pesar de ello, nuestras clases de C# no se limitarán a replicar lo que ya está hecho en Java: la JNI sigue un paradigma de programación reflexiva y cualquier acción, por pequeña que sea, cuenta con uno o varios pasos. La reflexión es la capacidad que tiene un programa para modificar una estructura de código fuente (clases, instancias, métodos, atributos, etc.) en tiempo de ejecución y manipularla como si fuera otro dato más. Si queremos utilizar un método, por ejemplo, tenemos que obtener la clase, instanciarla, obtener el método y finalmente llamarlo:

Como vemos, el proceso de comunicación con el JNI es costoso. Toda estructura de datos se identifica a través de una cadena que recibe el nombre de signatura. En los métodos, hay que indicar su nombre, el tipo de los parámetros de entrada y el tipo de la salida; para

IntPtr class_ref = JNIEnv.FindClass("<nombre de la clase>");

IntPtr constructor = JNIEnv.GetMethodID(class_ref, "<constructor>");

IntPtr inst = JNIEnv.NewObject(class_ref, constructor);

IntPtr metodo = JNIEnv.GetMethodID(class_ref, "<método>");

JNIEnv.CallMethod(inst, metodo)

Page 20: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

17

encontrar una clase, basta con poner la ruta de paquetes completa, pero en general nos encontramos ante un proceso lento y muy propenso a errores. Errores que, por otra parte, son casi imposibles de detectar en tiempo de compilación. Aunque las signaturas deben seguir una sintaxis específica, al final son strings en las que “todo cabe”. El hecho de que el JNI sólo maneje tipos IntPtr tampoco ayuda, ya que en principio no sabemos qué es lo que contienen. Podríamos estar llamando, por muy poco sentido que tenga, a un método de un atributo y no saberlo hasta que ejecutemos el programa.

El uso del JNI no es trivial y no se recomienda a menos que sea en entornos muy controlados y reducidos. Interactuar con la máquina virtual de Java es peligroso, porque cualquier error puede desestabilizarla de formas muy difíciles de reproducir y depurar (debug). Una diferencia respecto a los lenguajes de programación habituales, y que no conviene pasar por alto, es que todos los objetos son pasados a los métodos como referencias opacas.

Una referencia opaca es un tipo de puntero que apunta a una estructura interna de la máquina virtual. Estas referencias, a su vez, se dividen en tres tipos:

- Referencias locales. Son liberadas automáticamente por la máquina virtual y sólo tienen validez dentro de la estructura que las ha definido. Android permite un número limitado de referencias locales, normalmente 512. Si sobrepasamos este número, obtendremos un error de ART/runtime diciendo que ha habido un desbordamiento en la tabla.

- Referencias globales. No son liberadas por la máquina virtual, lo que nos da libertad para utilizarlas entre distintas estructuras sin que se produzcan incoherencias. No obstante, esto nos obliga a eliminarlas explícitamente. Los emuladores son capaces de almacenar hasta 2.000 variables globales, mientras que en los dispositivos físicos asciende hasta 52.000.

- Referencias globales débiles. Disponibles a partir de Android Froyo (2.2) o superior. No influirán en este proyecto.

Todos los datos se representan a través de IntPtr en C#, pero hay un pequeño matiz: no todos los IntPtr contienen una referencia opaca. Sólo las instancias y las clases entrarían en la clasificación anterior. Los métodos y los atributos, en cambio, se entienden como tipos jmethodID y jfieldID dentro de la máquina virtual.

Del ejemplo de código de la página 17 deducimos que algunos datos, como la referencia a la clase (class_ref) y los métodos, se utilizarán varias veces en la misma clase, por lo que son candidatos a almacenarse en un atributo estático. De esta forma, se compartirán entre todas las instancias.

La variable de la instancia (inst) también es común a todos los objetos, pero su valor es único en cada uno. Este hecho puede resolverse creando una superclase abstracta con una propiedad para obtenerlo y modificarlo. Como no hay razón para trabajar con esa propiedad fuera del ensamblado, se le aplicará un modificador internal.

Algunos métodos de la clase SPI reciben un objeto SPIConfig como parámetro. El JNI sólo puede recibir objetos del tipo JValue, por lo que SPIConfig debe ser transformado de alguna forma. Los tipos básicos, los IntPtr y las clases de Mono.Android se convierten automáticamente con una simple instrucción new JValue(), pero no ocurre lo mismo con las clases que hemos creado nosotros, que devolverían un error de compilación cannot convert. Gracias a la propiedad que hemos declarado en la superclase, podemos obtener el ‘churro de bytes’ que representa a la instancia y solucionar este problema.

Page 21: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

18

Superado el tema de las variables, nos enfrentamos ahora a las clases de enumeración. El principal inconveniente es que el concepto de enumeraciones en Java, como lista de constantes a la que pueden añadirse métodos, no existe en C#. En su lugar, debemos apañarnos con algo equivalente: una clase que englobe atributos de su mismo tipo e implemente los métodos pertinentes. Aunque tengamos la tentación de aplicar el modificador const sobre estos atributos, sólo es posible en los tipos integrados de C#, motivo por el que sólo nos queda la combinación static readonly.

La figura 7 resume el diseño del SPI API en un diagrama de clases (página 20).

5.1.1. La implementación plantea otra cuestión importante respecto a los atributos estáticos: una vez decididos los datos que queremos guardar, ¿cuál es el mejor lugar para inicializarlos? La referencia a la clase puede inicializarse inmediatamente, en la declaración, ya que resulta necesaria en todas las llamadas. Los métodos podrían afrontarse de la misma forma, pero si los inicializásemos todos sin saber si el usuario los va utilizar o no, sufriríamos una penalización de rendimiento en el momento de cargar la clase. Una solución intermedia consistiría en hacerlo cuando vaya a realizarse la primera llamada.

El fragmento de código muestra cómo quedaría el binding de un método Java siguiendo las consideraciones anteriores. La estructura condicional comprueba si el método está inicializado y lo obtiene en caso negativo.

Al construir un objeto con el JNI, éste devuelve una referencia local. El inconveniente de las referencias locales es que son demasiado volátiles y no pueden utilizarse fuera de la estructura o hilo que las ha definido. Por tanto, la clase JNIInstance tiene el deber de convertir la instancia en una referencia global para ahorrarnos futuros problemas. El método JNIEnv.NewGlobalRef es el encargado de crearlas. Aunque el límite de referencias globales en los dispositivos es bastante amplio, conviene eliminarlas cuando ya no hagan falta. Recordemos que la máquina virtual sólo gestiona automáticamente las referencias locales. Entre los programadores de .NET, es conocido el patrón Dispose en objetos que tienen acceso a recursos no administrados, como es el caso de las referencias opacas. Nosotros usaremos este patrón para liberar las referencias globales en el momento de destruir el objeto.

// Obtiene el número de la interfaz. // @return La interfaz SPI en uso. public int getInterface() { … }

private static IntPtr class_ref = JNIEnv.FindClass("com/digi/android/spi/SPI"); private static IntPtr getInterface;

/// <summary> La interfaz SPI en uso. </summary> /// <value> Obtiene el número de la interfaz. </value> public int Interface {

get { if (getInterface == IntPtr.Zero) getInterface =

JNIEnv.GetMethodID (class_ref, "getInterface", "()I"); return JNIEnv.CallIntMethod (Instance, getInterface); } }

Page 22: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

19

Figura 7. Diagrama de clases completo de SPI API.

Page 23: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

20

La clase JNIInstance implementará la interfaz IDisposable y el método público Dispose(). Además, definiremos otro método protegido Dispose(bool) que liberará unos recursos u otros en función de dónde se realice la llamada. Si la llamada proviene del método Dispose (su valor es true), liberaremos tanto los recursos administrados como los no administrados; si proviene de un destructor (su valor es false), sólo nos ocuparemos de los no administrados, ya que el recolector de basura se encargará del resto por nosotros.

El método Finalize() no puede sobrescribirse. En su lugar, utilizaremos la sintaxis propia de los destructores. La necesidad de definir el destructor es que el usuario podría olvidarse de llamar a Dispose explícitamente, por lo que los recursos no administrados seguirían ocupando memoria. Si no se diera el caso, y el usuario llamara a Dipose, tendríamos que sacar al objeto de la cola de finalización, puesto que ya no habría necesidad de liberar nada. Esto se consigue mediante la función SupressFinalize del recolector de basura. La figura 8 resume el flujo de este proceso.

Figura 8. Patrón Dispose para eliminar referencias globales.

Por lo que respecta a las clases derivadas de JNIInstance, sobrescribiremos el método Dispose(bool) para que libere sus propios recursos y acto seguido llamaremos al de la clase base. Todas las referencias globales pueden liberarse fácilmente a través del método DeleteGlobalRef() que proporciona el JNI.

Pero la gestión de los recursos no administrados nos dará un último quebradero de cabeza: las variables estáticas. Hemos oído multitud de veces que las variables estáticas se inicializan en el momento de cargar la clase, no de instanciarla. No sabemos cuándo ocurre exactamente; lo que sí debemos saber es que es que para .NET no es lo mismo destruir un objeto (llamar a su finalizador) que “descargarlo”. Imaginemos que un usuario decide llamar a Dispose() voluntariamente sin haber acabado con la aplicación que utiliza el wrapper, o bien .NET decide hacer lo propio por nosotros. Si dejáramos el patrón tal y como está, nos enfrentaríamos a un serio problema, ya que estaríamos

Page 24: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

21

liberando las variables estáticas (class_ref y enum_ref) sin que ello implicara la descarga de la clase. Por mucho que el usuario intentara crear instancias nuevas, no habría forma de reinicializar los atributos estáticos. Por ello, debemos liberar las variables estáticas única y exclusivamente cuando .NET esté descargando el dominio de la aplicación. El método Environment.HasShutdownStarted() nos indica si el hilo de descarga se ha iniciado o no.

Por otro lado, C# proporciona un mecanismo para que los programadores puedan documentar su código mediante XML. Los elementos <summary> y <value> son etiquetas predefinidas que el procesador de Xamarin es capaz de entender. Tanto el código fuente de las APIs como el de las miniaplicaciones se han documentado de esta forma.

5.1.2. Para que las APIS de C# no lancen errores de ejecución, lo primero que hay que hacer es añadir una referencia hacia JAR de Digi (el que contiene el fichero .dex) en el proyecto donde vamos a realizar las pruebas. Por suerte, Xamarin permite crear ‘proyectos de librería’ que transforman los JARs en DLLs, facilitando la importación.

Aunque los resultados no fueron muy concluyentes debido al reducido tamaño de las clases, se realizó una prueba para demostrar que la decisión que se tomó (en cuanto a la inicialización de los métodos) era la más adecuada. Dicha prueba consistió en repetir la misma operación quinientas veces seguidas y calcular su coste en tiempo.

Cuando se obtenía el método cada vez que el programa lo necesitaba (sin variables), la media ascendía a 2.5057 ms. Si las variables se inicializaban en el momento de declararlas (variables inmediatas), la primera llamada tardaba aproximadamente un 1 ms más que en el caso anterior, 74.14 ms frente a 73.11 ms, pero la media era ligeramente inferior, de 2.4710 ms. La media del coste de la solución elegida (variables a demanda) era de 2.4475 ms.

MODELO BLOQUE (x100)

MEDIA (ms) 1 2 3 4 5

Sin variables 2.4239 2.5526 2.4521 2.5502 2.5494 2.5057

Variables a demanda 2.4401 2.4417 2.5075 2.43114 2.4170 2.4475

Variables inmediatas 2.5212 2.4173 2.4902 2.4068 2.5191 2.4710

Tabla 4. Comparación de tiempos de los tres modelos.

Aparte de medir el rendimiento, esta fase se centró en utilizar todos los métodos y atributos implementados para asegurarse de que respondían correctamente. De encontrar un bug, lo más probable es que procediera de la parte de Java, ya que las APIs de C# se limitan a hacer un envoltorio. Casi todas las excepciones, de hecho, tenían su origen en errores tipográficos, como haber escrito mal la signatura10 de la clase o de un método. La tabla 5 recoge las más comunes junto a su significado. Merece la pena aclarar que las excepciones podrían surgir por motivos ajenos a los de la tabla, ya que sólo estamos hablando de este proyecto en concreto.

10 La JNI identifica los métodos a través de signaturas. Una signatura es una cadena en la que figuran (con una sintaxis específica) el nombre del método, el tipo de los parámetros de entrada y el tipo de la salida.

Page 25: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

22

ERROR TIPO SIGNIFICADO

TypeInitializationException Excepción

La clase C# no puede cargarse. Normalmente se debe a un error interno; en nuestro caso, por una mala inicialización de los atributos estáticos. El JNI no encuentra los atributos en la clase, ya sea por haber indicado mal la clase o los propios atributos.

NoSuchMethodError Excepción

No se encuentra el método dentro de la clase. La signatura es incorrecta o bien se ha indicado que el método es estático cuando no lo es (también al contrario).

NoSuchFieldError Excepción Análogo a NoSuchMethodError, pero con atributos.

ArgumentException Excepción El formato del parámetro no es adecuado. Sucedió al intentar ejecutar un método que era nulo: jmethod must not be IntPtr.Zero.

NoClassDefFoundError Excepción

La definición de la clase se ha encontrado durante la compilación, pero no está disponible en tiempo de ejecución. El android.jar contenía la clase, pero el firmware del ConnectCore 6 se había instalado incorrectamente.

Can’t call <type> on instance of <class>

Error de ART/runtime

Error de ART que surgió al intentar llamar a un método no estático de una clase, en vez de una instancia.

Tabla 5. Errores y excepciones encontradas en el SPI API y similares.

Page 26: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

23

5.2. El GPIO (General Purpose Input/Output ), como su nombre indica, es un sistema de entrada/salida de propósito general. Los pines GPIO no tienen un propósito especial definido y admiten usos múltiples, desde encender un LED hasta controlar motores de corriente continua.

5.2.1. Si el API del SPI sólo manejaba wrappers MCW, en el API del GPIO entra en juego otro concepto, el de wrappers ACW. La presencia de una interfaz nos obliga a plantear el problema justamente en sentido contrario: ya no es C# invocando código Java, sino Java invocando código C#. Pero volvamos a mirar, antes de nada, la estructura del API que tenemos entre manos:

- Una clase de gestión: GPIOManager. Crea objetos de la clase GPIO. - La clase GPIO. Permite obtener y modificar el valor de un dispositivo conectado a un

pin GPIO. - Dos clases de enumeración: GPIOValue y GPIOMode. El pin GPIO soporta tres modos:

entrada, salida e interrupción. El modo de interrupción es un tipo especial de entrada en el que se lanza una interrupción por cambio de estado.

- Un listener: IGPIOListener. - Una clase conteniendo información sobre las actualizaciones: GPIOSample. - Una clase de excepción: GPIOException.

El diseño de las cuatro primeras clases no entraña ningún misterio respecto a lo que se explicó en el API del SPI, así que pasaremos de largo. Sin embargo, la clase GPIO define dos métodos (RegisterListener y UnregisterListener) que merecen un par de aclaraciones:

- Aunque el patrón observer también recomienda codificar una interfaz que exponga los métodos propios de un notificador (como mínimo, para suscribir y desuscribir objetos), Digi no lo hace, y por tanto, nosotros tampoco. En primer lugar, porque tendríamos que cambiar la parte pública (la clase GPIO define RegisterListener, pero en el API de Serial se llama RegisterEventListener, por ejemplo); y en segundo lugar, porque la cabecera de algunos métodos varía en función de si el sujeto puede tener sólo uno o más suscriptores.

- El framework de .NET ofrece su propia versión del patrón observer, que no es otra que el sistema de delegados y eventos. El problema es que no hemos encontrado ninguna forma de que convivan ambas versiones a la vez: la tradicional en Java y la de .NET a nivel de C#. Por ello, se mantendrán los dos métodos de la clase GPIO, en vez de eliminarlos y sustituirlos por un evento. Para más información, -SECCIÓN: Conclusiones-.

La figura 9 recoge el diagrama de clases del GPIO API. Algunas de ellas están comprimidas para ahorrar espacio.

Page 27: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

24

Figura 9. Diagrama de clases completo de GPIO API.

5.2.2. Cada vez que la palabra reservada native aparece en la definición de un método Java, la máquina virtual entiende que su implementación está escrita en otro lenguaje. El enlace o registro de un método nativo y su correspondiente función C# se hace de forma automática (si seguimos ciertas normas de nomenclatura), pero existe una alternativa manual: la función RegisterNatives de la JNI. Entre los parámetros que recibe, se encuentran el método a registrar y un puntero al método C#.

Xamarin simplifica bastante este proceso, y en vez llamar directamente a RegisterNatives, sólo tenemos que dar la información adecuada a través de unas etiquetas especiales llamadas atributos. Además, podemos adelantar un par de cosas:

Page 28: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

25

- Habrá que crear una interfaz C# equivalente a la de Java, IGPIOListener. La única particularidad es que heredará de IJavaObject. Esto es para que Xamarin habilite la creación de ACWs (el proxy Java del que hablábamos en -SECCIÓN: estudio de viabilidad-) de los tipos que la implementen.

- Habrá que crear una clase invocadora, que llamaremos IGPIOListenerInvoker. Implementará IGPIOListener, heredará de Java.Lang.Object y destacaremos tres métodos:

- Uno para llamar, como de habitual, al método Java. - Otro al que apunte el método nativo. Este será el que se ejecute cada vez que

Java invoque código C#. Además, su cabecera seguirá la convención JNI. - Un conector que devuelva un objeto delegado (no confundir con los

delegados de .NET) hacia el método anterior.

Cuando una clase C# hereda de Object o implementa la interfaz IJavaObject, Xamarin crea en tiempo de compilación un proxy Java. En el caso de IGPIOListener, no nos queda más remedio que deshabilitar la creación de ACWs. De lo contrario, obtendríamos dos clases Java con el mismo nombre (el proxy en sí y la interfaz Java original sobre la que actúa el wrapper) y un error de compilación.

Supongamos ahora que un cliente C# decide utilizar nuestra interfaz e implementa el método ValueChanged. El proxy tendrá un método nativo llamado n_valuechanged y un bloque estático en el cual registrará ese método. Volviendo a lo que dijimos al principio del apartado, la información necesaria para el registro se da a través de unas etiquetas especiales (atributos) que hay que colocar sobre las clases y los métodos. En IGPIOListener debemos poner lo siguiente11:

El último parámetro del atributo Register es la ruta al método conector GetValueChangedHandler, el que hemos declarado en la clase IGPIOListenerInvoker. El método conector devuelve un delegado que contiene el método que se enlazará al método nativo; en este caso, n_ValueChanged. En otras palabras: el método C# que se ejecutará cuando Java llame a n_valuechanged será GetValueChangedHandler, el cual delega a su vez en n_ValueChanged. n_ValueChanged, por último, obtiene el cliente C# y llama a su implementación particular de ValueChanged. Podemos ver, en el diagrama UML, que la máquina virtual de Java le envía parámetros de tipo IntPtr, por lo que deben ser convertidos a tipos C# si queremos trabajar con ellos.

Después de explicar la unión entre Java y C#, queda una última cuestión en el aire: ¿cómo y cuándo se llama a n_valuechanged? El proxy Java, que actúa como intermediario del cliente C#, implementa la interfaz original. Por tanto, aparte de n_valuechanged y el bloque

11 La propiedad DoNotGenerateAcw nos permite indicar si queremos que se genere un ACW de una determinada clase. Puesto que la interfaz IPGIOListener ya existe en el dispositivo, la creación de un proxy para el IGPIOListener de C# daría lugar a otra clase Java con el mismo nombre y relación de paquetes (com.digi.android.IGPIOListener). Deshabilitaremos el ACW de IGPIOListener para evitar el conflicto.

[Register ("Ruta de la interfaz Java", DoNotGenerateAcw=true)] public interface IGPIOListener: IJavaObject {

[Register ("Método", "Signatura", "Ruta al conector (Invoker)")] void ValueChanged(GPIOSample sample); }

Page 29: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

26

estático de los que hablábamos antes, Xamarin crea en el proxy otro método más: valueChanged. Dentro de este método es donde precisamente ocurre la llamada a n_valuechanged, detonando la sucesión anterior.

Casi todas las decisiones de implementación no tienen un porqué más allá de adaptarse al funcionamiento de Xamarin. Si estuviéramos trabajando en otra plataforma, la solución sería distinta. El -ANEXO 2: generación de ACWs en Xamarin- ejemplifica la creación del ACW de IGPIOListener.

5.2.3. Mientras probábamos el API del GPIO, surgieron un par de errores nuevos que no se dieron en la del SPI.

ERROR TIPO SIGNIFICADO

TypeLoadException Excepción

Al instanciar la clase que implementa la interfaz IGPIOListener, dice que no encuentra IGPIOListenerInvoker en el ensamblado ‘.’, dando lugar a esta excepción. Esto es porque en la interfaz se indicó mal la ruta donde se encuentra el invocador. También hay que poner bien el número de versión del ensamblado.

Attempt to read local reference

index <n> of <m>

Error de ART/runtime

Surgió al probar una de las clases de enumeración en la miniaplicación de ejemplo. La JNI utiliza siempre las variables en contexto local. Por ejemplo, si definimos un atributo IntPtr en una clase y luego lo utilizamos dentro de una función que requiere otro hilo de ejecución (AsyncTask o Handler), a la hora de ejecutar se producirá un error porque no encuentra la variable en el contexto local del hilo. Se soluciona declarando la variable como global.

Tabla 6. Errores y excepciones encontrados en el GPIO API.

Por otro lado, al crearse el ACW de IGPIOListenerInvoker (recordemos que se trata de una clase Java) no se encontraba el paquete com.digi.android.gpio. El error era de compilación, por lo que había algún JAR que faltaba. Parece que Xamarin no compila sobre los .jar que están dentro de la carpeta add-ons del SDK de Android12. De hecho, ejecuta el programa javac.exe con el modificador –bootclasspath apuntando sólo a ‘android.jar’. Podría hacerse un binding del JAR que tiene la estructura del API, al igual que se ha hecho con el del .dex, pero da un error de ejecución porque las implementaciones están vacías. Literalmente, lanza un Java.RuntimeException avisando de que lo que hay en ese .jar son stubs13.

12 Cuando un usuario se descarga las APIs de Digi, se guardan en la carpeta add-ons del SDK de Android, que es donde Google obliga a poner todas las clases que extienden la versión estándar. Si programáramos para móviles HTC, por ejemplo, y decidiéramos usar las APIs del fabricante, ocurriría lo mismo. 13 El android.jar contiene implementaciones vacías de las clases del SDK (stubs). La implementación real se encuentra en el dispositivo físico o bien el archivo .dex.

Page 30: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

27

Necesitamos, por una parte, el binding del JAR con los stubs para que compile, y por otra, el JAR con el .dex para que se ejecute. El problema es que no es posible mantener los dos a la vez, puesto que Xamarin detecta que hay dos bindings a dos .jar que se llaman igual. Si intentamos engañar a Xamarin cambiando el nombre de alguno de ellos, produce un error java.exe terminó con estado 2, indicando otra vez que hay inconsistencias.

Una opción es meter, a lo bruto, el JAR con los stubs dentro del JAR del SDK de Android. Así, cuando javac.exe esté mirando el ‘android.jar’, encontrará también las clases de Digi. No obstante, esta aproximación no es del todo adecuada, ya que iría en contra de la estrategia de comercialización de Digi, que no es otra que separar sus APIs de las del SDK estándar de Android. La única solución factible pasa por crear otro JAR a partir del JAR con el archivo .dex, con la ayuda de una herramienta llamada dex2jar (u otra). Así, Xamarin será capaz de compilar las clases y luego de ejecutar el código.

Por último, en la miniaplicación de ejemplo desarrollado en Java, una parte del código comprueba si dos instancias de un objeto GPIO son iguales a través del operador ‘==’. En C#, tal y como se había planteado el diseño, esta condición nunca se satisfacerá, ya que cada vez que queremos envolver el ‘churro de bytes’ que nos devuelve el JNI en una GPIO, reservamos una zona de memoria diferente con su constructor interno. Ante esta situación, podemos optar entre varias vías:

- En vez de comprobar las instancias, comprobar aquellos valores de las instancias que nos parezcan significativos para determinar si son iguales o no.

- Sobrescribir el método Equals (y GetHashCode) para que devuelva true o false siguiendo la lógica anterior.

- Sobrescribir el operador ‘==’. Por obligación, habrá que sobrescribir también el operador “!=”. También se recomienda, en ese caso, sobrescribir Equals, y por tanto, GetHashCode. Esto es para evitar inconsistencias, puesto que los operadores y el método Equals se comportan de la misma manera con los objetos, comparando por referencia.

Escogimos sobrescribir el operador ‘==’. Se inició una ronda adicional de implementación y pruebas.

Page 31: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

28

6. La fase de revisión del SDK tuvo lugar tras el desarrollo del SDK, duró una semana y se dividió en tres partes diferenciadas:

En primer lugar, comprobamos la adecuación de las APIS en C#. Revisamos el código de los wrappers en busca errores o alguna línea que rompiera las convenciones de código C# que se recomiendan en las guías de Microsoft. Descubrimos que en realidad no hacía falta añadir una referencia al JAR de Digi en los proyectos que hacían uso del SDK, como habría sido de esperar desde el principio. Recordemos que, en la fase de pruebas del API SPI y GPIO, añadíamos un DLL apuntando hacia el JAR de Digi para evitar errores de ejecución y compilación durante la creación de ACWs.

Poniendo la etiqueta <uses-library> en el archivo de manifiesto de cada proyecto, conseguimos dos cosas: que Xamarin compilase sobre la carpeta add-ons del SDK y que buscara la implementación de la librería dentro del dispositivo.

En segundo lugar, desarrollamos una pequeña aplicación en Unity con el objetivo de confirmar si el SDK era compatible con otros IDEs, y en caso negativo, evaluar la dificultad de crear unos wrappers específicos para esa plataforma. Tal y como se adelantó en el estudio de viabilidad, la implementación del JNI es exclusiva de Xamarin y se basa en sus propios DLLs, por lo que al intentar utilizar el DLL de nuestro SDK en Unity obteníamos múltiples errores de compilación. Se intentó después hacer un wrapper equivalente al del API CPUTemperature (por ser la más corta, pero podríamos haber elegido otra) con la implementación del JNI que daba Unity: AndroidJNI. Si bien las pautas de creación de MCWs eran casi idénticas a las de Xamarin, no parecía haber ningún mecanismo que cubriera las relaciones de herencia e implementación de interfaces. Podíamos implementar una interfaz nativa de Java, pero no en concepto de wrapper porque Unity no se había concebido para ello, a diferencia de Xamarin. En cualquier caso, probamos a implementar el listener de CPUTemperature a su manera y no conseguimos que funcionara. A falta de información en la documentación oficial, los usuarios de Unity coincidían en que la parte de implementación de interfaces estaba todavía muy verde.

Por último, empleamos un osciloscopio para comparar el rendimiento entre las APIs en C# y las APIs en Java. El osciloscopio es un dispositivo de visualización gráfica que muestra señales eléctricas variables en el tiempo. Creamos un programa en C# y Java que alternaba el valor de un botón GPIO unas de diez mil veces seguidas (toggle), y partir de ahí realizamos varias capturas de pantalla con el osciloscopio. Medimos tanto los primeros ciclos, que suelen ser más irregulares, como los ciclos intermedios, en los que la señal ya se ha estabilizado. La figura 10 muestra el ciclo intermedio, pero en el -ANEXO 3: datos del osciloscopio- se han recogido todas las capturas. Los resultados nos decían que el rendimiento en Xamarin era ligeramente superior, de 6.560 milisegundos (152 Hz) frente a los 6.880 milisegundos (145 Hz) de Java. Sin embargo, no podemos concluir nada más allá de que no hay diferencias de rendimiento, puesto que la mejora es muy leve y podría tratarse de algo circunstancial.

Page 32: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

29

Figura 10. Toggle de GPIO en Java (arriba) y toggle de GPIO en C# (abajo).

Page 33: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

30

7. El 9 de febrero, después de traducir las dos primeras APIs, tuvimos una reunión -ANEXO 7: actas de reunión- con la tutora académica para preguntar algunas dudas, hablar sobre los requisitos del proyecto y tantear una posible ampliación del alcance. El trabajo realizado hasta el momento era demasiado repetitivo y se temía que pudiera influir negativamente en la nota. El 12 de febrero la tutora nos avisó de que ya había hablado con la empresa sobre el tema. Como resultado, Digi International Inc. fijó otra reunión el 3 de marzo. En ella, nos dieron el visto bueno para continuar traduciendo las APIs y aceptaron añadirle una segunda parte al proyecto.

El desarrollo del SDK finalizó el 11 de marzo, cuatro semanas antes de lo esperado. La guía de iniciación se escribió entre el 14 y el 18 de marzo. Además, nos indicaron a última hora que había que traducir otra API: Ethernet. El 8 de abril, finalmente, tuvo lugar la revisión final del producto. La empresa nos encomendó una última fase en la que se realizarían tres tareas: comprobar la adecuación de las APIS en C#, comparar su rendimiento con Java -ANEXO 3: datos de osciloscopio- y verificar su funcionamiento en Unity. Terminó el 22 de abril y se le dedicaron 15 horas.

En la tabla 7 aparecen todas las tareas acompañadas de su tiempo real y el estimado.

Id. NOMBRE ESTIMADO EMPLEADO DESVIACIÓN

1.1 Crear SDK 187 h. 145 h. 77,5%

1.1.1 Análisis de requisitos 1 h. 1 h. 15 min. 125%

1.1.2 Estudiar

viabilidad 15 h. 15 h. -

1.1.3 Diseño 9 h. 10 h. 111%

1.1.4 Implementación 153 h. 93 h 45 min. 61,27%

1.1.5 Pruebas 9 h. 10 h. 111%

1.1.6 Revisión - 15 h. -

1.2 Manual de usuario 15 h. 15 h. -

1.3 Gestión 35 h. 25 h 30 min. En curso

1.3.1 Planificación 10 h. 9 h 90%

1.3.2 Seguimiento y

control 5 h. 2h 30 min. En curso

1.3.3 Escribir memoria 15 h. 10 h. En curso

1.3.4 Reunirse 5h 4 h En curso

Tabla 7. Comparación de tiempos de las tareas realizadas.

Page 34: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

31

A continuación, pasaremos a comentar las desviaciones significativas:

- Crear SDK. La implementación, debido a su repetitividad, costó unas 60 horas menos de lo esperado. Sin embargo, esta mejora no fue tan acusada en el cómputo general: al añadir Ethernet, las fases de diseño y pruebas aumentaron una hora, y la revisión supuso otras 15. Comparando con la planificación inicial, nos ahorramos 42 horas.

Llegados a este punto, y confiando en que el resto de tareas (bloques de Gestión y Defensa) no sufran grandes desviaciones, nos quedan 97 horas libres que dedicar a la ampliación del alcance. Esto nos deja mayor margen que la planificación, puesto que en principio sólo sobraban 55.

El 27 de abril se presentó la aplicación de ejemplo. En la reunión nos dieron a conocer las dos primeras secciones que debíamos implementar (un reproductor de vídeo básico y una pantalla de visualización de la CPU), además de algunas pautas de diseño que concernían a la interfaz gráfica. La siguiente parte se dará a conocer tan pronto como acabemos la primera.

Este carácter parcial de la información nos obligará a adoptar una metodología incremental. La primera iteración cubrirá únicamente el desarrollo de la interfaz gráfica, es decir, el esqueleto de la aplicación. Contemplaremos una fase de diseño y pruebas. Como no disponemos de mucho tiempo, nos limitaremos a comprobar la navegabilidad de la interfaz y a asegurarnos de que no surgen errores. Los escenarios y usuarios de la aplicación son muy concretos, así que tampoco merece la pena desplegar un plan de evaluación exhaustivo. Durante la segunda iteración nos centraremos en implementar la funcionalidad de la aplicación propiamente dicha. Habrá que dedicar un tiempo adicional para crear un wrapper de una nueva API: CPU, que es una extensión del API de CPUTemperature. La tabla 8 recoge el tiempo estimado a cada tarea.

NOMBRE DESCRIPCIÓN ESTIMACIÓN

Aplicación de ejemplo

Desarrollo de una aplicación dividida en dos partes. 97 h.

Primera parte Creación de la interfaz gráfica y primera

funcionalidad. 41 h.

Análisis de requisitos

Captura de requisitos funcionales y no funcionales. Creación de casos de uso. 1 h.

Creación de la interfaz

Diseño, implementación y pruebas de la interfaz gráfica. 5 h.

Funcionalidad Diseño arquitectónico, implementación y pruebas. Incluye el wrapper de la nueva

API. 35 h.

Segunda parte - 56 h.

Tabla 8. Estimación de tiempos para la primera parte de la aplicación.

En la segunda parte de la aplicación invertiremos, de momento, unas 56 horas. Una vez acabada la primera parte, tendremos otra reunión en las que nos exigirán mayores o menores requisitos en función del tiempo restante.

Page 35: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

32

8. Habiendo completado la fase de desarrollo del SDK, podemos afirmar que el principal objetivo del proyecto se ha cumplido con éxito. Sin embargo, aparte de trasladar la funcionalidad de las APIs de Digi a C#, también nos preocuparemos por demostrar su uso. Así, un futuro cliente de Digi International Inc. que esté valorando la posibilidad de adquirir un módulo y programar desde Xamarin, podrá hacerse una idea sobre el modo en que interactúan estas interfaces. La presente sección describe el proceso de análisis, diseño, implementación y pruebas de la aplicación de ejemplo.

8.1. La aplicación de ejemplo se centrará en utilizar las APIs en C# para demostrar su posible utilidad en un contexto real. En concreto, se piden tres subsecciones:

- Un reproductor de vídeo. Recogerá todos los archivos de vídeo que encuentre en una carpeta fija del dispositivo. Los mostrará en forma de galería. El usuario podrá seleccionar y reproducir el que desee. Aunque no tenga ninguna relación con las APIs en C#, es común entre las demos de Digi ofrecer un reproductor de vídeo, por lo que en este caso se ha exigido lo mismo.

- Una pantalla de visualización del estado de la CPU. Mostrará el porcentaje de carga de todos los núcleos de procesador que tenga el dispositivo. El usuario será capaz de habilitar o deshabilitar cada uno de los núcleos, menos el primero. Se dará información adicional de la temperatura de la CPU, la frecuencia de trabajo actual, la frecuencia mínima de escalado y la frecuencia máxima de escalado. Estas dos últimas serán modificables. Por último, podremos ejecutar un test de estrés de la CPU. La naturaleza del test es indiferente (renderizar un componente gráfico muy pesado, realizar un cálculo exhaustivo, repetir una operación infinitamente, etc.), siempre y cuando se aprecie cómo sube el indicador del porcentaje de carga.

La figura 11 resume los primeros requisitos funcionales de la aplicación mediante un diagrama de casos de uso.

Page 36: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

33

Figura 11. Diagrama de casos de uso.

8.2.

8.2.1. El estilo de interacción se basará en menús y formularios, tanto para la entrada de datos como para la recuperación de los mismos. La pantalla central de la interfaz se organizará mediante un enrejillado, separando y acentuando la distribución entre áreas. Se espera que el enrejillado tenga unas dimensiones 2x2 o 2x1, lo que nos garantizará cierta sensación de simetría.

La interfaz dispondrá de un menú fijo. Seleccionando cada una de las opciones, la parte central cargará una pantalla u otra. Enfatizaremos el reconocimiento del menú siguiendo varios principios de claridad visual:

- Región común. Los botones se colocarán dentro de una misma región, a la izquierda de la pantalla, para que se perciban como un grupo.

Page 37: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

34

- Similitud, proximidad y continuidad. Los botones se colocarán unos debajo de otros. Sus características perceptuales serán las mismas.

- Cierre. La región en la que coloquemos los botones estará bien delimitada.

Predominará el color blanco, con tonos de grises en el fondo y los iconos. Utilizaremos el verde para resaltar la opción del menú seleccionada y otros elementos de la interfaz, por ejemplo, las líneas horizontales que actúen como separadores. Los iconos serán planos e irán acompañados de texto, por si no fueran suficientemente representativos por sí solos. Tanto el gris como el verde pertenecerán a la paleta de colores corporativos, cuyo código ARGB puede encontrarse en la guía de estilo que facilita la empresa. Con todo, el número de colores que aparecerá en la interfaz no será superior a cuatro.

La creación del menú lateral, tal y como se ha concebido, no se adapta mucho a lo que Android nos tiene acostumbrados. En su lugar, suele ofrecer un navigation drawer, un panel expandible con todas las opciones de navegación. El problema es que este tipo de elementos están orientados a pantallas en posición vertical, cosa que no será muy común entre los usuarios que hagan uso del módulo. El módulo posee interfaces HDMI y DSI para conectarlo a pantallas de televisión, monitores o tablets. El diseño de la interfaz se pensará, por tanto, en posición horizontal.

En la planificación ya adelantamos que no se llevaría a cabo una evaluación exhaustiva de la interfaz. Esto se debe a dos motivos: falta de tiempo y poca variedad de usuarios y escenarios. De hecho, el escenario más probable (por no decir el único) será el de un programador experimentando con el módulo desde su casa o puesto de trabajo. En cuanto a los dispositivos, existe la posibilidad de trabajar tanto con una pantalla táctil (entrada y salida) como con un ratón (entrada) y una pantalla (salida). La elección de uno u otro no tendrá ninguna influencia en el uso de la interfaz. Sin embargo, hay algunos aspectos de usabilidad a los que prestaremos especial atención:

- Siempre es importante que el usuario esté informado sobre las acciones que realiza (feedback), pero en el caso de uso “Estresar la CPU” lo es todavía más. Al ejecutar una tarea larga en segundo plano (un algoritmo para calcular hasta un millón de dígitos de π), el usuario querrá conocer en todo momento el estado de la operación.

- Tomaremos como referencia la guía de estilo de material design. Material design es una normativa de diseño desarrollada por Google para las aplicaciones que corran sobre el API 21 o superior, es decir, Android Lollipop 5.0. Entre sus principios más importantes, destacan los colores brillantes, iconos planos, sombras y elevaciones para establecer jerarquías, interfaz limpia, diálogos minimalistas, etc. los cuales intentaremos aplicar en la medida de lo posible14.

- Las tareas a realizar con la aplicación serán tan sencillas que al usuario apenas le costará familiarizarse con ellas. Se darán pequeñas explicaciones en pantalla dentro de algunos paneles.

14 Material design es un conjunto de pautas, no un dogma a seguir rigurosamente. Pese a los intentos de Google por unir a los desarrolladores, en la práctica ninguno lo aplica al cien por cien. Los manuales abarcan aspectos tan complejos como la separación por capas de la interfaz (superposición), la velocidad de las animaciones, el orden de aparición de los objetos y la proyección de sombras para dar profundidad. En este proyecto sólo trataremos los más superficiales con el objetivo de no romper con la apariencia visual que Google recomienda. Estudiar todas las pautas al detalle nos llevaría mucho tiempo.

Page 38: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

35

Por último, haremos un prototipo de bajo nivel de la interfaz para ilustrar las decisiones que hemos tomado en este apartado. Nos decantaremos por un prototipo de papel y contemplaremos la navegabilidad entre pantallas, si bien es escasa. En la figura 12 aparece este prototipo.

Figura 12. Prototipo de papel de la interfaz de la aplicación.

Page 39: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

36

8.2.2. Respecto a la capa de presentación, el hecho de que existan porciones de interfaz permanentes y otras variables, nos obliga a utilizar fragmentos (Fragments) en Android. Los fragmentos son contenedores que pueden añadirse o eliminarse de la interfaz de forma independiente al resto de elementos que la conforman. Los fragmentos, a su vez, se alojan dentro de unas estructuras mayores llamadas actividades (Activity). Las actividades son el concepto más básico de la programación en Android, puesto que representan las pantallas o ventanas de la aplicación. Aquí es donde definiremos el menú lateral. Tanto los fragmentos como las actividades deben tener una clase java para la lógica asociada, refiriéndonos con “lógica” al control de eventos de los elementos de la interfaz y a la muestra de información, entre otros. Por ello, crearemos tres clases públicas:

- MainActivity: la única actividad de la aplicación. Definirá el menú lateral y se encargará de cargar un fragmento u otro según la opción pulsada.

- VideoPlayerFragment: fragmento que representará al reproductor de vídeo. - PerformanceFragment: fragmento que representará la pantalla de estado de la

CPU.

Otra solución, aunque inadecuada, consistiría en repetir el mismo menú lateral en distintas actividades. No hace falta decir que empeoraría gravemente la reutilización de código. Antes de existir los fragmentos (API 11 e inferiores), esa era la única vía posible, pero a día de hoy no tiene ningún sentido adoptarla.

En la capa de lógica, podemos hacer una separación entre la lógica que modelará los conceptos de nuestra aplicación y la lógica “auxiliar” (otros procesos). El modelo será, ni más ni menos, el conjunto de APIs que hemos desarrollado en C# durante la primera parte del proyecto. Todo este tiempo lo hemos dedicado a implementar la lógica de negocio de la que hará uso la aplicación, si bien todavía nos falta hacer un wrapper sobre el API CPU. Por otro lado, como lógica auxiliar crearemos una clase que sea capaz de calcular el número π y devolver una enorme cantidad de dígitos. A dicha clase la llamaremos HighPrecision (alta precisión) y dispondrá de un método estático a tal efecto: GetPI().

La capa de persistencia es tema aparte. De momento, nuestra aplicación no necesitará almacenar datos, pero es técnicamente incorrecto decir que no se produce ningún tipo de persistencia. Las APIS de Digi están divididas, en realidad, en varias capas. Los wrappers que hemos creado en C# se comunican solamente con la de más alto nivel. Cuando realizamos una llamada a un método de esa capa, la mayor parte de las acciones se delegan en la de abajo. En el caso de la GPIO API, por ejemplo, existe una clase llamada GPIOHandler que es la que se encarga de gestionar la información. Al final, encender un dispositivo GPIO se traduce en escribir un 1 en un archivo específico dentro del sistema de ficheros; y obtener ese valor, leerlo. Sin embargo, hay otras APIS, como la del SPI y el I2C, que debido a su complejidad (buses que precisan llamadas al kernel del sistema operativo) definen una capa todavía más inferior, de muy bajo nivel, para las labores de persistencia. Esta capa está escrita en C++ y se basa en el JNI. Ojo, porque nosotros hemos usado esta tecnología en C#, pero también resulta imprescindible para conectar Java con C++, que es el lenguaje en el que está escrito el kernel de Linux (hilando con lo que se explicó en la introducción).

Page 40: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

37

Por tanto, aunque no vayamos a crear una capa persistencia (ya que viene “incluida” en el paquete de crear los wrappers), merece la pena aclarar que en el fondo sí se almacenan datos.

8.2.3. Llevaremos a cabo pruebas unitiarias de la funcionalidad que completemos durante la primera parte de la aplicación. Todas ellas se documentarán siguiendo la siguiente plantilla:

NOMBRE DEL TEST

Descripción

Procedimiento

Resultado

Tabla 9. Plantilla de los casos de test.

En la fila Resultados puntuaremos la prueba como “CORRECTO”, “PARCIALMENTE CORRECTO” e “INCORRECTO”. El criterio de aceptación no es único, sino que depende de varios factores:

- Adecuación de la tarea. El usuario obtiene de la tarea lo que espera de ella. - Acumulación de errores. - Inevitabilidad de los errores. Situaciones difíciles o imposibles de evitar. Por

ejemplo; si actualizamos muchos elementos de la interfaz gráfica a la vez, ésta se bloqueará durante unos instantes.

- Gravedad de los errores. Los errores impiden al usuario completar la tarea o bien tienen efectos negativos sobre el sistema a largo o corto plazo.

No realizaremos pruebas de integración porque los subsistemas de la aplicación son ajenos unos de otros y no interaccionan entre ellos.

8.3. Además de la clase de lógica, los fragmentos y actividades se componen de un fichero XML que determina el diseño puramente visual de la interfaz. Los ficheros XML tienen como elemento raíz un layout, destinado a controlar la distribución, posición y dimensiones de los controles que se insertan en su interior. Los conceptos son muy similares a los que nos podemos encontrar en la librería Swing de Java, por ejemplo.

La estructura del fichero XML de MainActivity será muy básica. Utilizaremos un LinearLayout como contenedor principal de la botonera, es decir, el menú lateral. Los LinearLayout distribuyen los controles uno tras otro y en la orientación que indique su propiedad android:orientation, que en este caso será “vertical”. A la derecha de este layout, colocaremos otro layout representando el contenido central. No obstante, estará vacío. La lógica de la actividad será la encargada de sustituir ese trozo de XML por el XML de cada fragmento concreto. El único requisito es añadirle la propiedad android:id para poder identificarlo posteriormente.

Page 41: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

38

El tipo del layout central dependerá de cómo queramos cargar los fragmentos. Hay dos alternativas. La primera de ellas consiste en declarar, en la lógica, una variable de referencia de la clase FragmentManager. Es el caso estándar, puesto que sólo hay que llamar al método replace() pasándole como parámetro el identificador del layout central (el que queremos sustituir) y una instancia de la clase de lógica asociada a ese fragmento, ya sea VideoPlayerFragment o PerformancePragment.

La segunda alternativa no utiliza un layout, sino una vista especial llamada ViewPager. Las vistas conviven en los ficheros XML junto a los layouts. De hecho, todos los controles de una interfaz Android (campos de texto, botones, listas desplegables, imágenes, etc.) son vistas. La diferencia más palpable respecto a los layouts es que las vistas sí tienen una representación visual. En concreto, un ViewPager actúa como una lista de fragmentos en el que todos los fragmentos están abiertos a la vez15. Además, añade una funcionalidad bastante interesante: la posibilidad de cambiar de fragmento deslizando el dedo por la pantalla, gesto que comúnmente se conoce como swipe. El inconveniente es que hay que crear otra clase más, un adaptador (Adapter), que se ocupe de almacenar las instancias de los fragmentos.

Nosotros, sin embargo, hemos decidido optar por la primera alternativa por dos motivos:

- El ViewPager no se encuentra en las librerías básicas de Android, sino en las librerías de soporte. Xamarin no ofrece un wrapper de estas librerías, por lo que nos resultará imposible crear el adaptador y una instancia del ViewPager. Hay una extensión oficial de Xamarin que ofrece los wrappers, pero no está actualizada (última vez hace año y medio). Algunos comentarios también sugieren fallos en el funcionamiento.

- No merece la pena. La única novedad que añade el ViewPager, el deslizamiento por pantalla, se adapta difícilmente a las necesidades de nuestro dispositivo. Hemos dicho que la aplicación se ejecutará en posición horizontal, pero el ViewPager está pensado para móviles y sólo permite swipe horizontal. Lo ideal sería que también permitiera swipe vertical para coordinarlo con el flujo de los botones del menú, que están apilados. La “ventaja” (no tiene por qué serlo) de que todos los fragmentos estén abiertos al mismo tiempo puede conseguirse de igual manera con la primera solución. Simplemente habría que instanciar el fragmento una vez y pasar esa referencia a replace(), en vez de crear una instancia nueva en cada llamada.

A nivel de lógica, lo primero que haremos será implementar el wrapper del API de CPU. Como ya hemos explicado este proceso en su sección correspondiente, no nos detendremos más aquí. En su lugar, pasaremos a hablar de la clase HighPrecision. A la hora de manejar números con una enorme cantidad de dígitos, el framework de .NET ofrece dos librerías imprescindibles: BigInteger y BigDecimal. A diferencia de sus homólogas Integer y Decimal, en las que el máximo valor a representar viene dado por la propiedad MaxValue (en el caso de Integer, 2.147.483.647, por ejemplo), estas clases no tienen un límite teórico. Eso quiere decir que reservarán tanta memoria como necesiten en el dispositivo para representar un número.

15 En la implementación habitual de un ViewPager, el programador simplemente se preocupa por alternar entre un fragmento u otro. Si los fragmentos no se destruyen, quedarán abiertos. Esto quiere decir que, si un usuario escribe algo en un campo de texto, cambia de fragmento y luego vuelve al anterior, lo que había escrito seguirá ahí, ya que la instancia es la misma.

Page 42: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

39

Por muy poco intuitivo que parezca, optaremos por BigInteger en vez de BigDecimal. La razón es que necesitaremos menos código para sobrescribir los operadores aritméticos (suma, resta, multiplicación y división). La constante π es irracional (3.141592…), pero en el momento en que decidimos limitar su precisión, deja de tener infinitas cifras para convertirse en un número racional no periódico. La característica principal de los números racionales es que pueden representarse como el cociente de dos números enteros, 𝜋 = 𝑎

𝑏 ⁄ . Si además son finitos, como en este caso, también pueden expresarse

como el cociente de un número entero y una potencia entera de diez. Entonces, 𝜋 = 𝑐10𝑛⁄

dependiendo “n” del número de dígitos que queramos obtener. Para calcular “c”, simplemente igualamos ambas expresiones y concluimos que 𝑐 = (𝑏 10𝑛) 𝑎⁄ . Este será el cociente que guardará la clase HighPrecision a través de BigInteger. Todas las cifras (ya sean de la parte decimal o no) se entenderán como un número entero muy grande, por lo que debemos sobrescribir el método ToString() para mostrar el número en el formato adecuado: añadir el “.”, realizar las conversiones pertinentes, etc.

Ahora que hemos solventado el hecho de representar un número racional con BigInteger, debemos ser conscientes de que el número π no “viene del aire”. Necesitaremos una fórmula para obtenerlo. Y una fórmula implica operaciones. Por tanto, nos veremos obligados a sobrescribir los operadores aritméticos para que los enteros y otros tipos numéricos interactúen correctamente con los objetos de nuestra clase HighPrecision. Utilizaremos la fórmula original de John Machin, muy conocida desde el siglo XVIII por su rápida convergencia:

𝜋 = 4 (4 arctan1

5 − arctan

1

239 )

A día de hoy, resulta bastante rudimentaria, pero servirá para cumplir los objetivos de la aplicación. El método estático GetPI() será el que la implemente, devolviendo como resultado una instancia de HighPrecision.

Lo siguiente será lidiar con las dificultades de un entorno multihilo:

- Para mostrar los porcentajes de carga de cada núcleo de la CPU, la temperatura y la frecuencia, crearemos un Timer de .NET que se ejecutará cada segundo. En ese Timer obtendremos los datos “frescos” de la CPU (con llamadas a las funciones del wrapper) y después actualizaremos los elementos de la interfaz. Nos hemos decantado por esta opción porque creemos que dichas instrucciones no superarán el intervalo del Timer. Los Timers de .NET están diseñados para reiniciarse o provocar un nuevo “tick” en el tiempo acordado, independientemente de si el ciclo anterior ha acabado o no. Las tareas largas en lapsos muy pequeños tienen todas las papeletas de quedarse a medias.

- En el caso de calcular π, crearemos un Thread de. NET y un ThreadStart (el método que ejecutará el hilo). Nos serviremos de otro Timer que irá mostrando por pantalla los segundos que han pasado desde que el usuario inició el proceso.

Según la documentación oficial, todos los procesos de una aplicación Android se basan en los pthreads nativos de Linux16 (con una abstracción de Thread en Java), pero la plataforma les asigna unas propiedades u otras para hacerlos diferentes entre sí. El hilo de interfaz gráfica (UIThread) es el hilo principal, utilizado para ejecutar los componentes

16 Hilos de la norma POSIX (Portable Operating System Interface), de IEEE.

Page 43: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

40

Android y actualizar, como su nombre sugiere, cualquier elemento de la interfaz. Se inicia cada vez que abrimos una aplicación y permanece abierto hasta el final de su ciclo de vida. Si la plataforma detecta que cualquier otro hilo intenta actualizar la interfaz, nos notificará lanzando una excepción CalledFromWrongThreadException.

Como temíamos, los Timers de .NET y los objetos Thread se ejecutan en un hilo distinto al principal, por lo que la tarea de actualizar los elementos de la interfaz se nos complica. Para solucionar esto, Android proporciona varias alternativas, entre ellas, la llamada al método RunOnUIThread para enviar operaciones al hilo principal desde un hilo secundario. Por fortuna, Xamarin da un wrapper sobre este método. Podríamos tener ahora el impulso de colocar todo el cuerpo de nuestros Timers y Threads en el hilo principal, pero eso es algo que hay que evitar a toda costa. Una tarea de larga duración en el UIThread bloqueará la aplicación (o hará que vaya a “trompicones” si no es tan larga), empeorando gravemente la usabilidad y provocando un efecto de lentitud en el usuario. Además, Android monitoriza todas las tareas del hilo principal y detecta aquellas que superan los cinco segundos, en cuyo caso obtendríamos un ANR, el típico “la aplicación no reponde” donde se nos insinúa forzar el cierre.

Así pues, sólo pondremos dentro del UIThread lo estrictamente necesario, es decir, la parte de mostrar los datos. Tanto el cálculo de π como la obtención de los mismos se mantendrán en segundo plano, permitiendo que el usuario continúe interactuando con la aplicación. La figura 13 es un esquema del flujo que seguirá el hilo de π.

Figura 13. Flujo del hilo para calcular π.

Después de mirar la figura, es posible que el lector se haya percatado de las llamadas a Abort() y Stop(), poniendo de relieve una última cuestión: ¿es realmente seguro parar los hilos sólo cuando hayan terminado su trabajo? La respuesta es evidente: no. Al cambiar de un fragmento a otro con replace(), este se desvincula de la actividad y es destruido, pero no afecta de ninguna manera a los procesos en segundo plano. Imaginemos que un usuario inicia el hilo y pasa al fragmento VideoPlayerFragment, sin haberlo acabado. El cálculo de π seguirá en marcha, pero al volver al fragmento de la CPU podrá iniciar otro nuevo, con lo que ya tendríamos dos hilos en ejecución. Repitiendo este proceso,

Page 44: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

41

conseguiríamos “estresar” a la CPU hasta unos límites poco recomendables y que distan mucho de lo que nuestra aplicación pretende demostrar.

La suerte es que Android permite sobreescrbir aquellos métodos que tienen que ver con el ciclo de vida de un fragmento para controlar este tipo de sucesos. Entrando en detalles, el método replace() llama sucesivamente a los métodos onPause(), onStop(), onDestroyView() y onDetach() del fragmento que se va a reemplazar. Nosotros hemos decidido parar el Timer y abortar el Thread cuando la vista del fragmento se destruye, es decir, en onDestroyView(). Ahora también podemos respirar tranquilos en el caso de que la aplicación (y por tanto, el fragmento) se cierre de forma inesperada.

8.4. La tabla 10 es un ejemplo de las pruebas que se llevaron a cabo durante esta fase. En el -ANEXO 6: pruebas unitarias- pueden consultarse todos los casos de test. Se intentó que cada prueba abarcase varias funciones de la aplicación, ya que las tareas eran tan sencillas que no merecía la pena descomponerlas y analizarlas por separado.

NOMBRE DEL TEST ESTRESAR LA CPU

Descripción Estresar el procesador calculando el número π.

Procedimiento

El usuario indica el número de dígitos. El usuario comienza la operación El usuario espera hasta que termine la operación y pulsa sobre Ver resultados. El usuario comienza la operación y la detiene.

Resultado

INCORRECTO. El sistema calcula π y habilita el botón de Ver resultados. La aplicación se cierra al intentar poner en pantalla un número tan alto de cifras. La operación no se detiene cuando pasamos a otro fragmento (permanece en segundo plano). El cálculo de π en sí y el cronómetro no dan problemas. El porcentaje de carga de algunos núcleos se eleva hasta el 100%.

Tabla 10. Caso de test de la tarea “Estresar la CPU”.

Page 45: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

42

9. El desarrollo de la primera parte de la aplicación terminó el viernes 13 de mayo. En la tabla 11 aparecen todas las tareas acompañadas de su tiempo real y el estimado. Nótese que, sin haber acabado el proyecto, ya hemos cubierto todo tiempo que les asignamos a las reuniones.

Id. NOMBRE ESTIMADO EMPLEADO DESVIACIÓN

- Aplicación de ejemplo 97 h. 46 h. En curso

- Primera parte 41 h. 46 h. 112%

- Análisis de requisitos 1 h. 1 h. -

- Creación de la interfaz 5 h. 5 h. -

- Funcionalidad 35 h. 40 h. 115%

- Segunda parte 56 h. - Sin iniciar

1.3 Gestión 35 h. 27 h 30 min. En curso

1.3.1 Planificación 10 h. 9 h 90%

1.3.2 Seguimiento y control 5 h. 3h 30 min. En curso

1.3.3 Escribir memoria 15 h. 10 h. En curso

1.3.4 Reunirse 5h 5 h En curso

Tabla 11. Comparación de tiempos de las tareas realizadas.

A continuación, pasaremos a comentar las desviaciones significativas:

- Funcionalidad. Se le dedicó un día más de lo esperado (aproximadamente cinco horas). Inicialmente se pensaba representar los porcentajes de carga de los núcleos mediante un gráfico de líneas. El problema es que Xamarin no ofrecía muchas librerías de creación de gráficos, y las pocas que había eran de pago o no soportaban a actualización dinámica de datos (redibujado). Perdimos un día intentando encontrar una librería y al final utilizamos barras de progreso. Por tanto, en la última parte de la aplicación podremos invertir un máximo de 51 horas, en vez de 56.

El 18 de mayo tuvo lugar la reunión en la que se introdujo la segunda parte de la aplicación. Esta consistía en un conjunto de sensores cuyos datos se mostrarían al usuario y se almacenarían en la nube. También incluía el desarrollo de otra aplicación muy básica (aplicación de muestra) en Java que se comunicaría con la nube para recoger dichos datos.

Page 46: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

43

NOMBRE DESCRIPCIÓN ESTIMACIÓN

Segunda parte Requisitos y segunda funcionalidad. 51 h. Análisis de requisitos

Captura de requisitos funcionales y no funcionales. Creación de casos de uso. 1 h.

Funcionalidad Diseño arquitectónico, implementación y pruebas. Incluye el wrapper de la nueva

API. 40 h.

Aplicación de muestra

Diseño, implementación y pruebas. 10 h.

Tabla 12. Estimación de tiempos para la segunda parte de la aplicación.

Tendremos que traducir el API de CloudConnector, que no estaba entre las del SDK original, pero sólo nos ocuparemos las clases y métodos que vayamos a utilizar.

Page 47: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

44

10.

10.1. Además de las dos subsecciones que se discutieron en -SECCIÓN: Aplicación de ejemplo-, el sistema incorporará:

- Una pantalla de visualización de sensores. Conectaremos cuatro componentes al dispositivo: un sensor de temperatura, un sensor fotoeléctrico, un botón GPIO y un LED GPIO (diodo emisor de luz). Cuando el usuario active el botón, el LED se encenderá. La pantalla mostrará en tiempo real el estado del botón y del LED, así como los valores de temperatura e iluminancia que proporcionen los sensores. Por otro lado, la aplicación intentará conectarse en segundo plano con la Digi Device Cloud, una plataforma de administración de dispositivos en la nube17. Si la conexión se establece sin errores, enviará cada cierto tiempo los datos de los sensores y el botón GPIO hacia la nube.

Por último, desarrollaremos una aplicación en Java (aplicación de muestra) que recogerá los datos que hemos dejado en la nube. Mostrará el valor actual de los sensores y el botón GPIO. Si la sección de los sensores actúa como emisor, esta aplicación adquirirá el rol de receptor, siendo la Digi Device Cloud el punto de encuentro. Opcionalmente se permite un registro de los valores que se vayan recibiendo.

La figura 14 resume los últimos requisitos funcionales de la aplicación con un diagrama de casos de uso. En -ANEXO 4: diagrama de casos de uso- puede verse el diagrama completo.

Figura 14. Diagrama de casos de uso.

17 Para acceder a la Digi Device Cloud, basta con crear una cuenta (nombre de usuario y contraseña). A continuación, se registra el dispositivo indicando algunos de los siguientes conceptos: MAC, IMEI y Device ID. La MAC (Media Access Control) es un identificador de 48 bits que se corresponde de forma única con una interfaz de red. El IMEI es otro código que identifica cualquier terminal móvil asociado a una red GSM o UMTS. El Device ID se genera partir de los otros dos y cumple la misma función.

Page 48: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

45

10.2. La arquitectura del sistema, la interfaz gráfica y el plan de pruebas no sufrirán grandes variaciones respecto a lo que se decidió en la primera parte. Como novedades, podemos citar las siguientes:

Sobre el almacenamiento de datos, nos encontraremos ante dos ubicaciones distintas:

- Digi Device Cloud. Aquí irán los valores de los sensores y del botón GPIO. No se enviará el estado del LED GPIO porque se entiende que estará sincronizado con el del botón, evitando así la redundancia. Si el estado del botón es 1 (encendido), el del LED también será 1.

- El propio dispositivo. En el ConnectCore 6 en el que se esté ejecutando la aplicación deberemos almacenar cierta información de configuración. Si queremos que la información “persista” entre varios usos, no podemos limitarnos a gestionarla a nivel de lógica, ya que Android elimina cualquier vestigio de la aplicación cuando el usuario la cierra o lleva mucho tiempo sin actividad. El usuario tendrá la oportunidad de habilitar/deshabilitar el envió de datos de un sensor determinado (o de todos a la vez) y establecer la frecuencia de envío.

En la capa de presentación añadiremos FragmentSensors, la clase de lógica asociada al fragmento de visualización de sensores, y la actividad Settings, con la que configuraremos el envío. Inauguraremos la capa de persistencia con una clase para guardar y obtener los datos de configuración almacenados en el dispositivo. A esta clase la llamaremos CloudPreferences.

10.3. Los tipos de persistencia en Android, por lo general, pueden dividirse en tres grupos: preferencias compartidas, base de datos en lenguaje SQLLite y ficheros. A nosotros no nos interesan los ficheros ni crear una base de datos para la poca cantidad de información que queremos almacenar. Las preferencias, en cambio, sí se ajustan a nuestras necesidades.

Las preferencias compartidas, cuya gestión se deja en manos de la clase SharedPreferences, son un mecanismo para almacenar datos livianos en forma de pares clave-valor. Es decir, cada preferencia está compuesta por un identificador único y un valor asociado a ese identificador. Cuando la aplicación se instala en el dispositivo, crea una carpeta privada a la que resulta imposible acceder desde cualquier otro proceso. En el interior de esa carpeta, hay otra carpeta llamada shared_pref conteniendo uno o varios ficheros XML. Esos ficheros XML son, ni más ni menos, el mapa de pares clave-valor correspondiente a las preferencias compartidas.

Este mecanismo fue diseñado específicamente para administrar los parámetros de configuración de una aplicación, pero la cosa no queda sólo ahí: además de dar una clase que nos facilita el acceso (SharedPreferences), Android ha creado una sublcase de fragmento que nos despoja, casi por completo, de la tarea de mostrarlas al usuario. Si antes nuestros fragmentos heredaban de Fragment, ahora la clase Settings cargará un

Page 49: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

46

PreferenceFragment18. Estableciendo ese tipo de herencia, seremos capaces de llamar al método AddPreferencesFromResource(), el cual recibe como entrada un fichero XML que registrará las preferencias. Cuidado, porque ese fichero XML no tiene nada que ver con el que genera Android para almacenar las preferencias; sólo anunciamos qué preferencias vamos a almacenar.

Terminada la pantalla que mostrará los parámetros de configuración, nos encontramos con que los valores se guardan automáticamente. Por ejemplo, si para habilitar el envío de datos del botón GPIO hemos creado una casilla de verificación (checkbox), Android guardará true/false en las preferencias cada vez que el usuario marque/desmarque dicha casilla. Por tanto, nuestra clase CloudPreferences sólo se preocupará de obtener los valores y no de almacenarlos, a diferencia de lo que dijimos en el diseño. La obtención de los valores no es demasiado complicada si se utilizan los getters de SharedPreferences.

El siguiente paso es la implementación de SensorsFragment, el fragmento de visualización de sensores. Haremos uso de nuestros wrappers en dos sentidos:

- Comunicación con los sensores. GPIO API para obtener el valor del botón y cambiar el del LED en consecuencia. El botón nos avisará de que su estado ha cambiado implementando IGPIOListener. ADC API para obtener los valores de los sensores de luz y temperatura, ambos analógicos. Implementaremos la correspondiente interfaz, IADCListener, con el objetivo de conocer dichos valores cada segundo.

- Comunicación con la nube. Cloud Connector API, la cual hemos traducido parcialmente. La subida se realiza mediante data streams, flujos de datos vinculados a un dispositivo concreto. Cada data stream está formado a su vez por conjunto de data points, que son los que contienen el valor a enviar19. Crearemos tres data streams, uno por cada sensor.

A la hora de enviar los data points hacia la Digi Device Cloud, disponemos de dos opciones: enviarlos inmediatamente y de uno en uno (tan pronto como se ejecuten los métodos de IGPIOListener y IADCListener) o enviarlos todos a la vez y cada cierto tiempo en una misma petición. Un aspecto a tener en cuenta para elegir una opción u otra son las limitaciones que nos impone el servicio de Digi Device Cloud. Las cuentas gratuitas, como la nuestra, permiten registrar un máximo de cinco dispositivos. Asimismo, En la página oficial de Digi International Inc. se informa de que la nube admite, como mucho, 3600 peticiones por hora y por dispositivo. Es decir, una petición por segundo. En caso de superar dicho límite, obtendremos un error denominado throttle, manifestando la posibilidad de que los datos no se hayan enviado correctamente. Nosotros podemos ignorar la primera limitación porque sólo tenemos un dispositivo, pero no la que afecta al número de peticiones. Optaremos por enviar todos los data points de golpe cada tres segundos, lo que nos asegurará cierto nivel de recepción de datos.

18 En un principio, sólo hablamos de crear la actividad Settings. Sin embargo, la documentación oficial de Android recomienda seguir un patrón diferente para las pantallas de configuración: una actividad que cargue fragmentos de preferencias y un fragmento de preferencias por cada subsistema. En casos como el nuestro, en los que sólo hay un fragmento, no tiene sentido crearlo, ya que nos resultaría más sencillo mostrar las preferencias directamente en la actividad. El problema es que el patrón antiguo que solventaba este hecho está deprecado. Por esta razón, aparte de Settings, tenemos un fragmento CloudPreferenceSettings que hereda de PreferenceFragment. 19 Opcionalmente, un data point puede llevar la localización GPS del dispositivo y e información sobre la calidad de los datos.

Page 50: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

47

Además, las peticiones a la nube son bastante susceptibles de sufrir retardos. Si realizamos una petición cada tres segundos en vez de una cada segundo, minimizaremos este efecto sobre el usuario.

Una tarea repetitiva como esta requerirá la creación de un Timer. La actualización de los elementos de la interfaz, por su parte, nos obligará a traspasar las operaciones desde el hilo secundario (los métodos de IGPIOListener y IADCListener, que nos informan de los cambios) hacia el hilo principal. Las pautas a seguir serán las mismas que las que se llevaron a cabo en el otro apartado. Una novedad es que el wrapper de CloudConnector también ofrece su propia interfaz ICloudConnectorListener, con métodos que responden a los eventos de conexión. A nosotros nos vendrá bien usarla para saber si el dispositivo se ha conectado o desconectado y controlar así el envío de datos. Un booleano que se ponga a true o false es suficiente.

10.4. En la tabla 13 aparece el principal caso de test que se llevó a cabo para esta parte de la aplicación. En el -ANEXO 6: pruebas unitarias- pueden consultarse todos los casos de test.

NOMBRE DEL TEST ENVIAR DATOS DE SENSORES

Descripción Comprobar que los datos de los sensores se almacenan correctamente en la nube.

Procedimiento

El usuario configura el envío de datos. El usuario entra a la pantalla de sensores y la deja abierta. El usuario entra a su cuenta de Digi Device Cloud y comprueba que le llegan los datos.

Resultado

PARCIALMENTE CORRECTO. El sistema envía los datos a la nube teniendo en cuenta la configuración elegida. Los datos aparecen en la cuenta de Digi Device Cloud y se van actualizando cada cierto tiempo. Leve retardo en la interfaz por aparición de throttles. El LED se enciende cuando pulsamos el botón.

Tabla 13. Caso de test de la tarea “Enviar datos de sensores”.

Page 51: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

48

11.

12. El 31 de mayo el producto se cerró de forma definitiva. La aplicación de muestra se inició inmediatamente después de terminar la aplicación de ejemplo. La memoria no recogerá el proceso de desarrollo de la aplicación de muestra porque creemos que no añade grandes novedades respecto a lo que se comentado ya. No obstante, haremos tres pequeños apuntes:

- Para comunicarse desde la nube hacia la aplicación, se utilizó una librería existente en Java (.jar) de Digi.

- Se tuvieron en cuenta las limitaciones de la nube en la obtención de datos, creando un hilo que se ejecutaba cada tres segundos.

- La muestra de datos se llevó a cabo mediante gráficos de líneas con la ayuda de la librería no-oficial AndroidPlot.

La tabla 14 compara las horas estimadas y empleadas de todas las tareas del proyecto.

Id. NOMBRE ESTIMADO EMPLEADO DESVIACIÓN

1.1 Crear SDK 187 h. 145 h. 77,5%

1.1.1 Análisis de requisitos

1 h. 1 h. 15 min. 125%

1.1.2 Estudiar viabilidad 15 h. 15 h. -

1.1.3 Diseño 9 h. 10 h. 111%

1.1.4 Implementación 153 h. 93 h 45 min. 61,27%

1.1.5 Pruebas 9 h. 10 h. 111%

1.1.6 Revisión - 15 h. -

1.2 Manual de usuario 15 h. 15 h. -

1.3 Gestión 35 h. 39 h 30 min. En curso

1.3.1 Planificación 10 h. 9 h 90%

1.3.2 Seguimiento y control 5 h. 4h. En curso

1.3.3 Escribir memoria 15 h. 20 h. 133%

1.3.4 Reunirse 5 h. 6 h 30 min. 130%

1.5 Aplicación de ejemplo

55 h. 87 h. 158,1%

1.5.1 Primera parte 41 h. 46 h. 112%

1.5.2 Segunda parte 56 h. 41 h. 73,2%

TOTAL 300 h. 294 h 30 min.

Tabla 14. Comparación total de horas.

Page 52: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

49

Sumando los tiempos que aparecen en la columna ‘empleado’ y la estimación inicial hacia el bloque de Defensa (ocho horas), nos da un total de 294 horas y 30 minutos. Disponemos todavía de seis horas para hacer retoques de última hora sobre la memoria o el proyecto en general, si se diera la necesidad. A continuación, se comentan las desviaciones significativas:

- Aplicación de ejemplo. Antes de terminar el SDK sólo nos quedaban 55 horas para dedicar a la aplicación de ejemplo. Sin embargo, esta tarea sufrió una desviación del 77,5% -SECCIÓN: Seguimiento y control (I)- y nos dejó 97 horas libres. Por tanto, la aplicación de ejemplo se estimó dos veces: una al inicio de proyecto y otra al acabar el SDK. La desviación respecto a las 97 horas ronda el 89%.

- Reunirse. Le asignamos cinco horas porque no pretendíamos realizar reuniones con tanta frecuencia. Al final, nos reunimos nueve veces; cinco en la empresa y cuatro con la tutora académica. La duración de las reuniones osciló entre los treinta minutos y la hora.

- Escribir memoria. No se valoró inicialmente la elaboración de documentos gráficos, tales como esquemas e imágenes. Además, tuvimos que rescribir algunas secciones a raíz de la penúltima reunión con la tutora.

- Segunda parte. La funcionalidad de la segunda parte de la aplicación costó menos de lo esperado, ya que habíamos asentado todas las bases (navegación, interfaz gráfica, estructura, etc.) en la primera iteración.

En cuanto a los entregables, el entregable con código ETFG-31 pasará a ser una copia electrónica de ETFG-23 junto a los ficheros generados en ETFG-11 y ETFG-13.

Page 53: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

50

13.

13.1. Al principio de la memoria, se detallaron los objetivos que debía cumplir este proyecto. Una vez finalizado, podemos afirmar que no sólo se han cumplidos los objetivos marcados inicialmente, sino que además se han ampliado de manera satisfactoria. Hemos creado unas APIs en C# prácticamente equivalentes a las de Java con una experiencia de uso similar. El manual y la documentación que se han escrito servirán como apoyo para un usuario inexperto. Pedro Pérez, Rubén Pérez y Tatiana León supervisaban continuamente el trabajo que desempeñábamos en la empresa y nos dieron su aceptación en numerosas ocasiones. La aplicación de ejemplo es una prueba real de que las APIs en C# funcionan, y la pantalla de los sensores nos da una idea de la enorme variedad de usos que pueden tener las interfaces del dispositivo.

En general, estamos contentos con la elaboración de este proyecto. Nos hubiera gustado indagar más en el proceso de creación de la aplicación para aplicar los conocimientos y competencias adquiridos en el grado, pero hay que ser conscientes de que esa parte del proyecto suponía, en cantidad de horas, menos de un tercio del mismo. Consideramos muy positivo todo lo relacionado con el aprendizaje del JNI y la arquitectura de Android, ya que se trataba de algo completamente desconocido para el alumno. Del mismo modo, se han adquirido competencias transversales de vital importancia en el mundo empresarial, entre ellas, la capacidad de tomar decisiones autónomas, de actuar como director de un proyecto y de responder a las necesidades de un cliente real. También se ha puesto en práctica nuestra capacidad de resolución de problemas.

13.2. Teniendo en cuenta el estado actual del producto, pasamos a enumeran una serie de mejoras que podrían incorporarse en futuras iteraciones:

- Uno de los requisitos no funcionales que debía satisfacer el SDK era la facilidad de mantenimiento. En ese sentido, se creó una clase Utils que guardaba las signaturas de los métodos y tipos de Digi en cadenas de sólo lectura, pero nunca se llegó a utilizar. Si la ruta de paquetes o las clases de Digi cambiasen en un futuro, nos ahorraríamos buscar en los wrappers la aparición de cada signatura. Una posible mejora del proyecto sería acabar esta clase, la cual está incompleta ahora mismo, e integrarla en el SDK.

- El framework de .NET ofrece su propia versión del patrón observer: el sistema de delegados y eventos. Nosotros, en cambio, hemos mantenido la forma tradicional, la de crear una interfaz exponiendo los métodos que deben ser implementados. Estaría bien que en próximas revisiones se investigara la posibilidad de dar soporte a los delegados, ya que nosotros no hemos sido capaces de hacerlo. Sabemos que es posible porque Xamarin lo hace en sus wrappers de Android. Por ejemplo, para controlar el click de un botón, puedes asignarle un delegado al evento Click o bien implementar la interfaz IOnClickListener, que sería la opción con “sabor” Java.

Page 54: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

51

- Xamarin alardea constantemente de que es posible desarrollar con su entorno aplicaciones multiplataforma. Esto es cierto a medias, ya que sólo se aplicaría a nivel de interfaz gráfica. Gracias a la CLI (Infraestructura de lenguaje común)20 de Mono, podemos diseñar una única interfaz que funcione en Android, iOS y Windows Mobile. Una mejora consistiría en migrar hacia Mono la interfaz de todas las aplicaciones que hemos creado, para darles mayor “universalidad”. Eso sí, sabiendo de antemano que nuestros wrappers jamás funcionarían en iOS y Windows Mobile, puesto que el firmware objetivo es Android.

- En la aplicación de ejemplo, dijimos que una de las alternativas que daba Android para ejecutar operaciones en el hilo principal era RunOnUIThread, pero no hablamos de las demás. La clase AsyncTask, por ejemplo, se utiliza específicamente para lanzar procesos con un flujo muy similar al de π: tarea larga en segundo plano primero y actualización de la interfaz después. Las instrucciones se colocan en alguno de sus métodos (doInBackground y onPostExecute) y éstos son llamados desde el hilo correcto. Nosotros no implementamos AsyncTask porque nos habría exigido eliminar los Timers y Threads de .NET, y decidimos darle más importancia al hecho de estar programando en C# que en Android. Cabe aclarar que, a nivel funcional, RunOnUIThread y AsyncTack hacen lo mismo; el único impacto recae en la estructura y limpieza del código. Si se quisiera, podríamos intercambiar una alternativa por otra.

20 El CLI, o Infraestructura de Lenguaje Común, es un estándar desarrollado por Microsoft y estandarizado por la ISO. Describe un entorno virtual para la ejecución de aplicaciones en distintas plataformas y lenguajes de alto nivel sin necesidad de reescribir el código. Para ello, los lenguajes compatibles con el CLI se compilan a CIL (Common Intermediate Language), un lenguaje intermedio independiente de del conjunto de instrucciones de la CPU. Cuando el código es ejecutado, el VES (sistema de ejecución virtual) convierte el CIL a código máquina. Mono es una de las implementaciones más conocidas de CLI.

Page 55: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

52

14.

[ 1 ] DOCUMENTACIÓN OFICIAL DE XAMARIN. https://developer.xamarin.com/guides/android/ Estudio de la plataforma y creación de wrappers. Hilos y referencias opacas en el JNI.

[ 2 ] SOPORTE OFICIAL DE DIGI INTERNATIONAL, INC. http://knowledge.digi.com/ Funcionamiento y limitaciones de la Digi Device Cloud.

[ 3 ] GUÍAS PARA PROGRAMADORES DE ANDROID. https://developer.android.com/guide/index.html Creación de fragmentos y ViewPagers. Procesos e hilos en Android.

[ 4 ] GUÍAS DE DESARROLLO PARA .NET FRAMEWORK. https://msdn.microsoft.com/es-es/library/w0x726c2(v=vs.110).aspx Implementación del patrón Dispose. Convenciones de código de Microsoft.

[ 5 ] ED. BURNETTE, HELLO, ANDROID. Conocimientos básicos de Android.

[ 6 ] ANDERS GÖRANSSON, EFFICIENT ANDROID THREADING Procesos e hilos en Android.

Page 56: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

53

GPIO API

Page 57: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

54

SPI API

Page 58: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

55

ADC API

Page 59: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

56

CAN API

Page 60: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

57

I2C API

Page 61: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

58

PWM API

Page 62: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

59

Watchdog

Page 63: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

60

CloudConnector API

Page 64: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

61

CPU API

Page 65: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

62

Ethernet API

Page 66: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

63

Serial API

Page 67: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

64

Supongamos que tenemos la interfaz IGPIOListener y una clase MiClase que la implementa:

Como resultado, se creará un proxy Java de la clase MiClase con la siguiente estructura:

El proxy Java hace uso de la interfaz original. Se crea un método nativo n_valueChanged que se registra en el bloque estático inicial. En dicho bloque asociamos n_ValueChanged a GetValueChangedHandler. Cuando el valor de la GPIO cambia, la máquina virtual de Java llama a valueChanged del proxy, en cuya implementación podemos ver que invoca al método nativo. De esta forma, conseguimos ejecutar código C# desde Java.

[Register ("com/digi/android/gpio/IGPIOListener", DoNotGenerateAcw=true)] public interface IGPIOListener: IJavaObject {

[Register ("valueChanged", "<signature>", "GetValueChangedHandler")] void ValueChanged(GPIOSample sample); }

public class MiClase: Java.Lang.Object, IGPIOListener { public MiClase() { GPIOManager gpioManager = new GPIOManager(Application.Context); GPIO gpio = gpioManager.CreateGPIO(38); gpio.RegisterListener(this); } public void ValueChanged(GPIOSample sample) { Console.WriteLine("¡El valor ha cambiado!")

} }

public class MiClase implements com.digi.android.gpio.IGPIOListener { static final String __md_methods; static {

__md_methods = "n_valueChanged:(GPIOSample):GetValueChangedHandler\n";

mono.android.Runtime.register (...); } @Override public void valueChanged (GPIOSampe sample) { return n_valueChanged (sample); } private native void n_valueChanged (GPIOSample sample); }

Page 68: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

65

Relación de capturas realizadas con el osciloscopio. La frecuencia y el período se encuentran a la derecha de la señal, en amarillo. Nótese que los valores experimentan una leve mejoría en C# (Xamarin).

Java C# (Xamarin)

Page 69: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

66

Page 70: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

67

Page 71: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

68

Caso de uso: Reproducir vídeo Objetivo: Reproducir el vídeo de la galería Actores: Usuario (U) Precondición: Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario abre por primera vez la aplicación o se dirige al reproductor.

2. S: Devuelve una lista en mosaico con todos los vídeos que encuentre en una carpeta.

3. U: Selecciona el vídeo que desea ver. 4. S: Lo amplía y reproduce el vídeo automáticamente.

Extensiones:

Caso de uso: Ver carga núcleos Objetivo: Ver el porcentaje de carga de los núcleos de la CPU Actores: Usuario (U) Precondición: Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario abre la sección del estado de la CPU.

2. S: Calcula el número de núcleos del procesador y averigua cuáles están deshabilitados y cuáles no.

3. S: Obtiene el porcentaje de carga de los núcleos. 4. S: Muestra el porcentaje de carga de cada núcleo. El SISTEMA repite los pasos 2-4 cada cierto tiempo.

Extensiones: 4.1 El núcleo existe, pero no está habilitado. 4.1.1 S: Informa de que el núcleo está deshabilitado, sin mostrar la carga.

Caso de uso: Habilitar núcleo Objetivo: Habilitar o deshabilitar los núcleos de la CPU Actores: Usuario (U) Precondición: Postcondición: Debe haber al menos un núcleo habilitado (no pueden deshabilitarse todos los núcleos). Pasos:

1. El caso de uso se inicia cuando el Usuario abre la sección del estado de la CPU.

2. S: Calcula el número de núcleos del procesador y averigua cuáles están deshabilitados y cuáles no.

3. S: Muestra el estado de los núcleos. 4. U: Habilita o deshabilita el núcleo de su elección.

Extensiones: 4.1 El núcleo a deshabilitar es el último que queda. 4.1.1 S: Informa del error o impide deshabilitar el núcleo. 4.1.2 Finalizar caso de uso.

Page 72: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

69

Caso de uso: Ver estado CPU Objetivo: Ver el estado actual de los principales parámetros de la CPU Actores: Usuario (U) Precondición: Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario abre la sección de la CPU. 2. S: Obtiene la temperatura del procesador, la carga total y la frecuencia de

trabajo. 3. S: Muestra los datos al usuario. El SISTEMA repite los pasos 2-3 cada cierto tiempo.

Extensiones: 3.1 El usuario desea cambiar las frecuencias de escalado. 3.1.1 Extend al caso de Uso Modificar frecuencias.

Caso de uso: Modificar frecuencias Objetivo: Modificar el valor de la máxima y mínima frecuencia de escalado del procesador Actores: Usuario (U) Precondición: Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario está viendo el estado de la CPU y quiere modificar las frecuencias de escalado.

2. S: Obtiene las frecuencias actuales y todas las frecuencias que admite el procesador.

3. S: Muestra los datos al usuario. 4. U: Selecciona una de las frecuencias posibles. 5. U: Confirma la nueva frecuencia a aplicar. 6. S: Informa si la acción se ha completado correctamente.

Extensiones:

Caso de uso: Estresar CPU Objetivo: Estresar la CPU realizando una operación larga o compleja, como calcular el número π Actores: Usuario (U) Precondición: Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario abre la sección de la CPU. 2. U: Introduce el número de dígitos que desea calcular. 3. U: Inicia explícitamente la operación. 4. S: Calcula π y muestra los segundos transcurridos. 5. S: Informa de que el cálculo ha finalizado y de que pueden verse los

resultados. 6. U: El usuario desea ver los resultados. 7. S: Muestra las cifras que se han calculado.

Extensiones: 4.1 El usuario desea detener la operación. 4.1.1 U: Detiene la operación. 4.1.2 S: Deja de calcular π e informa de que la operación se ha detenido. 4.1.3 Finalizar caso de uso.

Page 73: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

70

Caso de uso: Ver estado sensores Objetivo: Ver el estado de los sensores conectados al módulo Actores: Usuario (U) Precondición: Hay un sensor de temperatura y un sensor de luz conectados al sistema Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario abre la sección de los sensores. 2. S: Obtiene el valor de cada sensor y lo convierte a centígrados o lúmenes,

según el caso. 3. S: Muestra los valores de luz y temperatura al usuario. El SISTEMA repite los pasos 2-3 cada cierto tiempo.

Extensiones:

Caso de uso: Apagar y encender LED Objetivo: Ver el estado de los sensores conectados al módulo Actores: Usuario (U) Precondición: Hay un botón GPIO y un LED GPIO conectados al sistema Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario abre la sección del estado de la CPU.

2. S: Obtiene el estado del botón y el LED. 3. S: Muestra el estado actual del botón y el LED por pantalla. 4. U: Cambia el estado del botón, de OFF a ON o de ON a OFF. 5. S: Ilumina o apaga el LED según el estado del botón. 6. S: Muestra el estado actual del botón y el LED por pantalla.

Extensiones:

Caso de uso: Enviar datos Objetivo: Enviar estado de los sensores y el botón GPIO hacia la nube Actores: Usuario (U) Precondición: Hay un botón GPIO, un LED GPIO, un sensor de temperatura y un sensor de luz conectados al sistema Postcondición: Pasos:

1. El caso de uso se inicia cuando el Usuario abre la pantalla de configuración.

2. S: Muestra todas las opciones de configuración. 3. U: Selecciona la frecuencia con la que desea enviar los datos a la nube. 4. U: Selecciona qué valores desea enviar a la nube. 5. U: Confirma los cambios. 6. S: Envía los datos en segundo plano y cada cierto tiempo según los

parámetros elegidos.

Extensiones:

Page 74: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

71

NOMBRE DEL TEST NAVEGABILIDAD DE LA INTERFAZ

Descripción Comprobación de la navegabilidad de la interfaz gráfica.

Procedimiento El usuario selecciona una opción del menú lateral. El sistema carga una pantalla u otra en función de la opción seleccionada.

Resultado

CORRECTO. El sistema carga el fragmento del reproductor de vídeo por defecto. La sección actual se marca de color verde. Las secciones se resaltan cuando pasamos el ratón por encima o las mantenemos pulsadas. No surge ningún problema a la hora de cargar el resto de fragmentos.

NOMBRE DEL TEST REPRODUCIR VÍDEO

Descripción Reproducir un vídeo dentro de la carpeta por defecto.

Procedimiento

El usuario selecciona el reproductor de vídeo y uno de los vídeos de la galería. El sistema lo reproduce. El usuario para el vídeo y lo adelanta en la barra de reproducción.

Resultado

PARCIALMENTE CORRECTO. El sistema carga una miniatura de los vídeos que encuentra en la carpeta por defecto, pero las miniaturas son demasiado grandes. Hay que reducir el tamaño. Se reproduce automáticamente el primer vídeo de la carpeta.

NOMBRE DEL TEST MOSTRAR PORCENTAJE DE CARGA Y HABILITAR NÚCLEOS

Descripción Mostrar el porcentaje de carga de los núcleos de la CPU mientras estos se habilitan o deshabilitan.

Procedimiento El usuario habilita o deshabilita un núcleo. El sistema actualiza el estado del núcleo y muestra el porcentaje de carga en tiempo real.

Resultado

CORRECTO. El sistema muestra el porcentaje de carga de los núcleos de forma numérica y rellenando una barra de progreso. Si el núcleo no está habilitado, el porcentaje se sustituye por Disabled y la barra se vacía. Si volvemos a habilitar el núcleo, los datos se muestran de nuevo.

Page 75: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

72

NOMBRE DEL TEST ESTRESAR LA CPU

Descripción Estresar el procesador calculando el número π.

Procedimiento

El usuario indica el número de dígitos. El usuario comienza la operación El usuario espera hasta que termine la operación y pulsa sobre Ver resultados. El usuario comienza la operación y la detiene.

Resultado

INCORRECTO. El sistema calcula π y habilita el botón de Ver resultados. La aplicación se cierra al intentar poner en pantalla un número tan alto de cifras. La operación no se detiene cuando pasamos a otro fragmento (permanece en segundo plano). El cálculo de π en sí y el cronómetro no dan problemas. El porcentaje de carga de algunos núcleos se eleva hasta el 100%.

NOMBRE DEL TEST ENVIAR DATOS DE SENSORES

Descripción Comprobar que los datos de los sensores se almacenan correctamente en la nube.

Procedimiento

El usuario configura el envío de datos. El usuario entra a la pantalla de sensores y la deja abierta. El usuario entra a su cuenta de Digi Device Cloud y comprueba que le llegan los datos.

Resultado

PARCIALMENTE CORRECTO. El sistema envía los datos a la nube teniendo en cuenta la configuración elegida. Los datos aparecen en la cuenta de Digi Device Cloud y se van actualizando cada cierto tiempo. Leve retardo en la interfaz por aparición de throttles. El LED se enciende cuando pulsamos el botón.

Page 76: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

73

Reunión nº 1

FECHA HORA ASISTENTES 04/02/2016 13:00 – 14:00 M. Vico Pascual, Raúl Hernáez, Iciar Sesma, Gabriel

Valcázar ASUNTO LUGAR Presentación del proyecto de fin de grado Universidad de La Rioja ORDEN DEL DÍA

1. Puesta en común al tutor académico de cada uno de los temas. 2. Recomendaciones sobre el proyecto de fin de grado.

RESULTADO 1. Se establece el plan de comunicaciones con el tutor. 2. Posibilidad de registrarse en la aplicación de gestión de TFGs.

Reunión nº 2

FECHA HORA ASISTENTES 09/02/2016 13:20 – 13:40 M. Vico Pascual, Raúl Hernáez ASUNTO LUGAR Presentación del tema Universidad de La Rioja ORDEN DEL DÍA

1. Puesta en conocimiento al tutor de los requisitos del proyecto. 2. Preguntas al tutor sobre la estructura y gestión del proyecto (metodología a

aplicar). RESULTADO

1. Las dudas se han resuelto.

Reunión nº 3

FECHA HORA ASISTENTES 03/03/2016 11:00 – 12:00 Pedro Pérez, Rubén Moral, Tatiana León, Raúl Hernáez ASUNTO LUGAR Revisión parcial del SDK Oficinas de Digi, sala Iregua ORDEN DEL DÍA

1. Muestra a Pedro Pérez del trabajo realizado hasta el momento, incluidos código, aplicación de ejemplo y documentación.

RESULTADO 1. Aprobación por parte de Pedro Pérez del trabajo realizado hasta el momento. 2. Posible ampliación de alcance mediante una aplicación de ejemplo, a concretar

en las próximas semanas.

Page 77: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

74

Reunión nº 4

FECHA HORA ASISTENTES 06/04/2016 13:00 – 13:30 M. Vico Pascual, Raúl Hernáez ASUNTO LUGAR Puesta al día del proyecto Universidad de La Rioja ORDEN DEL DÍA

1. Puesta al día al tutor de las decisiones de planificación que se han tomado en el proyecto.

2. Preguntas al tutor sobre la estructura del proyecto y aspectos técnicos. RESULTADO

1. Las dudas se han resuelto. 2. Fijada una fecha límite (20/04/2016) para enviarle la memoria al tutor.

Reunión nº 5

FECHA HORA ASISTENTES 08/04/2016 12:30 – 13:30 Pedro Pérez, Rubén Moral, Tatiana León, Raúl Hernáez ASUNTO LUGAR Revisión final del SDK Oficinas de Digi, sala Iregua ORDEN DEL DÍA

1. Revisión final del SDK. 2. Ampliación del alcance mediante una aplicación de ejemplo.

RESULTADO 1. Aprobación por parte de Pedro Pérez del trabajo realizado. 2. Nueva fase de revisión a realizar antes de la aplicación de ejemplo.

Reunión nº 6

FECHA HORA ASISTENTES 27/04/2016 10:45 – 11:00 Rubén Moral, Tatiana León, Raúl Hernáez ASUNTO LUGAR Presentación de la aplicación de ejemplo Oficinas de Digi, sala Leza ORDEN DEL DÍA

1. Presentación de la aplicación de ejemplo.

RESULTADO 1. Se dan a conocer los requisitos de las dos primeras secciones de la aplicación. 2. Habrá otra reunión para establecer los próximos requisitos de la aplicación. La

reunión tendrá lugar después de que se implemente la primera parte.

Page 78: Implementación de un SDK para la plataforma ConnectCore 6 ... · Implementación de un SDK para la plataforma ConnectCore 6 y el framework Xamarin Autor/es ... Este proyecto consiste

TRABAJO DE FIN DE GRADO UNIVERSIDAD DE LA RIOJA

75

Reunión nº 7

FECHA HORA ASISTENTES 12/05/2016 13:30 – 14:15 M. Vico Pascual, Raúl Hernáez ASUNTO LUGAR Corrección de la memoria Universidad de La Rioja ORDEN DEL DÍA

1. Correcciones y comentarios de la tutora sobre la memoria.

RESULTADO 1. La próxima entrega de la memoria corregirá los errores que se han comentado

durante la reunión.

Reunión nº 8

FECHA HORA ASISTENTES 18/05/2016 11:30 – 12:00 Pedro Pérez, Rubén Moral, Tatiana León, Raúl Hernáez ASUNTO LUGAR Presentación de la segunda parte de la aplicación

Oficinas de Digi, sala Leza

ORDEN DEL DÍA 1. Revisión de la primera parte de la aplicación. 2. Presentación de los requisitos de la segunda parte de la aplicación.

RESULTADO 1. Aprobación del trabajo realizado hasta el momento. 2. Se dan a conocer los últimos requisitos de la aplicación.

Reunión nº 9

FECHA HORA ASISTENTES 8/06/2016 11:30 – 12:30 Pedro Pérez, Rubén Moral, Tatiana León, Raúl Hernáez ASUNTO LUGAR Revisión final de la aplicación de ejemplo Oficinas de Digi, sala Iregua ORDEN DEL DÍA

1. Revisión final de la aplicación. El alumno hará una demostración de la aplicación.

RESULTADO 1. Aprobación del trabajo realizado hasta el momento. 2. Se dan algunas pautas de cara a la defensa del proyecto ante la comisión de

evaluación. 3. El proyecto se ha cerrado por completo.