BESA MICRO-EDITION, ARQUITECTURA DE SISTEMAS MULTIAGENTE PARA MICROCONTROLADORES T.G. 0505 DAVID MAGIN FLOREZ RUBIO GUILLERMO ANDRES RODRÍGUEZ CANTOR JUAN MANUEL ORTIZ GÓMEZ PONTIFICIA UNIVERSIDAD JAVERIANA FACULTAD DE INGENIERIA CARRERA DE INGENIERIA ELECTRÓNICA BOGOTÁ 2005 BESA MICRO-EDITION, ARQUITECTURA DE SISTEMAS MULTIAGENTE PARA MICROCONTROLADORES T.G. 0505 DAVID MAGIN FLOREZ RUBIO GUILLERMO ANDRES RODRÍGUEZ CANTOR JUAN MANUEL ORTIZ GÓMEZ Informe Final Director ENRIQUE GONZALEZ Ingeniero Eléctrico PONTIFICIA UNIVERSIDAD JAVERIANA FACULTAD DE INGENIERIA CARRERA DE INGENIERIA ELECTRÓNICA BOGOTÁ 2005 ii TABLA DE CONTENIDO INTRODUCCIÓN 1 1. 3 1.1. 1.2. 2. 2.1. 2.2. 2.2.1. 2.2.2. 2.3. 2.3.1. 2.3.2. 2.3.3. 2.3.4. 3. 3.1. 3.2. 3.2.1. 3.2.2. 3.2.3. 3.3. 3.3.1. 3.3.2. 3.3.3. OBJETIVOS OBJETIVO GENERAL OBJETIVOS ESPECÍFICOS 3 3 MARCO TEÓRICO 5 SISTEMAS MULTI-AGENTE Aplicaciones ARQUITECTURA BESA DE SISTEMAS MULTI-AGENTE DEFINICIÓN DE AGENTE Estructura de un Agente (Canal – Comportamiento – Estado) Definición de Contenedor REQUERIMIENTOS DE BESA Necesidades de Sincronización Necesidades de Concurrencia Comunicación entre Agentes SISTEMAS OPERATIVOS SISTEMAS OPERATIVOS EN TIEMPO REAL PLANIFICACIÓN MECANISMOS DE SINCRONIZACIÓN Semáforos Mensajes MANEJO DE MEMORIA DESARROLLO 5 5 6 6 7 8 9 9 10 10 11 12 13 15 16 17 18 21 REQUERIMIENTOS DE BESA 21 SELECCIÓN DEL RTOS Y DE LA FAMILIA DE MICROCONTROLADORES 21 BÚSQUEDA Y SELECCIÓN DEL RTOS 21 SELECCIÓN DE LA FAMILIA DE MICROCONTROLADORES 24 APROPIACIÓN DEL RTOS 26 Gestión de Memoria 26 Pruebas Realizadas 26 CONSTRUCCIÓN DEL MODELO BESA-ME 27 DESCRIPCIÓN GENERAL 27 NIVEL AGENTE 28 Estructuras Asociadas a la Identificación del Agente 29 Construcción del Canal 30 Construcción del Comportamiento 32 El Estado 33 Simulación del envío de un Evento al Canal y ejecución de sus Comportamientos 34 NIVEL SISTEMA 34 Creación del Contenedor 35 El Administrador Local en BESA-ME 37 Envío de Eventos BESA desde Interrupciones 37 Comunicación entre Agentes 39 iii 3.4. 3.4.1. 3.4.2. 4. 4.1. 4.1.1. 4.1.2. 4.2. 4.2.1. 4.2.2. 4.2.3. PROTOCOLO DE COMUNICACIÓN EXTERNA PROTOCOLO DE COMUNICACIÓN A NIVEL BYTE Selección del Protocolo de Comunicación a Nivel Byte Introducción al Funcionamiento del Protocolo I2C Implementación del Protocolo de Comunicación a Nivel Byte PROTOCOLO DE COMUNICACIÓN A NIVEL TRAMA Trama Evento BESA Trama Acknowledge BESA Secuencia de Comunicación del Protocolo a Nivel Trama PRUEBAS Y ANÁLISIS DE RESULTADOS PROTOCOLO DE PRUEBAS IDENTIFICACIÓN DE VARIABLES Variables Independientes Variables Intervinientes Variables Dependientes PRUEBAS A REALIZAR Pruebas de Capacidad Pruebas de Comunicación Pruebas de Interrupciones ANÁLISIS DE LOS RESULTADOS OBTENIDOS PRUEBAS DE CAPACIDAD Tamaño del Stack Cantidad de Agentes por Contenedor Cantidad de Comportamientos Cantidad de Guardas Cantidad de Puertos Síntesis de Resultados Obtenidos PRUEBAS DE COMUNICACIÓN Envíos de Eventos por el Canal de Comunicación Tiempos de Respuesta a Eventos Tipos de Errores en la Comunicación Externa PRUEBAS DE INTERRUPCIONES 40 40 40 41 43 46 46 47 48 61 61 61 61 63 63 64 64 64 65 65 65 66 66 68 69 69 70 70 71 74 77 81 5. CONCLUSIONES 87 6. BIBLIOGRAFIA 91 7. ANEXOS 93 ANEXO A. MANUAL DEL USUARIO. ANEXO B. CODIGO DE PROGRAMACION. iv 93 94 INDICE DE FIGURAS Figura 1. Arquitectura interna de un agente. Tomado del artículo BESA.5 7 5 Figura 2. Modelo del nivel de sistema BESA. Tomado de BESA. 9 Figura 3. Modelo de Agente en BESA-ME 29 Figura 4. Estructuras asociadas al Agente 29 Figura 5. Estructura asociada al canal. 30 Figura 6. Estructura asociada a los Puerto y a las Guardas. 31 Figura 7. Estructura del Mensaje recibido por el Comportamiento. 31 Figura 8. Estructura asociada al Comportamiento. 33 Figura 9. Nivel Sistema en BESA-ME con el servicio de comunicación entre contenedores. El administrador local se encarga del manejo de los eventos. 35 Figura 10. Estructura asociada Contenedor. 36 Figura 11. Estructura de los buffer de Transmisión y de Recepción para la comunicación entre contenedores. 36 Figura 12. BESA_DATA, Estructura en la que almacenan los datos de usuario. 37 Figura 13. BESA_EVENT, Estructura en la que se almacena el tipo de evento y el BESA_DATA. Figura 14. 37 ISR_BESA_EVENT, Estructura en la que se almacena un BESA_EVENT cuando quiere ser enviado desde una rutina de interrupción. Figura 15. Diagrama de bloques del tratamiento de eventos 38 desde una rutina de interrupción. 38 Figura 16. Formato de tramas utilizadas para la comunicación entre Contenedores. 46 Figura 17. Tipos de respuesta acknowledge en BESA-ME. Ejemplo del envío de un agente X a un agente Z ubicados en distintos contenedores. 49 Figura 18. Señales START, no Acknowledge Hardware y STOP. 54 Figura 19. Señales presentes durante la comunicación exitosa desde un contenedor hacia otro contenedor. Tamaño máximo de Datos igual a 6. DataSize igual a 8. 55 Figura 20. Envío y recepción de eventos al bus I2C por medio de interrupciones. 56 Figura 21. Diagrama de flujo de la comunicación entre agentes en BESA-ME. 60 Figura 22. Envíos exitoso para diferentes frecuencias de envío y tamaño de cola igual a uno. Figura 23. 73 Envíos exitoso para diferentes frecuencias de envío y tamaño de cola igual a dos. Figura 24. 73 Envíos exitoso para diferentes frecuencias de envío y tamaño de cola igual a tres. Figura 25. 74 Tiempos de atención a eventos periódicos de envíos externos, desde los comportamientos. 75 v Figura 26. Tiempos de atención a eventos periódicos de envíos locales, comportamientos. Figura 27. desde los 76 Envíos exitosos vs periodo de envío, para dos agentes ubicados en distintos contenedores. Cada punto representa un grupo de 100 envíos 77 Figura 28. Porcentaje de causas de error para un xDelayTime de 2ms. 78 Figura 29. Porcentaje de causas de error para un xDelayTime de 11ms. 78 Figura 30. Porcentaje de causas de error para un xDelayTime de 14ms. 78 Figura 31. Porcentaje de causas de error para un xDelayTime de 20ms. 79 Figura 32. Envíos exitosos vs periodo de envío, para 2 agentes productores y un consumidor. 80 Figura 33. Porcentaje de Causas de error para un xDelayTime de 3 ms. 80 Figura 34. Porcentaje de Causas de error para un xDelayTime de 10 ms. 81 Figura 35. Porcentaje de Causas de error para un xDelayTime de 14 ms. 81 Figura 36. Envíos generados desde interrupciones periódicas. 83 Figura 37. Distribución de los agentes y sus respectivos comportamientos para la aplicación Figura 38. de demostración. 85 Distribución de los agentes según los recursos físicos disponibles. 86 vi INDICE DE TABLAS Tabla 1. Comparación de los recursos de memoria entre PIC18F452 y PIC18F8720. Tabla 2. Descripción de los bytes de la trama Event BESA para un Data Size de tamaño Tabla 3. N. 25 47 Descripción de los bytes de la trama Ack BESA. Constante para cualquier tamaño de datos. 48 Tabla 4. Valores de los Stacks. 66 Tabla 5. Tiempos de Respuesta para distintas cantidades de Agentes en un Contenedor. Todos los tiempos en milisegundos. Tabla 6. 67 Tiempos de Respuesta para distintas cantidades de Comportamientos en un Contenedor. 68 Tabla 7. Cantidad máxima de Guardas en un contenedor 69 Tabla 8. Tiempos de respuesta a eventos con distintas cantidades de Puertos 69 Tabla 9. Envíos de Eventos por el puerto I2C con diferentes tamaños de colas y periodos de envío. 71 Tabla 10. Tiempos de respuesta a un envío remoto por I2C. 74 Tabla 11. Tiempos de atención a los envíos externos de eventos periódicamente. Tabla 12. Tiempos de 75 atención a los periódicamente. Tabla 13. generados envíos locales de eventos generados 76 Promedio de Envíos exitosos y fallidos generados desde una rutina de interrupción a un agente local. 82 vii INTRODUCCIÓN En la cotidianidad se puede observar que para la solución eficiente de problemas complejos, resulta conveniente dividirlos en tareas más simples que puedan ejecutarse por separado. Un buen resultado depende de la coordinación entre ellas. Éste mismo concepto puede ser llevado a la industria, donde el avance de la tecnología plantea nuevos retos que requieren soluciones rápidas y efectivas. Existe un modelo que abstrae el concepto de tareas distribuidas y que propone un esquema para la construcción de sistemas complejos. Éste modelo es conocido como Sistema Multi-Agente (SMA). A partir de los desarrollos sobre SMA publicados por Jiming Liu, se puede obtener una visión general del origen y justificación de este modelo. Sus desarrollos respondían a la pregunta de por qué tener múltiples individuos afirmando: “por la misma razón que organizaciones como las conformadas por abejas y hormigas están formadas por grupos de individuos nacidos con una labor específica, los individuos se comunican entre sí, para entre todos, lograr un objetivo común” 1 . De esta forma, se muestra la existencia de entidades (individuos) especializadas para el desarrollo de determinadas labores y como a través de estas entidades, es posible distribuir las tareas, disminuyendo la carga para cada uno de ellos y mejorando el resultado final. Los SMA no sólo son una tecnología muy prometedora, también están emergiendo como una nueva manera del pensamiento: un paradigma conceptual para analizar problemas y para el diseño de sistemas; un medio para manejar la complejidad, distribución e interactividad, y quizás una nueva perspectiva en las ciencias de la computación y la inteligencia artificial 2 . El diseño de aplicaciones desde el concepto SMA presenta algunas dificultades tales como la falta de herramientas para su desarrollo y su reducido uso industrial. Para darle solución a lo anterior hemos desarrollado una herramienta de programación de alto nivel que facilita la distribución de tareas y su aplicación en un entorno hardware, con la característica de permitir al diseñador modificarlas en una forma eficiente, así como realizar labores de mantenimiento o actualización del sistema (escalabilidad). Dado el extendido uso de los microcontroladores para aplicaciones industriales y de investigación, la implementación de la herramienta se ha realizado sobre estos dispositivos. 1 LIU, Jiming. “Multi – Agent Robotic Systems”. CRC Press, Boca Ratón, Fl. 2001 2 Robocup Federation, “RoboCup Home Page”. http://www. robocup.org. 1 Debido al enfoque Multi-Agente de la herramienta que fue implementada, este libro comienza con un resumen de las generalidades y aplicaciones de los SMA. En el capítulo siguiente se describe BESA, la arquitectura de SMA desarrollada en la Pontificia Universidad Javeriana, con base en la cual se ha desarrollado la herramienta descrita en este trabajo y que da origen a su nombre BESA Micro Edition (BESA-ME). Una vez identificadas las necesidades de este modelo de SMA y su aplicación a microcontroladores, se muestra la necesidad de usar un Sistema Operativo que las soporte, por lo cual continuamos con un capítulo donde se explican las características generales y se describen más a fondo los Sistemas Operativos de tipo Tiempo Real (RTOS por sus siglas en inglés). Luego, en el desarrollo, se sintetizan lo requerimientos de ejecución de la arquitectura BESA, con base en estos se explica como se seleccionó el RTOS para soportar el modelo y como fue construido el modelo BESA adaptado a las características de un micro-controlador y a un ambiente distribuido de dos microcontroladores. exponen las Por último, se pruebas y sus resultados, con los cuales se evaluaron las características de capacidad y velocidad de la herramienta aplicada a una plataforma hardware específica. BESA-ME es entonces una herramienta innovadora, económica y de gran facilidad de aplicación, diseñada con posibilidades de ser actualizada a medida que los microcontroladores evolucionen. 2 1. OBJETIVOS 1.1. Objetivo General Desarrollar una plataforma de software que implemente el modelo BESA para una familia de microcontroladores, permitiendo la creación de aplicaciones con enfoque Multi-Agente. 1.2. Objetivos Específicos 1. Seleccionar e implementar para una familia de microcontroladores, un sistema operativo ya existente que posea las características de un RTOS y proporcione los servicios básicos de un ambiente multitarea requeridos por el modelo BESA. 2. Diseñar e implementar una plataforma de software basada en el modelo BESA que funcione sobre el RTOS seleccionado e implementado y que soporte la creación de aplicaciones con enfoque Multi-Agente. 3. Desarrollar el servicio de comunicación entre agentes de dos microcontroladores de la misma familia adecuado para el modelo BESA. 3 4 2. MARCO TEÓRICO En este marco teórico se muestra un resumen de las generalidades y aplicaciones de los Sistemas Multi-Agente. Con base en esto se describe el modelo abstracto de SMA planteado por la arquitectura BESA. Dadas las características que plantea este modelo y su aplicación a microcontroladores, se muestra la necesidad de usar un Sistema Operativo Tiempo Real, sobre el cual se profundiza también. 2.1. Sistemas Multi-agente Un Sistema Multi-Agente (SMA) es un sistema computacional con características de autonomía, es decir, capaz de ejecutar ciertas tareas dentro de un entorno determinado y modificarlo, según la función especifica para la cual fue diseñado. Las funciones que puede realizar están definidas por un conjunto de instrucciones que pueden ser ejecutadas o no. La arquitectura del sistema determina la forma de comunicación entre agentes y la administración de los recursos 3 . En la estandarización de estas arquitecturas de SMA, la fundación FIPA (Foundation for Intelligent Physics Agents) ha creado ciertas directrices. Propone una plataforma de software que contiene la definición de un lenguaje de comunicación entre agentes y los elementos básicos para la construcción del sistema 4 . Aplicaciones Actualmente los Agentes y los sistemas multiagente son una de las tecnologías más prominentes y atractivas de la ingeniería y la informática. Las tecnologías, métodos y teorías de sistemas multiagentes están contribuyendo en diversos dominios de aplicación, tales como: recuperación de información, diseño de interfases de usuario, robótica, juegos de computador, educación, ambientes de entretenimiento, manejo y administración de proyectos, simulación social, realidad virtual, etc. En la solución de muchos de estos problemas se emplean mecanismos de control de software y de hardware, como algoritmos computacionales y máquinas dedicadas que utilizan microcontroladores y DSP. 3 WEISS, Gerhard. “Multiagent systems: A modern approach to Distributed Artificial Intelligence”. Masachussets, U.S.A 1999. 4 Foundation For Intelligent Physical Agents, http://www.fipa.org, Noviembre 5 del 2004. 5 2.2. Arquitectura BESA de Sistemas Multi-Agente BESA es una arquitectura para la construcción de Sistemas Multi-Agente, que implementa tres conceptos principales en su modelo abstracto de SMA 5 , de los cuales se desprende la sigla BESA: • Behavior – Oriented: Los agentes se descomponen modularmente en entidades más simples, las cuales poseen ciertos comportamientos con una semántica asociada entre ellos, que permite la cooperación. Un agente está compuesto por un conjunto de comportamientos concurrentes. • Event – Driven: Los eventos que desencadenan la ejecución de comportamientos son señales que pueden ser percibidas o usadas por los agentes y esta ejecución depende de un mecanismo selector que evalúa el estado actual de la entidad y el estado de comunicación asociado a la detección del evento. • Social – Based: El sistema se crea sobre una organización social de agentes, compuesta en un conjunto de organizaciones de más bajo nivel, que conservan la estructura de un agente y cuyos últimos eslabones son los agentes individuales. 2.2.1. Definición de Agente Un agente es la unidad abstracta fundamental a partir de la cual se conforma el sistema MultiAgente BESA. A nivel social es la unidad más simple que sirve como base para construir cualquier nivel superior. Su arquitectura interna determina la estructura del sistema, los mecanismos de interacción entre los mismos agentes y el tratamiento dado a los eventos con el fin de obtener una respuesta. Los agentes responden a eventos provenientes del entorno o de una tarea en ejecución. Así como el agente puede percibir eventos provenientes del entorno, también puede modificarlo. Para esto, cada evento que se defina en el sistema debe tener un tratamiento asociado, de manera que cuando el agente lo perciba ejecute un procedimiento y se obtenga un resultado. Un agente debe además poder comunicarse con los demás agentes del sistema, pues es fundamental la interacción entre ellos para lograr el objetivo esperado a través de la ejecución concurrente de las tareas, el intercambio de eventos y la respuesta dada a los mismos. 5 GONZALEZ, Enrique, AVILA, Jamir, BUSTACARA, César. “BESA” Bogotá, Colombia. 2003. 6 Estructura de un Agente (Canal – Comportamiento – Estado) La arquitectura interna de los agentes integra cuatro elementos importantes: una composición modular de comportamientos, un canal compuesto por un buzón de recepción y un mecanismo selector de eventos y un estado. Figura 1. Arquitectura interna de un agente. Tomado del artículo BESA.5 El canal y el comportamiento son las dos tareas por las cuales está compuesto un agente como mínimo. En el canal se reciben los eventos; para cada tipo de evento debe existir un puerto al cual se asigna el evento recibido para ser transferido a los comportamientos asociados. Allí se almacenan y se ejecutan los procedimientos relacionados a cada evento. Como se observa en la figura 1, el canal está formado por un buzón de entrada, donde se reciben los eventos direccionados al agente. Mediante un mecanismo selector basado en guardas los eventos que se reciben se transfieren al puerto correspondiente. Los puertos al igual que el buzón de entrada son colas, que permiten almacenar varios eventos de un mismo tipo en un puerto específico. La política implementada para el despacho de los eventos es FIFO (First in – First out), razón por la cual por cada tipo de evento asignado a un agente, debe existir un puerto asociado, con el fin de evitar el bloqueo entre eventos y que no se ejecuten los procedimientos relacionados en el momento adecuado. 7 El evento almacenado en el puerto sólo se transfiere al comportamiento correspondiente cuando se comprueba una condición booleana, que se puede ver afectada por el mismo evento o por una variable que influye en la condición, disparando la guarda. Los comportamientos son tareas que pueden ejecutarse en paralelo y deben estar asociados con la guarda asociada al tipo de evento. Cada comportamiento tiene una cola para recibir eventos provenientes de los puertos del canal; cuando llega el evento, el comportamiento ejecuta automáticamente la función de tratamiento correspondiente. Un sistema multitarea permite que varios procesos sean ejecutados al mismo tiempo, compartiendo uno o más procesadores. BESA tiene la característica de ser una arquitectura multitarea ya que debe coordinar concurrentemente el uso del canal de comunicación y la ejecución de los comportamientos de los agentes en tiempo real. Tener más de un comportamiento en la arquitectura de un agente permite el paralelismo en el sistema, es decir, la ejecución de diferentes procedimientos en tiempo real, como respuesta a eventos que pueden ser concurrentes o no. Dentro de la arquitectura del agente existe un espacio denominado Estado (State) reservado para guardar información acerca del contexto del agente, del entorno, de los demás agentes y del sistema en general, según el tipo de información que el usuario final requiera. El estado puede ser accedido desde las funciones de tratamiento que se ejecutan en el comportamiento; puede ser leído y modificado según se requiera, por lo que debe ser protegido para que sólo pueda ser accedido por una tarea a la vez. Definición de Contenedor Un conjunto de agentes reunidos da origen a un nivel social más abstracto conocido como sistema. En BESA un sistema está formado por contenedores, que pueden funcionar en diferentes máquinas físicas o virtuales. Un contenedor es un espacio de ejecución donde los agentes habitan. Estos están manejados por un administrador local que es el encargado de la gestión del ciclo de vida de los agentes y de permitir la comunicación con agentes de otros contenedores. 8 Modelo del nivel de sistema BESA. Tomado de BESA.5 Figura 2. Los agentes pertenecientes a un mismo contenedor interactúan directamente, a diferencia de los agentes ubicados en distintos contenedores, los cuales se comunican entre si a través de un único puerto compatible con FIPA, el cual recibe la comunicación y las consultas de otros sistemas externos. (Ver Figura 2). 2.2.2. Requerimientos de BESA Necesidades de Sincronización En la construcción del modelo de implementación (BESA-ME, BESA-Micro Edition) surge la necesidad de proteger estructuras y variables que pueden ser accedidas por varias tareas al mismo tiempo. Si una tarea accede a determinada variable y está utilizando la información contenida en ésta, ninguna otra tarea debe acceder a la misma variable hasta que no sea liberada por la tarea anterior. En el peor de los casos el acceso simultáneo por más de una tarea a una variable podría causar que ésta sea modificada mientras está siendo accedida y generar un error en la información o en la ejecución. Para evitar que esto suceda es necesario contar con algún mecanismo de señalización que proteja la variable a la que se accede y la información contenida en ella, de manera que en los casos críticos en los que se requiera, sólo una tarea pueda acceder la variable a la vez. La utilización de semáforos es seguramente la solución más adecuada para solucionar los problemas de sincronización. Cuando se va a acceder a una variable crítica, se baja el semáforo, cuando se libera la variable se sube el semáforo y otra tarea puede accederla. 9 Necesidades de Concurrencia Debido a que el modelo abstracto de BESA plantea la ejecución de los comportamientos en paralelo, se requiere que la arquitectura BESA sea una arquitectura multitarea, creando cada comportamiento y cada canal como una tarea del sistema operativo, lo que permite su ejecución concurrente por parte del planificador del RTOS. Cada agente puede tener más de un comportamiento, y a cada comportamiento le son asignados eventos con sus respectivas funciones de tratamiento; las funciones deben ser ejecutadas entonces simultáneamente para responder a los eventos en tiempo real a medida que se vayan presentando. Puede ser útil entonces, el manejo de prioridades para asegurar la ejecución de ciertos comportamientos críticos que requieran una acción inmediata, teniendo presente que se debe evitar la inanición de las tareas de menor prioridad. El hecho de que el canal sea una tarea que se ejecute paralelamente con los comportamientos, asegura al máximo la recepción de los eventos que le sean dirigidos y su reenvío a los comportamientos correspondientes. Comunicación entre Agentes BESA plantea un servicio de directorios que facilita la comunicación entre los agentes. El servicio tiene dos secciones principales: una de páginas blancas donde es posible ubicar los agentes por una identificación dada en el momento de la creación; y otra de páginas amarillas donde se puede localizar a un grupo de agentes que tengan ciertas características en común, según su especialidad. Cada contenedor tiene su propio servicio de directorios. La comunicación entre agentes se puede dar de dos maneras diferentes: entre agentes del mismo contenedor o entre agentes de contenedores distintos. Comunicación entre Agentes del Mismo Contenedor Cuando un agente quiere comunicarse con otro, recurre entonces al servicio de directorios para poder localizar el destinatario, ya sea por su identificación o por su especialidad. Si los agentes pertenecen al mismo contenedor, la comunicación es directa, envían información de uno a otro, sin que el administrador local del contenedor intervenga. Comunicación entre Agentes de Distintos Contenedores El agente acude al servicio de directorios para localizar al agente con el que se quiere comunicar. Una vez localizado, la comunicación se realiza a través del puerto serial al que todos los contenedores pueden acceder, el cual se encarga de transmitir y recibir la información proveniente de otro contenedor y entregarla al agente correspondiente. 10 Los contenedores deben tener en su servicio de directorios la información correspondiente a los agentes existentes en los demás contenedores. Si un agente es creado o destruido, el administrador local del contenedor debe informar a todos los otros contenedores del sistema, con el fin de que sea actualizado su servicio de directorios. Lo mismo debe hacerse en el arranque del sistema para que cada contenedor conozca a de la existencia de otros contenedores y agentes 6 . 2.3. Sistemas Operativos Los Sistemas Operativos (SO) son uno de los más grandes logros en el desarrollo de software y constituyen uno de los más complejos programas. La búsqueda por lograr una administración eficiente y segura de los recursos de un computador ha llevado al desarrollo de los conceptos de proceso, gestión de memoria, seguridad y protección de la información, planificación y gestión de recursos, y estructura de sistema 7 . El concepto de proceso es uno de lo grandes logros en el desarrollo de SO. Se define como la mínima unidad de actividad; está caracterizada por una ejecución secuencial, por un estado actual y por estar asociada a un conjunto de recursos. Está compuesto por una o más unidades de trabajo conocidas como hilos, estos incluyen un contexto propio y áreas de datos propias, a partir de las cuales se logran establecer bifurcaciones a subrutinas, es decir, son interrumpibles y permiten que los procesos cedan y retomen el control del procesador (control expropiativo), utilizando así, la técnica de multi-hilos para ejecutar varias tareas independientes (multiproceso) 8 . Para la administración del paso de ejecución de un proceso a otro y sus implicaciones existen varios algoritmos de planificación. Esta administración parte de 5 posibles estados de los procesos: Nuevo, Listo, Ejecutándose, Bloqueado y Terminado, según los cuales se deben tomar las acciones determinadas por el algoritmo de planificación. En la actualidad el estándar POSIX, define la interfaz que los sistemas operativos deben ofrecer a las aplicaciones, así como la semántica de los servicios ofrecidos por esta interfaz. 6 GONZALEZ, Enrique, AVILA, Jamir, BUSTACARA, César. “BESA” Bogotá, Colombia. 2003. 7 STALLINGS, William. “Sistemas Operativos”. Prentice Hall. Madrid, España. 2001. 8 STALLINGS, William. “Sistemas Operativos”. Prentice Hall. Madrid, España. 2001. 11 2.3.1. Sistemas Operativos en Tiempo Real Cuando un sistema computacional requiere dar respuesta a determinados dispositivos en tiempo real, aspectos como la administración eficiente de la memoria y el aumento en la eficiencia de utilización de la CPU se hacen secundarios, tal es el caso de las plataformas robóticas y mallas de control industrial. Esta necesidad ya ha sido detectada por empresas diseñadoras de microcontroladores usados en aplicaciones de tiempo real y ha sido superada mediante el desarrollo de sistemas operativos para estos dispositivos, son conocidos como sistemas operativos en tiempo real (RTOS, siglas en inglés). Los Sistemas Operativos Tiempo Real son diseñados para administrar la respuesta a sucesos o eventos, de tal forma que se respeten ciertos rangos de tiempo de respuesta, los cuales, en el caso de ser críticos para el sistema, requieren atención inmediata. En todo caso el RTOS es determinista, en consecuencia permite que el usuario prediga los tiempos de respuesta que el RTOS proporcionará al sistema informático que administra. Estos eventos, normalmente se producen en el entorno del sistema; estos llegan como interrupciones al procesador, ya sean por software o hardware. Los RTOS deben atender ráfagas de miles de interrupciones que activan diferentes procesos. Para no perder ningún suceso recibido, el RTOS debe trabajar con la técnica multiproceso, la cual ejecuta los procesos independientemente unos de otros, pero en ciertas aplicaciones se deben tener estrategias para asignar prioridad a los procesos y ejecutarlos según su importancia, lo cual se logra con una planificación expropiativa basada en prioridades. Algunas de las características más importantes de los RTOS son 9 : - La gestión de dispositivos críticos en tiempo. - Sofisticadas estrategias para la gestión de interrupciones. - Eficiente almacenamiento de E/S. - Permiten acceso desde los programas de usuario a los vectores de interrupción para prestar servicio a los sucesos. Otras áreas críticas en los RTOS son el determinismo, la sensibilidad, el control del usuario, la gran fiabilidad y la tolerancia a los fallos. 10 Entre éste tipo de SO se encuentran muchas versiones comerciales de alto costo como URTX, RTX, QNX, útiles para dispositivos de alto desempeño como los microprocesadores 80X86 y 9 MILENKOVICH, Milan. “Sistemas Operativos: Conceptos y Diseño”. Mc. Graw Hill, Madrid, España. 1998. 10 STALLINGS, William. “Sistemas Operativos”. Prentice Hall. Madrid, España. 2001. 12 algunos de libre distribución como SALVOTM y la migración del SO MartOS al MC68332 11 . SALVOTM, con versiones para microcontroladores Microchip, TI y Motorola entre otros, soporta multiproceso y en su versión de libre distribución soporta hasta tres tareas simultáneas12 . 2.3.2. Planificación El planificador es un conjunto de políticas y mecanismos incorporados al Sistema Operativo que gobiernan el orden en que se ejecutan las tareas en un sistema multiprogramado. El objetivo primario de la planificación es optimizar el rendimiento del sistema de acuerdo con los criterios considerados más importantes por los diseñadores. Existen 3 clases de planificadores, los cuales se clasifican según la frecuencia con la que es invocado por el procesador; estas son planificaciones a largo, mediano y corto plazo; este último es el único que se implementa en los RTOS. El planificador a corto plazo, también conocido como distribuidor (Dispacher), es el que toma decisiones con una mayor frecuencia y detalle sobre la tarea que se ejecutará a continuación. Su principal objetivo es maximizar el rendimiento del sistema de acuerdo con un conjunto de criterios elegidos. El planificador a corto plazo debe ser ejecutado por lo tanto, cada vez que una tarea se detenga (bloqueo), o cada vez que un suceso (interno o externo) ocurra. Éste es el tipo de planificador que soportan los sistemas RTOS, ya que el tiempo de ejecución es el criterio más importante a tener en cuenta. La suspensión, la terminación o aborto de una tarea en ejecución, son también sucesos que pueden necesitar la llamada al planificador a corto plazo. 13 Los algoritmos o mecanismos de planificación se pueden dividir en dos grandes grupos, expropiativos y no expropiativos. La no expropiación implica que cuando una tarea de mayor prioridad aparece, la tarea actual en ejecución no se ve obligada a ceder la propiedad del procesador, sino hasta que éste termine su ejecución. Con planificación expropiativa una tarea en ejecución puede ser sustituida por una tarea de mayor prioridad en cualquier instante, lo que implica entonces una mayor carga de trabajo para el planificador pero un menor tiempo de respuesta a los eventos críticos. Las características que deben cumplir los RTOS son apoyadas por el uso de planificación expropiativa. Round Robin (RR), planificación por turno rotatorio o también conocida como fracciones de tiempo, presenta una apropiación del reloj de modo que se genera periódicamente una interrupción indicando que la tarea que se encuentra en ejecución tiene que ser colocada en la 11 CASTO GUTIÉRREZ, Alberto, “Migración de un Sistema Operativo De Tiempo Real, MaRTE OS, a un microcontrolador”, http://marte.unican.es/alberto_slides.ppt, Septiembre 5 de 2004. 12 SALVOTM, http://www.pumpkinc.com, Febrero 15 de 2004. 13 MILENKOVICH, Milan. “Sistemas Operativos: Conceptos y Diseño”. Mc. Graw Hill, Madrid, España. 1998. 13 cola de listas y se selecciona la siguiente, según un FIFO. El criterio de diseño es el tiempo de duración de los cuantos (fracciones de tiempo) que se va a usar. Si el cuanto es muy pequeño, las tareas cortas tendrán que pasar varias veces por el sistema antes de ser finalizados, generando una sobrecarga en la gestión de recursos. Si el cuanto es muy grande, RR se degenera en un simple FIFO donde las tareas cortas tienen que esperar mucho tiempo. Existen otros algoritmos de planificación que presentan una serie de características más complejas, impidiendo así cumplir con los criterios necesarios para la implementación de un RTOS. Algunos de estos son SRT (Shortest Remaining Time), para el cual la tarea con menor tiempo esperado de ejecución será la más prioritaria; Realimentación el cual presenta un mecanismo dinámico de colas y prioridades. Cada cola representa un nivel de prioridad, y el más alto es el de las tareas más nuevas. Una vez una tarea vuelve a su estado de Lista, luego de su primera ejecución, es colocado en la segunda cola de menor prioridad. Después de cada ejecución, la tarea Lista es degradada al nivel inmediatamente inferior de prioridad. Cada una de estas colas funciona con la filosofía de FIFO, menos la última, que funciona con el mecanismo de RR por no poder descender más; Planificación de colas multi-nivel (MLQ, Multiple-Level Queues), el cual clasifica la carga de trabajo de acuerdo con sus características y mantiene colas de tareas separadas servidas por diferentes planificadores. Una posible separación sería programas interactivos, tareas del sistema y trabajos de lotes (simuladores). Estas asociaciones no son de gran utilidad, para sistemas en tiempo real, por lo que no se suele implementar esta disciplina en RTOS. Un criterio más que debe cumplir un RTOS en el que se desee implementar en un sistema MultiAgente es el “tiempo de respuesta”, es decir, cualquier opción que presente una reducción en el tiempo de procesamiento y de decisión, debe aparecer en las posibilidades de adopción para éste proyecto. La no utilización de planificadores a largo y mediano plazo es una decisión evidente para cumplir con los parámetros necesarios, ya que el tiempo de procesamiento requerido por cada uno de ellos, implica retardos indeseables. Por esta misma razón, los algoritmos de planificación que requieren de cálculos complejos son desechados de las posibilidades de implementación, como los son SPN (Shortest Process Next), SRT (Shortest Remaining Time), Mayor Tasa De Respuesta y Colas Multi-Nivel, métodos descritos anteriormente. “La planificación dinámica del mejor resultado es el método utilizado en la mayoría de los sistemas en tiempo real comercializados en la actualidad. Cuando llega una tarea, el sistema le asigna una prioridad en función de sus características. Normalmente, se emplea alguna forma de planificación por plazos, como puede ser la de primero el plazo más próximo. En general, las tareas son aperiódicas, por lo que no es posible un análisis estático de planificación. Con este tipo de planificación, no se sabe si se va a cumplir una restricción de tiempo hasta que vence el 14 plazo o la tarea termina. Esta es la mayor desventaja de esta forma de planificación. Su ventaja está en la facilidad de implementación.” El uso de múltiples colas, cada una de ellas de distintas prioridades (diferente al mecanismo de Colas Multi-Nivel), recorridas con el mecanismo de turno rotatorio, se presenta como la mejor opción de implementación para los requerimientos de BESA, ya que la característica de Event – Driven requiere de una selección de tareas basada en prioridades, y de rotación equitativa, además, su fácil implementación garantiza una rápida ejecución del planificador, evitando de esta forma la inanición de procesos 14 . 2.3.3. Mecanismos de sincronización Los sistemas operativos de tipo tiempo real (RTOS) soporten la concurrencia de tareas. Esta característica tiene varios niveles de complejidad dependiendo el tipo de relación que tienen entre sí las tareas que requieren el uso del procesador, así: estas tareas pueden ser independientes y no conocer la existencia de las otras (competencia), tener conocimiento indirecto de las otras tareas (cooperación por compartimiento) o tener conocimiento directo de las otras tareas (cooperación por comunicación). Las anteriores relaciones llevan a situaciones de competencia y de cooperación que deben ser soportadas por el sistema operativo o tenidas en cuenta por el programador. Para que un sistema soporte la concurrencia sincronizada de tareas, en éste se deben realizar dos acciones fundamentales: la Administración de recursos globales y la Gestión óptima de los recursos. Para llevarlas a cabo se han diseñado los mecanismos de sincronización. Estos permiten solucionar los tres problemas principales de la sincronización entre tareas: la exclusión mutua, el inter-bloqueo y la inanición de las tareas. El problema de la exclusión mutua se da cuando un recurso puede ser usado por una sola tarea y no puede compartir su tiempo con otras hasta que la tarea salga de la sección de programa que lo usa, estos recursos son llamados recursos críticos y la región del programa que los usa son llamadas regiones críticas. El sistema operativo junto con otros servicios se deben encargar de que sólo una tarea opere en su sección crítica a la vez. Por otro lado el inter-bloqueo se presenta cuando dos tareas (o más) esperan la liberación de un recurso compartido, y a s vez, esta espera retiene la liberación de otro recurso. Por último la inanición de una tarea se da cuando el SO le concede el uso de un recurso a determinadas tareas periódicamente y se impide que alguna o algunas tareas determinadas vuelvan a tomar el control del procesador, por ejemplo por ser de baja prioridad. 14 MILENKOVICH, Milan. “Sistemas Operativos: Conceptos y Diseño”. Mc. Graw Hill, Madrid, España. 1998. 15 Los problemas de sincronización que aparecen por la concurrencia de tareas son fundamentalmente los mismos tanto para un sistema monoprocesador, donde se intercalan las tareas, como para un sistema multiprocesador, donde también hay superposición (simultaneidad) en la ejecución de tareas. Las soluciones a los anteriores problemas se pueden agrupar en tres tipos: • Por software, estas son implementadas en el código de programa de usuario. Los 15 Algoritmos de Dekker y de Peterson ofrecen una solución de éste tipo . • Desde sistema operativo, a través de funcionalidades como los semáforos y los mensajes. • Por Hardware, como, por ejemplo, el uso de inhabilitación por interrupciones. El primer tipo es propenso a errores y a generar sobrecarga en el sistema. Las soluciones por Hardware usan instrucciones de máquina por lo que no son soluciones generales. Estos problemas no se presentan en las soluciones implementadas como servicios del sistema operativo o del lenguaje de programación, por esto y otras ventajas adicionales, se han convertido en las estrategias de sincronización de más éxito. Dado que cubren las necesidades de facilidad de programación y portabilidad, necesarias para el desarrollo del proyecto, serán las óptimas para cumplir los objetivos planteados. Explicamos su funcionamiento básico a continuación. Semáforos El principio de los semáforos es la cooperación entre las tareas por medio de la generación de señales y usados como mecanismos de sincronización permiten que se cumpla la exclusión mutua entre tareas y evitan el interbloqueo. Los semáforos son variables que se modifican a través de dos tipos de señales, una señal que indica que una tarea está esperando un resultado y que llamaremos down y una señal que indica que se ha producido el resultado la cual llamaremos up con la cual el semáforo debe “dejar pasar” una de las tareas que se encontraban “esperando” en ese semáforo. La variable semáforo puede iniciar en un valor no negativo y se debe disminuir en una unidad cuando haya down y aumentar cuando se produzca up. Si al llegar un down el valor del semáforo se hace negativo entonces la tarea que generó el down se bloquea ya que dicho valor indica que no hay resultados disponibles para la tarea que los solicita. Ahora, cuando se produce una señal up hacia cierto semáforo, significa que se produjo un resultado de interés para las tareas que hayan estado esperando o para las que van a llegar a esperar, por lo cual se incrementa en una unidad el valor del semáforo respectivo. 15 STALLINGS, William. “Sistemas Operativos”. Prentice Hall. Madrid, España. 2001. 16 Para decidir a cual de las tareas que produjeron un down en determinado semáforo se le debe dar el control del procesador cuando ocurra el siguiente up (debido a la liberación de un recurso, por ejemplo) se ha encontrado que la política más equitativa es FIFO, esta decisión es independiente del mecanismo de planificación del sistema operativo. FIFO es la política para semáforos más apropiada para el RTOS a implementar ya que disminuirá el riesgo de inanición de una tarea en el acceso a un recurso. Una vez una tarea haya solicitado acceso al semáforo ninguna tarea de más prioridad podrá quitárselo. Los semáforos permiten solucionar el problema de la exclusión mutua, mediante identificadores que avisen con una señal down cuando se entra en la sección crítica de un programa. Sin embargo, el éxito del uso de semáforos depende de su correcto manejo, debido a que la falta del uso de alguna de estas dos señales puede llegar a bloquear el sistema. Mensajes El paso de mensajes entre procesos permite que las tareas cooperantes se sincronicen y que a su vez intercambien información. El servicio de mensajería es útil en sistemas distribuidos, en sistemas multiprocesador y monoprocesador de memoria compartida. Por lo cual será de gran utilidad para la comunicación entre agentes. Por un lado tenemos el intercambio de información. Para intercambiar información se necesita al menos un sencillo protocolo de comunicación que permita la sincronización de los mensajes. El esquema más sencillo consiste en el uso de las primitivas send y receive. Con estas primitivas se pueden generar distintas configuraciones: bloqueo de la tarea tras generar send hasta que reciba una respuesta, o no bloqueo, bloqueo tras generar receive hasta encontrar un mensaje o no bloqueo. Según el tipo de sistema a desarrollar existen diferentes técnicas para solucionar problemas como la pérdida de los mensajes o el bloqueo indefinido de las tareas al esperar un mensaje que nunca llega. Para enviar y recibir mensajes hacia y desde la tarea correcta se usa el direccionamiento directo e indirecto, para cada primitiva. La primitiva send con direccionamiento directo requiere tener identificadores para cada tarea, el cual debe ser enviado al llamar la primitiva. En el caso de direccionamiento indirecto los mensajes se envían a una estructura de datos formada por colas (denominada buzón), en las cuales se almacena temporalmente la información hasta que un receptor la lee, es análogo a un arreglo de buzones donde cada uno ha sido creado para establecer distintos tipos de relaciones entre las tareas. Estas relaciones pueden ser de un emisor a un receptor (comunicación punto a punto), de un emisor a muchos receptores o de muchos emisores a un receptor, para éste último caso el buzón es denominado puerto. 17 La primitiva receive con direccionamiento directo requiere que cada tarea tenga conocimiento anticipado sobre qué tarea o tareas le enviarán información, pero para los casos en que es imposible predecir de qué tareas se va a recibir un mensaje en cada instante, se usa el direccionamiento implícito, en éste, al ejecutar la primitiva receive, la tarea receptora espera el identificador de la tarea que da origen al mensaje, proveniente de la ejecución de un send. Cuando sucede un envío con exitosa recepción, el sistema puede realizar una copia del mensaje en una cola o buzón, o simplemente transferir el apuntador a la información, lo cual la convertiría en memoria compartida. Cuando se realiza copia del mensaje se asegura que no se modificará indeseablemente el contenido de la información, sin embargo, éste método es lento, ya que a medida que crece el tamaño de la información crece el tiempo de transferencia, además utiliza más memoria para la creación de los buzones pero evita usar recursos adicionales para proteger la información. El traslado del apuntador utiliza eficientemente la memoria, pero se debe tener cuidado (usando los mecanismos adecuados) para no modificar los mensajes originales en casos indeseados. Cuando se quiere minimizar la carga de procesamiento y minimizar el coste de almacenamiento, requerimientos de este proyecto, se usa un formato de mensajes de tamaño corto y fijo apoyado en una organización de memoria por ejemplo pool de buffers, concepto que se ampliará en la sección 2.3.4. En el formato del mensaje se incluye algunas veces información sobre la prioridad del mensaje, para soportar el caso en el que no se desee tomar los mensajes de un buzón con política FIFO. Por otro lado el paso de mensajes permite la sincronización respecto a los recursos del sistema, es decir, soporta la exclusión mutua 16 . 2.3.4. Manejo de memoria Dadas las características de memoria de los microcontroladores actuales, se necesita una estrategia para el manejo de memoria que no consuma muchos recursos del dispositivo y que no sobre cargue el procesador. La estrategia más sencilla es definir cuales son los tamaños de palabra más útiles para el sistema operativo y crear arreglos de buffers de estos tamaños, y solicitarlos al sistema a medida que se vayan necesitando. La anterior estrategia es conocida como pool of buffers. Presenta la ventaja de requerir mínimo sobre costo en el uso del procesador ya que elimina la búsqueda de espacios de memoria libres al dejarlos de tamaño fijo. Sin embargo puede llegar a ser ineficiente el uso de la memoria cuando se reserva un espacio mayor al máximo de los buffers necesario o se usa menos espacio que el menor de los reservados. Además, el programador debe ser muy cuidadoso de liberar los 16 MILENKOVICH, Milan. “Sistemas Operativos: Conceptos y Diseño”. Mc. Graw Hill, Madrid, España. 1998. 18 semáforos de protección una vez han sido usados los buffers, para permitir la posterior reutilización de los mismos. 19 20 3. DESARROLLO Se comenzó por analizar los requerimientos de la arquitectura BESA; con base en estos se explica como se seleccionó el RTOS para soportar la construcción y aplicación del modelo. Se adaptó el modelo BESA a las características de un micro-controlador, luego se diseño y aplicó un protocolo de comunicación para la extensión del modelo a un ambiente distribuido que usa dos microcontroladores. 3.1. Requerimientos de BESA En el capítulo 2 se describieron las características de Concurrencia, Sincronización y Comunicación entre tareas como los principales requerimientos del modelo BESA. Como se mostró en el aparte de sistemas operativos, estas características son soportadas por los RTOS actuales, pero adicional a estos requerimientos surge uno nuevo, ya que al ser implementado sobre un microcontrolador se hace crítica la capacidad de memoria del hardware. En consecuencia es indispensable tener en cuenta que el modelo se pueda implementar sobre las condiciones de memoria del dispositivo seleccionado. 3.2. Selección del RTOS y de la Familia de Microcontroladores Se realizó una investigación sobre el funcionamiento de un RTOS en un micro controlador desarrollando un kernel básico sobre un PIC18F452. Luego se buscaron los RTOS disponibles en el mercado, buscando que tuvieran las características necesarias para implementar el modelo BESA. Teniendo en cuenta criterios de bajo costo y facilidad de adaptación a nuestras necesidades se seleccionó el RTOS freeRTOS y se estudiaron los posibles microcontroladores sobre los cuales desarrollar la aplicación. 3.2.1. Búsqueda y Selección del RTOS El Sistema Operativo necesario para la implementación de BESA debe ser como primera medida de tiempo real, ya que se requiere dar respuesta a los eventos con la mayor rapidez posible y de manera simultánea. Por esta razón el planificador debe dar tiempo de procesamiento a todas las tareas que lo requieran, y contar con la característica de expropiación para permitir que tareas de mayor prioridad tomen el control del procesador cuando lo necesiten. Además el SO debe brindar un mecanismo para la creación y eliminación de tareas, y la posibilidad de suspenderlas y reactivarlas, ya sea a una o a todas simultáneamente, en cualquier instante del procesamiento. 21 El RTOS debe brindar la posibilidad de utilizar Semáforos, mecanismo seleccionado como la mejor opción para solucionar los problemas de Sincronización, ya que permite el uso adecuado de los espacios de memoria compartida a los que varias tareas (canal, comportamientos y otras) pueden acceder, como el estado y los buffers utilizados para las transmisiones de un contenedor a otro. Un motivo por el cual una tarea puede llegar a bloquearse, es el envío no exitoso de un mensaje a otra tarea; esta razón trae consigo la necesidad de un servicio de transmisión de mensajes entre tareas, que permita la acumulación de mensajes cuando el planificador no permita su inmediata recepción por tener bloqueada la tarea destino. Esto se logra por medio de colas tipo buzón, en las cuales se puedan almacenar temporalmente eventos que serán atendidos una vez la tarea destino sea desbloqueada y pueda recibir y dar tratamiento a los eventos enviados. La búsqueda de un sistema operativo arrojó como resultados varios RTOS de libre distribución desarrollados por distintas organizaciones y versiones de demostración de algunas empresas. De todos estos destacamos aquí dos de los más sobresalientes y que más se acomodaban a nuestras necesidades, SALVOTM y freeRTOSTM. SALVOTM, del grupo PumpkincTM, fue diseñado expresamente para sistema embebidos, cuyas aplicaciones típicas usan entre 1 y 2K bytes de ROM, y entre 50 y 100 bytes de RAM. Cumple con el criterio de multitarea cooperativa, servicio de eventos, bloqueo y suspensión de tareas, y con muchos otros aspectos necesarios descritos anteriormente para el desarrollo del proyecto. SALVOTM puede implementar en una gran cantidad de dispositivos, como son: • Familia 8051 y derivados. • ARClite microRISC. • ARM® ARM7TDMI® • Atmel® AVR® y MegaAVR™ • Motorola M68HC11 • TI's MSP430 Microcontriolador de baja potencia • Microchip PIC12|14000|16|17|18 PICmicro® MCUs • TI's TMS320C2000 DSPs Sin embargo, la versión demo de SALVOTM que puede ser adquirida libremente permite crear únicamente 3 tareas como máximo, lo que impediría en gran parte un buen aprovechamiento del mismo 17 . La adquisición de la versión completa implica una inversión económica que no está contemplada en el proyecto, razón de peso para desistir de este RTOS. 17 SALVOTM, http://www.pumpkinc.com, Febrero 15 de 2004. 22 FreeRTOSTM ofrece bajo consumo memoria RAM puesto que ha sido desarrollado específicamente para aplicaciones con sistemas embebidos (microcontroladores). Presenta además tres modelos posibles de asignación de memoria para la implementación de las aplicaciones. Utiliza un tipo de planificación expropiativa que implementa colas por cada nivel de prioridad, recorridas cíclica y equitativamente según el mecanismo FIFO; también ofrece un sistema de sincronización por medio de semáforos binarios. FreeRTOSTM es de libre distribución, es de fácil implementación y entendimiento gracias a que se puede acceder libremente a su documentación. FreeRTOSTM también puede ser implementado en una gran variedad de dispositivos 18 : • LPC2106, LPC2124 and LPC2129 (ARM7). Incluye código para el manejo de I2C. Renesas H8S2329 (Hitachi H8/S) con un demo de EDK2329. • Atmel AT91SAM7 o las familias (AT91SAM7S32, AT91SAM7S64, AT91SAM7S128, AT91SAM7S256). Incluye código para el manejo de USB para IAR Kickstart. • AT91FR40008 con demo de ATEB40X . • MSP430 con manejador de LCD. • HCS12 (MC9S12C32) • Cygnal 8051 / 8052 • Microchip PICMicro (PIC18) • Atmel AVR (MegaAVR) con código de demostración STK500. • RDC8822 Microcontroller (AMD clon embebido del 186) con demo para Flashlite 186 SBC. • PC [corre con FreeDOS u otro DOS] FreeRTOSv2.6.0 ofrece todas las características necesarias para la correcta implementación de la arquitectura BESA, así como servicios que facilitaron las pruebas ejecutadas en el transcurso del proyecto. Los códigos y la documentación pueden ser descargados de Internet y traen adjunto tres programas de demostración que sirven para familiarizarse con el RTOS, sirviendo de punto de partida para nuevas aplicaciones. Se puede observar que este sistema operativo tiene más oportunidades de migración a otros procesadores que los ofrecidos por SALVOTM, y por consiguiente mayores aplicaciones posibles para el futuro de BESA-ME. Además cuenta con un foro en la red donde es posible aclarar dudas y compartir inconvenientes y soluciones junto con los demás usuarios y los desarrolladores del RTOS. Todas estas características llevaron a tomar la decisión de implementar FreeRTOSTM como sistema operativo soporte a la plataforma BESAME desarrollada. 18 FreeRTOSTM, www.freertos.org. Mayo 25 de 2005. 23 3.2.2. Selección de la Familia de Microcontroladores La familia de microcontroladores fue escogida con los siguientes criterios: • Debe ser soportada por el RTOS escogido. (freeRTOSTM) • Se analizó que tuviera la memoria suficiente para soportar el RTOS seleccionado y dejar libre la memoria necesaria para el código BESA-ME. • El tercer criterio fue que ofreciera un módulo para la comunicación con otros dispositivos microcontroladores, para permitir que agentes de distintos contenedores pueden interactuar. • Para la generación de interrupciones interpretadas como eventos en el contesto BESAME y la interacción con otros dispositivos hardware como respuesta a estos, se observó que ofreciera un número de puertos y periféricos considerable. • Finalmente se tuvo en cuenta la familia de microcontroladores más usados en el contexto académico de los proyectos desarrollados en la Carrera de Ingeniería Electrónica de la Pontificia Universidad Javeriana, en el cual se desarrolla BESA-ME. Cualquiera de los sistemas embebidos que se desee implementar en la práctica, presentará como criterio más crítico, la limitación de los recursos físicos. En éste caso, los requerimientos de BESA indican que el recurso más limitado es el de memoria, pues esta arquitectura requiere del uso constante de buzones para la recepción y envío de mensajes. Además, es necesaria la asignación dinámica de segmentos de memoria que serán utilizados y reutilizados según la aplicación implementada. El stack requerido por las tareas para guardar su información cuando se produce un cambio de contexto, y las estructuras propias de BESA implican también un espacio de memoria. El continuo manejo de colas, (tanto para planificación de tareas, como para los comportamientos y eventos del sistema) que serán modificadas y leídas por distintas tareas (las colas son memoria compartida), implica también el manejo de semáforos, que también consumen memoria, para la correcta sincronización en el acceso a los espacios de memoria que lo necesiten. Todos estos aspectos demuestran porque el aprovechamiento de la memoria al máximo es un aspecto crítico del presente proyecto. De esta forma, los criterios de selección del microcontrolador para el proyecto, están ligados con la selección del RTOS freeRTOS. Este RTOS presenta demostraciones específicas para el microcontrolador PIC18F452 de microchip. Además, la universidad posee el hardware necesario para la programación de estos dispositivos (ICD2 – In Circuit Debbuger), así como el software de simulación y de programación (MPLAB). Adicionalmente, la plataforma ROBOCOOP 19 que sería un ambiente óptimo para la aplicación de BESA-ME usa el microcontrolador PIC18F452. 19 ROBOCOOP Es un proyecto de robótica distribuida, desarrollado en la Pontificia Universidad Javeriana. 24 El PIC18F452 se acomoda fácilmente a las necesidades de la arquitectura BESA gracias al soporte que presta el sistema operativo a este dispositivo. Sin embargo, no fue el microcontrolador usado para finalizar el desarrollo de BESA-ME. Luego de realizar la construcción del Nivel Agente, expuesto más adelante, se encontró que la capacidad de memoria del PIC18F452 sólo permitía la creación de 1 agente y 2 TM comportamientos, razón por la cual se decidió realizar una migración de freeRTOS microcontrolador de la misma familia pero con más capacidad de memoria. a otro Se escogió el PIC18F8720, por las características que se muestran en la Tabla 1. Para lograr esto fue necesario modificar el archivo p18f8720.lkr que viene incluido en los archivos del compilador mcc18 de Microchip para el lenguaje de programación C. Estas modificaciones fueron necesarias debido a que el manejo de memoria que hace freeRTOSTM requiere que se defina un gran bloque de memoria sobre el cual se separan los bytes de RAM a medida que se solicitan (ver anexo C). PIC18F452 20 PIC18F8720 Memoria de Programa (Bytes) 32K 128K Memoria de Programa (Instrucciones) 16384 65536 Memoria de Datos (Bytes) 1536 3840 Memoria de Datos EEPROM (Bytes) 256 1024 Fuentes de Interrupciones 18 18 21 Tabla 1. Comparación de los recursos de memoria entre PIC18F452 y PIC18F8720. Realizando esta migración de freeRTOS se demostró parte de la fácil implementación de la arquitectura BESA-ME en una gran variedad de microcontroladores, ya que a Nivel de Agente la migración sólo depende de que el RTOS, la capa inferior de la arquitectura, sea portada al dispositivo deseado. Esta familia de microcontroladores está siendo usada además en los proyectos de investigación del grupo SIRP 22 de la Pontificia Universidad Javeriana. P De esta forma, la plataforma BESA-ME será la base de futuras aplicaciones tanto para SIRP como para aquellos estudiantes que deseen enfocar el desarrollo de sus proyectos por medio de sistemas Multi-Agente. 20 MICROCHIP, PIC18FXX2 Data Sheet, Microchip Technology Inc 2002. 21 MICROCHIP, PIC18F6520/8520/6620/8620/6720/8720 Data Sheet, Microchip Technology Inc 2002. 22 SIRP, Sistemas inteligentes, Robótica y Percepción. Grupo de Investigación de la Facultad de Ingeniería Electrónica, Pontifica Universidad Javeriana. 25 3.2.3. Apropiación del RTOS FreeRTOSTM presenta tres programas de demostración que son descargados junto con el sistema operativo. Cada uno de estos demos presenta características distintas con el fin de que el usuario se acomode a distintos aspectos del sistema. El circuito inicial creado para la realización de las pruebas se basó completamente en las necesidades de dichos demos. Gestión de Memoria FreeRTOSTM presenta tres esquemas para el manejo de memoria. La asignación estática de espacios de memoria se presenta como opción para sistemas en la cuales no se creará ni se eliminarán dinámicamente tareas, colas o semáforos; de tal forma que esta distribución se realiza sólo una vez en el sistema. El segundo esquema de planeación, asigna espacios de memoria que luego podrán ser liberados, sin embargo puede llegar a se ineficiente en su funcionamiento, si los tamaños asignados en la creación de diversas variables son distintos, presentando indeseablemente segmentación de memoria. Y por último, el tercer esquema maneja dinámicamente la asignación de la memoria RAM, pero se sugiere que sea utilizado aplicaciones con computadores de escritorio, ya que requiere de mucho más procesamiento. BESA-ME utilizará entonces el primer modelo de manejo de memoria, ya que no requiere la liberación dinámica de espacios, puesto que las tareas creadas inicialmente, no serán destruidas nunca. Además es el esquema de más fácil aplicación, y el que mejor se desempeña en dispositivos microcontroladores. Pruebas Realizadas Luego de confirmar el correcto funcionamiento del RTOS, se procedió a realizar la primera aproximación de las tareas necesarias para la implementación de los requerimientos de BESA. Para esto se realizaron las siguientes pruebas: 1. Una tarea envía a otra un dato, éste dato es puesto en una cola compartida de tamaño 1. La tarea que envía el dato (productora) se duerme durante un tiempo prudencial para poder apreciar fácilmente el suceso (aproximadamente 500ms). Cuando la tarea consumidora recibe el dato, lo muestra en el respectivo LED del puerto B, configurado como salida. Cuando el productor se despierta, incrementa el valor anterior, y manda un nuevo dato, para que el consumidor lo muestre. 2. Ahora, aparece una tercera tarea que envía con una frecuencia menor, a la misma cola un dato negativo, de tal forma que cada vez que llega un dato el consumidor decrementa en uno el orden de muestra de los LEDs. En esta segunda prueba, las tareas funcionan perfectamente, no se pierden datos ni se alteran los mismos. 26 3. En la tercera prueba, una cuarta tarea aparece como productora, introduciendo un valor constante de 2 que se suma al valor acumulado, dando la apariencia de un salto en la secuencia de los LED. En esta última prueba todos los productores presentan la misma prioridad, y el consumidor tiene una prioridad de cero. Con estas características, el sistema no funciona correctamente, se pierden datos. Sin embargo aumentando el tamaño de la cola N (N = Número de productores), el sistema regresa a la normalidad. Cuando el consumidor tiene mayor prioridad, ningún dato se pierde, aun cuando la cola sea de tamaño unitario. Una vez identificadas a plenitud las características de los métodos de envió y recepción de mensajes por medio de colas, la creación y bloqueo de tareas con las primitivas del RTOS, se procedió a la construcción del modelo abstracto de BESA. 3.3. Construcción del Modelo BESA-ME Diseñado para ser implementado en un microcontrolador, en el modelo BESA-ME se modificaron algunos servicios originales del modelo abstracto planteado por BESA, con el objetivo de ahorrar memoria y mejorar velocidad de respuesta, pero conservando siempre la esencia de la arquitectura. 3.3.1. Descripción General Dentro de las características que fueron modificadas se encuentran las condiciones booleanas, que se presentan en el mecanismo selector de guardas. Las condiciones booleanas ya no se verificarán para la activación de los comportamientos asociados. Para éste proyecto, no son de vital importancia. Su ausencia permitirá la reducción de gran parte el tiempo de filtrado de los eventos en los puertos, y la minimización del uso de memoria para la ubicación de los eventos que llegan a los puertos. Igualmente el servicio de directorio de agentes, fue simplificado eliminando la sección de páginas amarillas. En consecuencia, el usuario puede hacer envíos a un agente sólo si conoce el nombre del agente, el cual es llamado alias en el contexto BESA-ME. Los eventos recibidos por un agente, son almacenados directamente en una cola FIFO (tipo buzón) de eventos entrantes, propia del canal de cada agente. Se decidió recibir estos eventos por recopia y no por apuntador para garantizar la seguridad de la información pero en detrimento de la velocidad de respuesta a los eventos. Estos eventos son ubicados en los puertos correspondientes según el tipo de evento al que pertenezca. Existen tantos puertos como tipos de eventos declarados inicialmente. Cuando un evento llega a un puerto, se crea un 27 mensaje especial para ser enviado a los correspondientes comportamientos. Éste mensaje contiene el apuntador a la función que se debe ejecutar, y el dato proveniente del evento BESA inicial. Cuando el mensaje llega a la cola de recepción del comportamiento, éste se desbloquea, e invoca a la función correspondiente mandándole como parámetro el dato asociado a evento BESA. Esta función asociada, es la que el usuario final podrá programar directamente. En las funciones asociadas también se pueden presentar envíos de datos a otros agentes, ya sean del mismo contenedor o de otro. En el modelo abstracto de BESA, a nivel social, existen agentes mediadores que pueden servir como despachadores de eventos entrantes al contenedor, para distribuirlo a los agentes destinatarios. Un agente mediador puede servir también para manejar mecanismos de cooperación y asignación de tareas. Sin embargo, el modelo de implementación BESA – ME no contiene en su sistema agentes mediadores ya que la distribución de eventos, se realiza directamente a través del servicio de envíos dentro del contenedor cuando son originados por otro agente, o desde una tarea adaptador, encargada de recibir los eventos desde otro contenedor o desde las rutinas de interrupción del microcontrolador, con el objetivo de repartirlos adecuadamente. Por tal razón en lugar del nivel social, en BESA-ME hablaremos de nivel sistema. Otra característica importante es que, tras analizar el concepto de contenedor de BESA, como el espacio donde habitan y cumplen sus ciclos de vida los agentes, hemos decidido abstraer cada microcontrolador como un contenedor. El contenedor debe ser visto como el medio de interacción local de los agentes. Las estructuras y funciones de cada uno de los componentes del sistema BESA-ME se describirán a continuación separadas en dos niveles: El nivel agente en el cual no existe el contenedor y el nivel sistema donde inician las interacciones entre agentes. 3.3.2. Nivel Agente La implementación del modelo de agente BESA-ME, requiere de mínimo dos tareas para cumplir con el modelo BESA, estas son: la tarea encargada de cumplir las funcionalidades del canal y la que ejecuta cada comportamiento. En el caso más sencillo de agente se debe tener mínimo un comportamiento. Además, ligados a la creación del agente, deben existir mecanismos de identificación para ser usados por las tareas canal y comportamiento. Estas tareas son re-entrantes, en consecuencia, el mismo código es usado cada vez que se crea un agente o un comportamiento adicional, lo cual reduce la cantidad de memoria de programa 28 usada al escalar el sistema. En la Figura 3 se muestra la estructura implementada del agente, que se explica a continuación. AGENT Port_1 Guard_1 CHANNEL Guard_2 Behavior_1 Guard_X Buzón Port_2 Guard_1 Behavior_2 Guard_2 Action_1 Action_2 Guard_Y Events Behavior_N Action_N Port_M Guard_1 Guard_2 Estado Guard_Z Beh_1 Beh_2 Beh_N Figura 3. Modelo de Agente en BESA-ME Estructuras Asociadas a la Identificación del Agente El agente esta constituido por sus dos tareas básicas (Canal y Comportamiento) y por dos estructuras que permiten que el agente acceda a la información del sistema y que el sistema obtenga información de él, estas estructuras son: Figura 4. Estructuras asociadas al Agente Estructura Agente (stAgentBESA): Contiene datos como el estado del agente, el apuntador a la estructura del canal asociado a dicho agente, una lista de los comportamientos que se 29 encuentran asociados a dicho agente, y por último una estructura stAgentHandler que contiene a su vez el Alias y el AgentID, el cual para el caso de BESA-ME no es usado, ya que basta con el Alias para identificar al agente, sin embargo éste se deja allí para futuras aplicaciones. También está contenido aquí el apuntador a la cola de recepción del canal para la recepción de eventos. Podemos ver entonces que con el conocimiento del Alias, se puede acceder a toda la información relacionada con el agente. En la Figura 4 se observa el código con el que fue implementada. Construcción del Canal El canal es el encargado de recibir los eventos provenientes del entorno o de otros agentes, para luego asociarlos al puerto correspondiente, de esta forma el dato es enviado a los comportamientos indicados por la guarda asociada al puerto. Para esto, el canal debe contar, como mínimo, con un buzón de entrada (cola de recepción), un puerto por cada tipo de evento y una guarda que asocie el evento a un comportamiento. Estructura Canal (stChannelBESA): Contiene un apuntador a la cola de recepción del canal (xQueueRxChannel), un arreglo de apuntadores a los diferentes puertos que lo comprenden (apChannelPorts) y una variable para indicar el número de puertos (número de eventos) que tiene el canal (NumPortChannel). En la Figura 5 se observa el código con el que fue implementada. Figura 5. Estructura asociada al canal. El tamaño del arreglo de apuntadores está definido por el máximo número de puertos que el usuario haya establecido para el canal. Nótese que no se maneja un sistema de colas de almacenamiento de eventos retenidos, debido a que no se implementaron las condiciones booleanas de las guardas. Estructura Puerto: (stPortBESA) Cada puerto contiene una constante que indica el tipo de evento al que corresponde (xEventType), una variable que indica el número de asociaciones definidas para el tipo de evento (NumBindGuards) y un arreglo de apuntadores a guardas que contienen la información necesaria de cada asociación del puerto (apBindGuard). Estructura Guarda: (stGuardBESA) Tiene un apuntador a la función de tratamiento asociada al tipo de evento que debe ejecutarse en el comportamiento (*ActionFunction) y un apuntador a la 30 cola de recepción del comportamiento asociado (xQueueRxBehavior). En la Figura 6 se observa el código con el que fue implementada la guarda BESA y el puerto BESA. Figura 6. Estructura asociada a los Puerto y a las Guardas. Estructura Mensaje para el Comportamiento: (stMsgBehavior) Tiene un apuntador a los datos que se envían en el evento (pEventData) y un apuntador a la función de tratamiento asociada al tipo de evento (*ActionFunction) que debe ejecutarse en el comportamiento. De esta forma el usuario sólo tendrá que realizar la programación correspondiente a las funciones asociadas, con los datos entrantes al agente. En la Figura 7 se observa el código con el que fue implementado el tipo Mensaje a comportamiento. Figura 7. Estructura del Mensaje recibido por el Comportamiento. Para la ejecución del canal se creó una tarea a partir de los servicios del RTOS, la tarea asociada al canal se denomina vChannel. Esta es la encarga de revisar constantemente el buzón de entrada de mensajes para saber si ha recibido un evento; si no hay un evento pendiente en la cola, esta tarea se bloquea hasta que alguno llegue. Cuando se recibe un evento, la tarea debe verificar el tipo de evento y compararlo con los puertos existentes; si no existe un puerto para este tipo de evento el canal no ejecuta ninguna operación y el evento es ignorado; informándole además al transmisor inicial que el evento no pertenece al sistema. Al identificar el puerto correspondiente, se evalúa el número de asociaciones existentes, para la correcta ubicación del evento y se accede a las guardas para crear el mensaje y enviarlo al comportamiento indicado por la guarda. La tarea vChannel recibe como parámetro el apuntador a la estructura del canal pChannel, para así poder tener acceso a las demás estructuras. Dentro de esta tarea se crea el mensaje que se 31 envía al comportamiento, como se muestra a continuación en pseudo código de la tarea vChannel: void vChannel (void *pvParameters) { Creación de los apuntadores a las estructuras stPort, stGuard, stChannel, stEvent y stMsgBehavior; Asignación de los apuntadores a las estructuras creadas. for( infinito ) { if ( hay algún evento nuevo en la cola de recepción del canal? ) { for ( Se recorre cada uno de los puertos del arreglo de puertos ) { If ( el tipo de evento recibido es igual al tipo de evento del puerto actual?) { For ( Recorrer el arreglo de guardas para el puerto actual ) { Armar el mensaje para el comportamiento indicado en la guarda; Enviar el apuntador del mensaje a la cola de recepción del comportamiento indicado por la guarda actual; if ( envió no exitoso ) { intentar de nuevo el envío; } } }else { Aumentar la posición del apuntador para cambiar de posición en el arreglo de puertos; } } } } Construcción del Comportamiento El comportamiento es el encargado de recibir los mensajes que contienen el dato y el apuntador a la función de tratamiento que haya sido determinada por el usuario para el tipo de evento. Debe tener entonces una cola de recepción para almacenar los mensajes. Además es necesario acceder al estado del agente para obtener información del estado y poder modificarlo. La estructura asociada al Comportamiento es: Estructura Comportamiento: Tiene un apuntador a la cola de recepción del comportamiento (xQueueRxBehavior) y un apuntador al “Handler” del Agente (pAgentHandler) que permite acceder a su estructura y por ende al estado del agente. La estructura de los comportamientos se muestra en la figura 8. 32 Figura 8. Estructura asociada al Comportamiento. Para la ejecución del comportamiento se creó una tarea a partir de los servicios del RTOS, la tarea asociada al comportamiento se llama vBehavior. Es la encargada de revisar constantemente su cola de recepción para verificar la llegada de mensajes. Cuando llega un mensaje, el comportamiento debe propiciar la ejecución de la función de tratamiento, la cual debe recibir como entrada el apuntador al evento BESA que fue enviado en el mensaje y un apuntador al Agente al cual pertenece el comportamiento, a través del cual puede acceder al estado, si así lo requiere el usuario. A continuación se presenta el pseudo código de vBehavior: void vBehavior ( void *pvParameters ) { Creación de las las variables tipo stBehaviorBESA y stMsgBehavior; Creación y asignación de los apuntadores a las estructuras creadas; for ( infinito ) { if ( llegó algún evento a la cola de recepción del comportamiento ) { Se invoca la función de acción según lo indica el apuntador en el mensaje que acaba de llegar y se le mandan los datos recibidos; } } } El Estado El estado es un espacio de memoria compartida que sólo debe ser accedido desde las acciones ligadas a los comportamientos. A través del estado los comportamientos pueden actualizar información relativa al agente y a los procesos que éste ejecuta. Su implementación se realizó a través de una cola con capacidad para almacenar una apuntador de tipo void. Se crearon las funciones TakeStateData y GiveStateData para permitir al usuario modificar el estado en una forma segura. Su uso se explica en el manual del usuario que se encuentra en el anexo A. 33 Simulación del Envío de un Evento al Canal y Ejecución de sus Comportamientos Para verificar el correcto funcionamiento de la estructura de un agente, antes de expandir el modelo a más agentes y distintos contenedores, se realizó una prueba creando una tarea adicional para enviar eventos al canal. La tarea adicional llamada vPrueba envía al buzón del canal un determinado evento, bloqueándose luego de esto por un tiempo determinado; luego se despierta para repetir el envío. El canal recibe el evento, busca el puerto correspondiente y allí verifica la guarda para crear el mensaje y enviarlo al comportamiento adecuado. Una vez el mensaje llega al buzón del comportamiento, éste lo recibe y llama la función de tratamiento asociada para ejecutarla. El correcto funcionamiento de está primera aproximación del agente se observó a través de la ejecución de la función asociada, la cual conmutaba unos LED de acuerdo al dato recibido. Luego de observar el correcto desempeño del agente, se procede a aumentar el número de comportamientos asociados a un mismo tipo de evento. Prueba que arrojó resultados positivos observando la conmutación correspondiente de los LED; la última fase de estas primeras aproximaciones acerca de la configuración de un agente se basaron en la creación de distintos tipos de eventos enviados a un mismo agente, el cual activa a su vez, luego del tratamiento propio de cada entidad, los comportamientos asociados con sus respectivas funciones. 3.3.3. Nivel Sistema Una vez la estructura de cada agente esta completa, es necesario establecer el nivel superior del sistema BESA, es decir, el conjunto de varios agentes funcionando en el contexto de un contenedor. 34 BUS SERIAL I2C Contenedor A Contenedor B Contenedor C Administrador Local Administrador Local Administrador Local Páginas Blancas Páginas Blancas Páginas Blancas Agentes Sensor Figura 9. Agentes Actuador Sensor Agentes Actuador Sensor Actuador Nivel Sistema en BESA-ME con el servicio de comunicación entre contenedores. El administrador local se encarga del manejo de los eventos. Un sistema de agentes implementado en BESA–ME se considera como un sistema distribuido compuesto por uno o varios contenedores BESA, los cuales funcionan en diversas máquinas físicas o virtuales, en este caso, cada contenedor esta ubicado en un microcontrolador (contenedor físico). La integración de mas de un contenedor y la posibilidad de comunicación entre los agentes pertenecientes a éstos a través del protocolo serial I2C, completa el modelo BESA-Micro Edition a nivel de sistema distribuido. En la figura 9 se observa una representación gráfica del modelo implementado. Creación del Contenedor BESA-ME tiene estipulado, en su modelo de implementación, que cada contenedor esta contenido en un microcontrolador, el cual para efectos de la comunicación necesitará un número de identificación fijo, el cual está estipulado por una constante denominada CONTAINER_ID a la cual se le deben asignar valores desde 01H hasta 80H, para un máximo de 127 contenedores. El CONTAINER_ID es asignado por el usuario. 35 Figura 10. Estructura asociada Contenedor. Cada contenedor contiene una estructura necesaria para almacenar la información de los agentes internos y los de otros contenedores, tal como se muestra en la Figura 10 (directorio de páginas blancas de los agentes de todo el sistema). Además contendrá dos buffers para almacenar temporalmente los datos entrantes y salientes de la comunicación entre distintos contenedores. Esta utilización de espacios de memoria compartida (buffers, ver Figura 11) hace necesario el uso de sistemas de sincronización que permitan el manejo seguro de estos espacios de memoria. Se utilizan entonces dos semáforos propios de los servicios de freeRTOSTM, los cuales serán explicados en la sección de comunicación entre contenedores. Figura 11. Estructura de los buffer de Transmisión y de Recepción para la comunicación entre contenedores. El contenedor también contiene dos colas de recepción para manejar la información proveniente de otros contenedores. Estas colas permiten un manejo seguro del protocolo de comunicación entre contenedores. Hay otra cola más para la recepción de eventos BESA desde una rutina de interrupción. Los Eventos BESA en BESA-ME han sido implementados de tal forma que el usuario pueda crear su propio tipo de eventos, de acuerdo a sus necesidades, siempre y cuando respete la sintaxis explicada en el Manual del Programador (ver Anexo A). 36 Figura 12. BESA_DATA, Estructura en la que almacenan los datos de usuario. Como se observa en la figura 12, BESA_DATA cuenta con un campo data_size, en el cual se debe almacenar el número de bytes del evento, este debe ser inicializado por el programador. Figura 13. BESA_EVENT, Estructura en la que se almacena el tipo de evento y el BESA_DATA. A partir de BESA_DATA (Figura 12) se crea la estructura BESA_EVENT, en la cual, además, existe el campo xEventType, en donde el programador debe poner el tipo de evento de la estructura stEventBESA creada. (Figura 13). En el microcontrolador se ha declarado sólo una estructura de tipo stContainerBESA, a la cual se tiene acceso desde el apuntador pContainer, el cual es un apuntador de tipo global, en consecuencia no ha sido necesario usarlo como parámetro de alguna función en BESA-ME. El Administrador Local en BESA-ME El administrador local en BESA-ME está formado por un conjunto de tareas y funciones que se encargan de la administración de la comunicación entre agentes y la administración de los eventos BESA generados desde rutinas de interrupción. En este conjunto se encuentran vAdaptor y SendAck las cuales han sido implementadas como tareas. También están las funciones SendEvent, SendEventFromISR, SendEventI2C e i2cISR (ver Anexo A- sección API). Envío de Eventos BESA desde Interrupciones Pensando en las diferentes aplicaciones que se pueden implementar, como las enfocadas al control, se ha desarrollado un servicio especial para enviar eventos a los agentes desde una rutina de interrupción. El servicio es accedido desde la función SendEventFromISR. Cuando el envío del evento es generado desde una rutina de interrupción, se usa otro tipo de evento cuya estructura es ISR_BESA_EVENT (Figura 14). Este tipo de evento es usado automáticamente por el administrador local cuando el programador hace uso de la función SendEventFromISR. Los parámetros xEvent y alias son puestos en una misma estructura para poder ser enviados a la cola de recepción de eventos provenientes de una rutina de interrupción. 37 Esta estructura es recibida en un cola tipo buzón por la tarea vAdaptor, que hace parte del administrador local. Figura 14. ISR_BESA_EVENT, Estructura en la que se almacena un BESA_EVENT cuando quiere ser enviado desde una rutina de interrupción. Una vez ha recibido este evento, La tarea vAdaptor se encarga de traducir el envío de un evento desde una rutina de interrupción a un envío desde una tarea tal como si fuera un envío desde un comportamiento usando la función SendEvent (ver Figura 15). Esta estrategia brinda robustez a la generación de eventos y brinda al programador una utilidad que le facilita el desarrollo de aplicaciones sobre BESA-ME. Figura 15. Diagrama de bloques del tratamiento de eventos desde una rutina de interrupción. El pseudo código del código implementado se presenta a continuación. void vAdaptor(void * pvParameters) { Creación de la estructura del tipo stEventFromISR; Creacion del contador i; for(;;) { while(no llegue un evento a la cola xQueueRxFromISR, se espera máximo un tiempo portMAX_DELAY){} inicialización del contador i en cero; while( el contador i sea menor a NUM_OF_ITERATIONS_IN_SEND_EVENT_FROM_ISR) { se envía el evento al alias, según el tipo de evento definido por el usuario if( envío exitoso) { el contador i se iguala a NUM_OF_ITERATIONS_IN_SEND_EVENT_FROM_ISR para se que finalicen las iteraciones; } se incrementa el contador i en una unidad; } } } 38 Comunicación entre Agentes Existen dos clases de comunicación entre agentes; la primera de estas es la transmisión que se realiza entre entidades que se encuentran en el mismo contenedor. La segunda clase es la que se presenta cuando los agentes que intervienen en la comunicación se encuentran en distintos contenedores. Sin embargo, para el usuario, la función que debe escribir cuando desea enviar un evento a un agente local o externo es la misma. Comunicación entre Agentes del Mismo Contenedor Cuando un comportamiento es activado por la recepción de un mensaje en la cola de un comportamiento, éste puede desatar una serie de invocaciones a sus funciones asociadas. Algunas de esas funciones podrán generar envíos a otros agentes. Si el agente al que se le desea enviar pertenece al mismo contenedor (búsqueda en las páginas blancas), se realizará simplemente un envío a la cola de recepción del canal de dicho agente. Cuando este comportamiento no puede realizar un envió exitoso, esta función retorna un valor determinado según la causa del fracaso. El remitente determinará entonces la acción más adecuada para esta situación. Los posibles valores retornados por la función SendEvent en el caso de un envío local son: 1 Send_ok -7 Queue Full: Significa que no se ha podido depositar el evento en la cola de recepción del canal del agente. Puede ser a causa de que se ha configurado mal el tamaño de dicha cola para la velocidad y cantidad de eventos generados. -8 Agent No Exist: El agente ha sido identificado como un agente local pero no se ha encontrado su cola de recepción de eventos. Puede deberse a una mala configuración del tamaño del stack del canal o de los comportamientos (ver Manual del programador en el anexo A). -9 Container No Exist: El agente no pertenece a ningún contenedor. Comunicación entre Agentes de Distintos Contenedores Inicialmente se identificaron los requerimientos básicos que se deben cumplir, según lo determina la arquitectura BESA, en la comunicación entre agentes pertenecientes a distintos contenedores. Dichas requerimientos se presentan a continuación: o Cualquiera de los contenedores podrá enviar mensajes en cualquier momento. o El número de contenedores del sistema debe poder crecer fácilmente. (criterio de escalabilidad). o Todos los contenedores deben tener la misma prioridad para el envío y recepción de mensajes. 39 Esta clase de comunicación se implementó de tal forma que para el usuario es transparente el envío de un evento BESA a un agente local o a un agente externo. La plataforma BESA-ME, al determinar que el agente se encuentra en un contenedor externo, se encarga de hacer llegar los datos al agente correspondiente e informarle al usuario si la comunicación fue exitosa o el tipo de error que ha ocurrido en la comunicación. Los posibles valores retornados por la función SendEvent en el caso de un envío externo son examinados en la sección 3.4, donde se encuentra una descripción detallada de los procedimientos implicados en este tipo de comunicación. Además, fue necesario modificar el archivo tasks.c propio de freeRTOSTM, que contiene una tarea que se ejecuta cuando el programa arranca (IdleTask), aquí se incluyó una configuración extra para que la plataforma BESA-ME pudiera realizar la comunicación entre microcontroladores. Es aquí donde se crea el modulo de configuración de la comunicación externa sólo cuando la aplicación del usuario requiera de varios microcontroladores (ver anexos A y C). 3.4. Protocolo de Comunicación Externa Teniendo presentes los 3 criterios planteados por el modelo BESA para la comunicación entre contenedores, se estudiaron los protocolos de comunicación (Nivel Byte) disponibles en la familia de microcontroladores seleccionada. Luego se desarrolló un esquema de mensaje apropiado para lograr una comunicación segura (Nivel Trama), que cuenta con una verificación de errores y permite transparencia al remitente sobre si el envío que hace es local o externo, pero en el caso de ser externo, le informa de los errores asociados a este tipo de comunicación. 3.4.1. Protocolo de Comunicación a Nivel Byte En este nivel de la comunicación se controla el direccionamiento de los microcontroladores, el flujo de datos byte por byte, y las señales necesarias para realizar el arbitramiento del bus de comunicación, que será accedido por varios microcontroladores. Selección del Protocolo de Comunicación a Nivel Byte A nivel byte se presentan las siguientes necesidades, producto de los requerimientos del modelo BESA: o Direccionamiento de los microcontroladores (Contenedores). o Arbitramento del bus de comunicación. o Comunicación bi-direccional. o Igual prioridad en el uso del bus de comunicación. 40 Los microcontroladores Microchip de la familia 18f ofrecen dos módulos de comunicación, estos son la USART y el MSSP. significativas para este El módulo MSSP, frente a la USART presenta algunas ventajas contexto; el primero permite mayor control por Hardware, proporcionando registros específicos y múltiples causas de interrupción diseñadas para este propósito, que permiten realizar acciones como el direccionamiento de los dispositivos, el arbitramento del bus, y el estado de la comunicación, haciendo más sencillo el software de control a este nivel y en consecuencia permitiendo mayor velocidad en la comunicación. El módulo USART a diferencia del MSSP, no permite detectar por Hardware eventos ligados a la transferencia de datos, como lo es determinar si el bus está ocupado o libre para transmitir, si el byte recibido es un dato o una dirección, el inicio y el final de una trama de bytes, si la transmisión está en proceso, etc. Otra característica del módulo MSSP es que soporta la comunicación bi-direccional y sincrónica, por lo cual solo necesita dos alambres de comunicación, uno para datos y otro para la señal de reloj. Al ser sincrónica, no es crítica la configuración en la velocidad de transmisión desde los diferentes dispositivos que se conecten al bus, presentando mayor robustez frente a la comunicación asíncrona. El módulo MSSP de los microcontroladores Microchip ofrece el modo SPI e I2C (Inter-Integrated Circuit). SPI aunque de fácil implementación, no presenta homogeneidad en la asignación de prioridades, ya que permite el manejo de un sólo maestro, dejando al resto de dispositivos como esclavos. Además, para cumplir con el criterio de escalabilidad, se hace necesario el aumento de pines de salida, mientras que I2C utiliza tan sólo dos señales para manejar hasta 128 dispositivos, los cuales pueden ser maestros o esclavos según la necesidad de envío 23 . De esta forma también se cumple con el criterio de homogeneidad de prioridades de los contenedores, cumpliendo así con los requerimientos de BESA, razones de peso para adoptar el protocolo I2C. Introducción al Funcionamiento del Protocolo I2C El protocolo utiliza dos señales para implementar la comunicación, estos son SDA (Datos) y SCL (Reloj); cada una implica un alambre de comunicación diferente. I2C plantea dos estados para poder llevar acabo toda comunicación, un dispositivo debe estar configurado como Master (Transmisor) y el otro como Slave (Receptor). En la transmisión, el protocolo requiere de una serie de secuencias para que la transferencia de datos se pueda realizar correctamente. Antes de iniciar la transmisión, es necesario verificar el estado del bus. Si el bus está libre, se inicia la comunicación con una señal START, colocando en seguida en el bus la dirección del dispositivo al cual se le enviará el mensaje; el receptor 23 MICROCHIP, Inter-Integrated Circuit™ (I2C™). Microchip Technology Inc 2004. 41 correspondiente envía una señal de contestación indicando que está listo para recibir datos. El transmisor coloca el dato (un byte) en el bus, seguido de la confirmación del receptor. Esta contestación es generada automáticamente por el modulo MSSP del microcontrolador, y puede ser negativa por dos razones: si la dirección no existe en el sistema o si el bus I2C fue desconectado durante la comunicación, razones por las cuales se debe finalizar la transferencia de datos. Si la contestación es afirmativa, se continúa con la comunicación hasta que el transmisor genere una señal STOP. Esta última le indica al receptor que ya no debe esperar más datos, de tal forma que el bus es liberado para que otros microcontroladores puedan comunicarse. Las señales START, STOP y Contestación negativa pueden observarse en la Figura 18. I2C permite la transmisión y recepción de datos según lo requiera el dispositivo maestro. El tipo de comunicación (lectura o escritura) que se llevará a cabo está dado por el último bit del byte de dirección colocada en el bus inicialmente (1 = lectura; 0 = escritura). BESA-ME declara a todos los contenedores del sistema inicialmente como esclavos. Cuando algún esclavo quiere comunicarse con otro, el microcontrolador se establece como maestro para luego poner en el bus la dirección del microcontrolador al cual desea enviar datos y espera la señal de confirmación. Existirá entonces sólo un maestro en el sistema a la vez. El dispositivo que se encuentre como maestro sólo puede escribir en los esclavos, lo que indica que en BESA-ME nunca deberá ser declarada una dirección (CONTAINER_ID) en la cual el ultimó bit sea un 1, debido a que se presentarían errores en la comunicación entre contenedores. Las interrupciones generadas por las señales puestas en el bus, son escuchadas por todos los dispositivos conectados a éste, pero únicamente el contenedor cuya dirección recibida coincide con su CONTAINER_ID, es el que realiza el tratamiento adecuado para recibir los datos. Al producirse un evento que genere una interrupción (una señal de START, STOP, bit de Confirmación o buffer de recepción lleno), la bandera de interrupción es activada (automáticamente por el modulo MSSP) de tal forma que en la rutina de interrupción propia de BESA-ME se ejecuta el procedimiento adecuado, y se continúa con la espera de otro suceso relevante. En la comunicación por I2C, cada uno de los bytes enviados es puesto en el bus tras una rutina de interrupción. Luego de que un byte es puesto en el bus, se abandona la interrupción, liberando el control del procesador durante el tiempo de envío de cada uno de estos datos, ya que la velocidad de transmisión es aproximadamente 100 Khz, pequeña en comparación con la velocidad de oscilación del reloj del microcontrolador; permitiendo de esta forma que otros procesos puedan ser ejecutados durante esos periodos. 42 Implementación del Protocolo de Comunicación a Nivel Byte Para maximizar el uso de la CPU del microcontrolador durante la transmisión de datos a otro microcontrolador se implementó el uso y control del protocolo I2C usando las herramientas de interrupción que ofrece el módulo MSSP. Para iniciar el envío de un byte a otro contenedor, es necesario realizar antes el arbitramento del bus para verificar que esté libre y no haya error en la comunicación. Una vez haya sido tomado el bus, se debe configurar el modulo como Master e inicializar ciertas variables utilizadas en la transmisión. Todo lo esto se realiza la función SendEventI2C(), cuyo pseudo código se muestra a continuación. char SendEventI2C(unsigned char NumDataToSend) { Deshabilita Interrupciones Globales y del modulo I2C; if( El bus está libre) { Cantidad de datos por enviar = NumDataToSend + 4; Apuntador al buffer de Tx del Container = Primera posición del buffer de Tx del Container; Se configura el modulo I2C como Transmisor (Master); Se inicia la condición de start en el bus; Habilita Interrupciones Globales y del modulo I2C; Se retorna un cero; } else { Habilita Interrupciones Globales y del modulo I2C; Retorna que no se pudo tomar el bus (BUS_COLLITION); } } Cuando se transmite un byte, los posibles errores que pueden ser retornados al remitente del evento BESA, son los siguientes: o BUS_COLLITION: El bus no está libre para iniciar la transmisión. Una vez el bus ha sido ocupado, no puede ser tomado por otro micro-controlador hasta que se genere una señal de STOP por el dispositivo que estaba realizando la transmisión. o NO_ACK_HARDWARE: Al finalizar la transmisión de un byte, este no ha sido recibido por el microcontrolador destinatario. Las posibles causas de este error son: El microcontrolador receptor no tiene capacidad física de recibir (desconectado del bus o apagado) o ningún microcontrolador responde a la dirección transmitida, que en el contexto de BESA-ME es el CONTAINER_ID. Cuando esto sucede, el Administrador local del microcontrolador remitente genera una señal de STOP en la transmisión, 43 con lo cual libera el bus para que pueda ser usado por otro microcontrolador. En el microcontrolador destinatario se reiniciará la recepción y se pondrán los datos en las posiciones de memoria adecuadas cuando se reciba una señal de START. Una vez el bus de comunicación haya sido tomado, desde el microcontrolador remitente se genera una señal START que es detectada por el módulo MSSP de los microcontroladores conectados al bus. Inmediatamente después de la señal START, el remitente envía la dirección del microcontrolador destinatario (7 bits). Si están configurados adecuadamente, los módulos MSSP que detectaron la señal START compararán la dirección recibida con la dirección interna (CONTAINER_ID) que esta cargada en un registro para tal propósito. La comparación se hace automáticamente por hardware y no necesita control adicional por software. Cuando en alguno de los microcontroladores la comparación ha coincidido entonces su módulo MSSP genera una señal eléctrica que aquí llamamos Acknowledge Hardware. Una vez esta señal de Acknowledge Hardware es detectada por el transmisor, se inicia el envío de los bytes de información que conforman la trama de datos. El pseudo código que se muestra a continuación corresponde a la rutina de interrupción implementada para integrar la comunicación a nivel byte y la comunicación a nivel trama. void i2cISR(void) { Se limpia la bandera de interrupción del módulo I2C; If ( El modulo esta en modo TRANSMISOR (Master) ) { ******** ESTA EN MODO TRANSMISOR *********** if ( La interrupción fue a causa de un STOP ) { Pasa a modo Receptor (Slave); Libera el semáforo de protección del buffer (SemBuffer); } else { if (Hubo Acknowledge de Hardware para el último byte transmitido) { if (Cantidad de datos por enviar>0 ) { Buffer Módulo I2C = Lo apuntado por el apuntador al buffer de Transmisión del Container; Se disminuye en uno la Cantidad de datos por enviar; Se incrementa el Apuntador al Buffer de Transmisión del Container en uno; } else { Cantidad de datos por enviar = 0; Se genera una señal de STOP en la transmisión; Se espera a que se termine de transmitir el STOP; 44 Limpia la bandera de interrupción del módulo I2C; Pasa al modo Receptor (Slave); Se libera el semáforo de protección del buffer (SemBuffer); } } else { Cantidad de datos por enviar = 0; Limpia la bandera de No Ack_Hardware para el último byte transmitido; Se genera un STOP en la transmisión; Se espera a que se termine de transmitir el STOP; Limpia bandera de interrupción del módulo I2C; If( Se estaba transmitiendo una trama EventBESA y no una AckBESA ) { Informa a la tarea que transmitió que no hubo Acknowledge; } Pasa a modo Receptor (Slave); Libera el semáforo de protección del buffer (SemBuffer); } } } else // **** ESTA EN MODO RECEPTOR *********** { Activa el modo Clock Stretching; (asegura no recibir más datos hasta que no se lea el buffer del modulo I2C donde se guarda el dato recibido) if (La interrupción fue a causa de un STOP ) { Limpia la bandera de over flow; Envía a la tarea vSend_ack una copia del buffer de Recepción del container; } else { if( La interrupción fue a causa de que el buffer de Rx del modulo I2C está lleno) { if( El último dato recibido fue una dirección ) { Apuntador al buffer de Rx del Container = Primera posición del buffer de Rx del Container; Posición apuntada por Apuntador al buffer de Rx del Container = buffer de Rx del módulo I2C; Se incrementa en uno el Apuntador al Buffer de Recepción; } else { Posición apuntada por Apuntador al buffer de Rx del Container = buffer de Rx del módulo I2C; Se incrementa en uno el Apuntador al Buffer de Recepción; } } else { Limpia la bandera de over flow; 45 } } Libera el bus para recibir más bytes (Deshabilita Clock Stretching); } Habilita las interrupciones del módulo I2C; } Cada una de las acciones propias de I2C se implementó usando funciones, de tal forma que la adopción de otro tipo de protocolo implicará sólo cambios internos en dichas funciones, sin entrar a reparar el esquema de tratamiento a nivel trama. 3.4.2. Protocolo de Comunicación a Nivel Trama Se diseñaron dos tramas de comunicación, una para el envío de eventos BESA y otra para el envío de mensajes de confirmación BESA (Acknowledge BESA). Al transmitir las dos tramas, sólo se envía los bytes que contienen información útil para el sistema. El tamaño máximo de trama de eventos BESA corresponde al tamaño de la estructura stBufferBESA (ver Figura 11). Sin embargo, este tamaño varía según la configuración de BESA-ME, en función del número de bytes de los eventos BESA creados por el usuario (ver Manual del Usuario, Anexo A). En la Figura 16 se observan una representación gráfica de los dos tipos de tramas BESA utilizadas en la comunicación entre contenedores. Figura 16. Formato de tramas utilizadas para la comunicación entre Contenedores. Trama Evento BESA En la Tabla 2 se encuentra la descripción de cada byte de la trama EventBESA. Las celdas sombreadas corresponden a los bytes que conforman el Evento BESA, tal como se usa en los envíos locales (ver Figura 13). El campo Cantidad de Datos (Data Size) de la trama, contiene el número de bytes N que comprenden el Evento BESA, es correspondientes al campo Event Type, Data Size y Data BESA. decir, incluye los bytes Para los diferentes tipos de eventos, el tamaño de los datos puede diferir del máximo MAZ_DATA_SIZE definido para el sistema (ver figura 12), por lo que únicamente se envían los bytes que son utilizados por el tipo 46 de evento en particular, haciendo variable la longitud de la trama EventBESA y más eficiente el uso del bus de comunicaciones. Posición del byte Nombre del byte Descripción 1 Container ID Rx Es el byte que será comparado con el registro SSPADD del receptor que se encuentra en modo esclavo. Byte de Dirección para el protocolo I2C. 2 Alias Usado por el administrador local para hacer llegar el evento BESA al agente. 3 Container ID Tx Se almacena para enviar el Ack BESA al contenedor adecuado, una vez el evento BESA haya sido enviado al agente destinatario. 4 Event Type 5 Data Size Número de bytes ( N ) que componen el Evento BESA. 6 Data BESA… Los Bytes en los que se encuentra la información del usuario. … N+4 Tipo de Evento transmitido …. Check sum Byte calculado realizando la operación XOR entre todos los bytes de la trama anteriores al Check sum. Usado para control de errores en la transmisión. Tabla 2. Descripción de los bytes de la trama Event BESA para un Data Size de tamaño N. Trama Acknowledge BESA El tamaño de la trama AckBESA es constante para todos los casos. En la Tabla 3 se encuentra la descripción de cada byte de la trama AckBESA. Como se observa en esta tabla, el byte Ack (que luego será retornado por la función SendEvent al remitente), puede tener los mismos valores que retorna la función SendEvent en el caso de un envío local, y adicionalmente, el valor correspondiente a un error de check sum. Esto se debe a que se recibe una trama de AckBESA sólo cuando el contenedor destinatario recibió la Trama EventBESA y su administrador local intentó realizar el envío en su contenedor. Cuando la trama EventBESA no puede ser enviada al destinatario, la función SendEvent retornará al remitente un Ack local, con otros valores correspondientes a otros tipos de error, los cuales se explican en la Secuencia de Comunicación. 47 Posición del byte Nombre del byte 1 Container ID Rx Es el byte que será comparado con el registro SSPADD del receptor que se encuentra en modo esclavo. Byte de Addres para el protocolo IIC. 0x00H Este campo corresponde al alias del Buffer de recepción del contenedor. El valor 0x00H esta reservado para identificar cuando la trama corresponde a un Ack BESA. 2 Descripción 3 Ack Resultado de la transmisión. siguientes valores: 1 Send_ok -5 Chk sum bad -7 Queue Full -8 Agent No Exist -9 Container No Exist 4 Check sum Check sum para verificación transferencia de los datos. Puede de tener la los correcta Tabla 3. Descripción de los bytes de la trama Ack BESA. Constante para cualquier tamaño de datos. Secuencia de Comunicación del Protocolo a Nivel Trama Transmisión de las Tramas El primer byte que se transmite corresponde al ID del container con el cual se desea establecer comunicación. Cuando una confirmación ack hardware indica que la dirección existe y que dicho contenedor está listo para recibir, se continúa entonces con el envío de los datos como lo muestra la trama del mensaje de datos (Ver figura 16). El contenedor transmisor envía entonces el Alias del agente al que está dirigido el mensaje, seguido de la identificación del contenedor transmisor, al cual se le deberá responder cuando el mensaje haya llegado al agente destinatario. Cabe anotar que cuando el bit Ack no es recibido en cualquier momento de la comunicación, la trama no se termina de enviar, y se genera la instrucción STOP, propia de I2C. A continuación se tiene el tipo de evento (xEventType) de los datos que se envían, seguidos del número de datos N que se deben esperar. En esta cantidad se incluye el byte de tipo de evento y el byte usado por la cantidad de datos, pero no está incluido el de seguridad de información (check sum). Este último se calcula con la función lógica XOR de los primero N+3 bytes de la trama. Si suponemos que se desea enviar un sólo byte como dato, tendríamos entonces en cantidad de datos N=3, correspondientes a tipo de evento, cantidad de datos y un byte del dato; completando un tamaño total de trama de 6 bytes (N+3) de información del sistema más 1 byte de check sum. Recordemos que cada uno de los bytes está seguido automáticamente del bit de ack hardware generado por el contendor esclavo. 48 Envío en Condiciones Normales de una Trama EventBESA Figura 17. Tipos de respuesta acknowledge en BESA-ME. Ejemplo del envío de un agente X a un agente Z ubicados en distintos contenedores. En la figura 17 se representa de manera general la secuencia normal de comunicación entre agentes de distintos contenedores. El envío exitoso de un evento BESA a un agente que se encuentra en un contenedor externo comprende los siguientes pasos: 1. Ejecución de la función SendEvent 2. Se revisa el directorio de páginas blancas. 3. Se determina si el agente habita en el contenedor. 4. Si no, se revisa que exista en algún contenedor. A partir de aquí inicia el envío externo… 5. Se obtiene el Container ID del contenedor receptor en el cual existe el agente, y se toma el semáforo de protección de envío de eventos (SemSend). 6. Si se pudo tomar el semáforo SemSend, entonces se toma el semáforo de protección del Buffer de transmisión (SemBuffer). 7. Una vez tomado SemBuffer, se llena el Buffer de transmisión con la información correspondiente a la Trama Event BESA que se desea transmitir. 8. Se realiza el arbitramento del bus I2C para determinar si se puede tomar el bus. 9. Una vez se toma el bus, se pone el módulo de comunicación en modo Master y se genera la secuencia de Start que da inicio a la comunicación. 10. Cuando se termina de transmitir el último byte de la Trama EventBESA, se genera una señal de STOP en I2C y se libera el semáforo de protección del SemBuffer. 49 11. El comportamiento que generó el envío permanece bloqueado hasta que se reciba un ack en la cola de recepción de ack. 12. Llega una trama nueva de datos por el bus I2C al contenedor transmisor. 13. Se revisa que sea de tipo AckBESA verificando el byte 2 que ha llegado en la trama. 14. Se revisa que se esté esperando un AckBESA, verificando que el semáforo SemSend no ha sido liberado. 15. Si se está esperando el AckBESA, el byte de Ack recibido dentro de la trama es enviado a la cola de recepción de ack, que permite desbloquear el comportamiento remitente de la trama EventBESA. 16. El comportamiento remitente libera el semáforo SemSend. 17. Se retorna al remitente (quien hizo un llamado a la función SendEvent) el valor del Ack recibido. El comportamiento que envió inicialmente el mensaje se encuentra bloqueado hasta que la confirmación BESA sea recibida. El campo Ack en 0x01 (hexagesimal) indica que el evento enviado fue recibido exitosamente por el agente destino. De no ser así, el campo Ack variará con valores negativos según la causa del error permitiendo que el remitente decida cual es el procedimiento a seguir. Gestión de Errores en el Envío de una Trama EventBESA Dentro de los pasos anteriores, ejecutados para realizar el envío externo de un evento BESA, se pueden presentar errores por diversas causas. A continuación se muestra cual tipo de error se retorna y en qué pasos del protocolo pueden ocurrir. 1. Ejecución de la función SendEvent 2. Se revisa el directorio de páginas blancas. 3. Se determina si el agente habita en el contenedor. 4. Si no, se revisa que exista en algún contenedor. A partir de aquí inicia el envío externo… 5. Se obtiene el Container ID del contenedor receptor en el cual existe el agente, y se toma el semáforo de protección de envío de eventos (SemSend). Error: Si no se puede tomar el Semáforo inmediatamente, el comportamiento que invocó la función SendEvent se bloquea durante el tiempo máximo que puede transcurrir entre el instante en que un comportamiento tome este semáforo y el instante en que lo libera al recibir una trama AckBESA. 50 Si transcurrido este tiempo, el comportamiento que había tomado el semáforo no lo ha liberado, entonces se libera de manera obligada y se retorna al remitente el error TIME_OUT_SEND (-2). Se sugiere que este tiempo de espera sea medido bajo condiciones controladas de comunicación entre dos contenedores, tal como se muestra en la Figura 19, multiplicando por un factor de error de 1.5, con el cual se contempla el tiempo transcurrido entre el momento en que se toma el SemSend y el momento de la transmisión del primer byte de la trama, así como el tiempo transcurrido entre la llegada del último byte de la Trama AckBESA y el instante en que se libera el SemSend, los cuales no pueden ser medidos con las señales del bus I2C. 6. Si se pudo tomar el semáforo SemSend, entonces se toma el semáforo de protección del Buffer de transmisión (SemBuffer). Error: Si no se puede tomar el Semáforo SemBuffer inmediatamente, el comportamiento que invocó la función SendEvent se bloquea durante el tiempo máximo que puede transcurrir entre el instante en que un comportamiento toma este semáforo y el instante en que lo libera, lo cual sucede al transmitir el último byte de una trama de datos y generar una secuencia de Stop de I2C. En la figura 19 se puede ver a manera de ejemplo como calcularlo fácilmente. Si transcurrido este tiempo el comportamiento o servicio que lo había tomado no ha liberado el semáforo, entonces se libera de manera obligada y se retorna al remitente el error TIME_OUT_BUFFER (-3). 7. Una vez tomado SemBuffer, se llena el Buffer de transmisión con la información correspondiente a la Trama Event BESA que se desea transmitir. 8. Se realiza el arbitramento del bus I2C para determinar si se puede tomar el bus. Error: Cuando hay colisión en la toma el bus de comunicación debido a que otro contenedor no ha finalizado el envío de una trama de datos entonces se retorna al remitente el error BUS_COLLITION (-6). El usuario puede establecer en un archivo de configuración (ver anexo A) el número de veces que debe intentar el sistema el envío del evento cuando se obtiene este error. 9. Una vez se pudo tomar el bus, se pone el módulo de comunicación en modo Master y se genera la secuencia de StART de I2C que da inicio a la comunicación. 51 Error: Si en cualquier momento de la comunicación el microcontrolador receptor no puede recibir algún byte retornará una señal de no Ack de hardware. Esto puede deberse por ejemplo, a desconexión física, desconfiguración, o a que se encuentra en una región crítica en la que no pudo vaciar los registros de recepción del modulo MSSP. Cuando ningún dispositivo está identificado con el CONTAINER_ID correspondiente al primer byte transmitido entonces también se recibe este tipo de error. La comunicación es interrumpida automáticamente por el microcontrolador Maestro generando una secuencia de Stop de I2C, tal como se muestra en la Figura 18. Se retorna al remitente el error NO_ACK_HARDWARE (-4). Al igual que en el caso anterior, el usuario determina la cantidad de veces que se intenta enviar el evento al producirse este error. El número de intentos es igual para ambos casos. 10. Cuando se termina de transmitir el último byte de la Trama EventBESA, se genera una señal de STOP en I2C y se libera el semáforo de protección del SemBuffer. 11. El comportamiento que generó el envío permanece bloqueado hasta que se reciba un ack en la cola de recepción de ack. Error: Si transcurrido el tiempo máximo de espera de un AckBESA este no llega, entonces se detiene la espera, se desbloquea el comportamiento remitente y se libera el semáforo SemSend. Se retorna al remitente el error TIME_OUT_ACK (-1). Las variables intervinientes en el cálculo de este tiempo son la velocidad de CPU de cada microcontrolador, el tamaño de la trama de datos y la velocidad del reloj de transmisión. Se sugiere que sea medido bajo condiciones controladas de comunicación entre dos contenedores, tal como se muestra en la Figura 19, multiplicando por un factor de error de 1.2, con el cual se contempla el tiempo transcurrido entre el momento en que se envía la Trama EventBESA y el instante en que se recibe el byte ack en el comportamiento que se encuentra bloqueado, después de recibida la trama AckBESA. 12. Llega una trama nueva de datos por el bus I2C al contenedor transmisor. 13. Se revisa que sea de tipo AckBESA verificando el byte 2 que ha llegado en la trama. 52 14. Se revisa que se esté esperando un AckBESA, verificando que el semáforo SemSend no ha sido liberado. Error: Si el semáforo esta libre, quiere decir que ningún comportamiento está bloqueado esperando un AckBESA, por lo cual se descarta este mensaje. En este caso puede ser que el destinatario se haya demorado un tiempo mayor al TIME_OUT_ACK, por lo cual este último debe ser revisado. 15. Si se está esperando el AckBESA, el byte de Ack recibido dentro de la trama es enviado a la cola de recepción de ack, que permite desbloquear el comportamiento remitente de la trama EventBESA. 16. El comportamiento remitente libera el semáforo SemSend. 17. Se retorna al remitente (quien hizo un llamado a la función SendEvent) el valor del Ack recibido. Error: Si el ack recibido es igual a CHK_SUM_BAD, antes de retornar el valor recibido al comportamiento remitente, se reintenta el envío el mismo número de veces que para los errores de bus_collition y no_ack_hardware de los Pasos 8 y 9. Este tipo de error se puede producir si los datos originales sufren alguna alteración durante la secuencia de transmisión o recepción. La comunicación fue implementada intentando reducir al máximo los errores asociados al hardware. Por esto, para este tipo de errores el usuario tiene la oportunidad de decidir el número de veces que la plataforma debe reintentar un envío al producirse el error, como se explicó en los pasos 8, 9 y 17. Para los errores producidos a nivel de sistema BESA, el usuario tiene también la posibilidad de decidir la acción a seguir una vez se ha recibido el ack informando el resultado de la comunicación. Cuando se presenta un error en la dirección del dispositivo esclavo, o un error de conexión física entre los dispositivos conectados al bus I2C, se obtiene la señal de la Figura 18. En esta figura la señal de arriba corresponde a la dirección del esclavo incluyendo el noveno bit en alto que significa “No Acknowledge Hardware”. La señal de abajo es el reloj de sincronización @ 100 Khz. Ambas señales son generadas por el dispositivo configurado como maestro en el momento de la transmisión. 53 Dirección generada por el transmisor Bit de No Acknowledge Hardware generado por el receptor t4 t1 START STOP t2 t3 Señal de reloj generada por el receptor. Trama AckBESA Figura 18. Señales START, no Acknowledge Hardware y STOP. En la figura 18 se pueden observar claramente los eventos START y STOP generadas por el modulo I2C. El microcontrolador reconoce que ocurrió un START cuando la señal SDA baja a cero antes de que lo haga la señal SCL. Un STOP se reconoce cuando la señal SCL sube a uno y en seguida lo hace también la señal SDA. Como se dijo antes, el dispositivo identifica automáticamente estos eventos por Hardware. En la figura 19, se puede observar en la parte superior izquierda la trama EventBESA y a la derecha la respuesta en la trama AckBESA. Bajo las condiciones específicas de la prueba, el valor mínimo que deberían tener los tiempos de espera antes de generarse los errores de TIME_OUT_SEND y TIME_OUT_ACK, (sin multiplicar por el factor a tener en cuenta en cada uno) es de aproximadamente 7.2 ms. La señal superior corresponde a los datos y la inferior a la señal de reloj. Reloj de transmisión @ 100 KHz. Reloj CPU Microcontrolador transmisor @ 20 MHz. Reloj CPU Microcontrolador receptor @ 25 MHz. A partir de la figura 19, se puede entender con mayor claridad el comportamiento de las señales en el bus de comunicación. El contenedor que transmite en un momento dado (configurado como Master), es el que genera también la señal de sincronismo SCL. Los tiempos indicados en la figura, muestran a manera de ejemplo algunos de los tiempo y eventos que se producen durante en la comunicación por I2C: 54 o t1 -> Antes de iniciar la transmisión, se toma SemSend. o t2 y t4 -> Un instante antes de enviar el primer byte se toma SemBuffer. o t3 y t5 -> Un instante después de terminar el envío de la trama se libera SemBuffer. o Tiempo de respuesta de Ack = T2. t3 t1 t4 t2 T1 T2 t5 Señal de datos (SDA) Señal generada por el transmisor. Trama EventBESA Señal generada por el receptor. Trama AckBESA Señal de Reloj (SCL) Figura 19. Señales presentes durante la comunicación exitosa desde un contenedor hacia otro contenedor. Tamaño máximo de Datos igual a 6. DataSize igual a 8. Entre los tiempos t2 - t3 y t4 - t5 se toma y se libera el semáforo SemBuffer. El mayor tiempo se obtiene entre t2 y t3, que es el tiempo que debe esperarse para producir el error de TIME_OUT_BUFFER. El tiempo debe medirse al transmitir el tamaño máximo de datos posible para tener en cuenta el peor caso. Par establecer el tiempo TIME_OUT_SEND en que debe liberarse el semáforo SemSend, es necesario obtener el tiempo T1 que se muestra en la figura 19. Este tiempo se mide a partir de que comienza la transmisión del primer byte por el bus, hasta que se transmite el último byte de la trama AckBESA por parte del receptor; se debe multiplicar por 1,5 para tener en cuenta el tiempo de procesamiento que se realiza antes y después de la transmisión y recepción. o Tiempo de bloqueo de SemSend = T1 x 1,5. Para establecer el tiempo TIME_OUT_ACK en que debe liberarse el semáforo SemSend al no recibirse una confirmación (Acknowledge), se debe tomar el mismo tiempo T1; debe multiplicarse por 1,2 para tener en cuenta también el tiempo de procesamiento asociado a la 55 comunicación. Sin embargo, el factor de escalamiento es menor que en el caso anterior, ya que el comportamiento remitente se bloquea después de transmitir la señal de START de I2C. o Tiempo máximo de espera de AckBESA = T1 x 1,2. La velocidad escogida para la transmisión por el bus I2C fue de 100 Khz como se observa en las figuras 18 y 19. Aunque es posible según los estándares del protocolo transmitir a frecuencias mayores (400 Khz y 1Mhz), los errores de los diferentes tipos mencionados anteriormente, y en especial de “NO_ACK_HARDWARE” y “BUS_COLLITION” presentados en estas velocidades durante las pruebas de comunicación, fueron bastante superiores a cuando se transmitió con velocidad de reloj igual a 100 Khz. Recepción de las Tramas de Datos La tarea vSendAck, que hace parte del Administrador Local, es la encargada de leer y filtrar la información del buffer de recepción del contenedor cada vez que llega una trama de datos. La información del buffer de recepción es enviada desde la rutina de interrupción de recepción cuando se termina de recibir una trama, y es recibida por la tarea vSendAck (Figura 20), por copia, en la cola creada para tal propósito. Figura 20. Envío y recepción de eventos al bus I2C por medio de interrupciones. 56 Una vez se ha recibido se filtra su información para, si se recibió un AckBESA, realizar los pasos 14 y 15 descritos anteriormente, pero si se recibió una trama EventBESA realizar los pasos siguientes: 1. Se calcula el check sum sobre la trama recibida y se realiza la comparación con el valor de check sum recibido. 2. Si la comparación muestra error en los datos, se salta al paso 6. Si el chk_sum es correcto se procede a hacer un envío local al agente indicado por el byte alias. Al agente alias se le envía la sección EventBESA de la trama recibida. 3. Se ejecuta la función SendEvent que originará un envío local. 4. Se guarda el ack retornado por la función SendEvent 5. Se toma el semáforo SemBuffer 6. Se llena el buffer de transmisión del contenedor con la trama de AckBESA obtenida a partir del ack resultante del envío local del paso 3 o con el ack CHK_SUM_BAD, obtenido en el caso de error en el paso 2. 7. Se toma el bus I2C. 8. Se inicia la comunicación generando la rutina de Start en el bus I2C. 9. Cuando la rutina de interrupción termina la transmisión, libera el semáforo SemBuffer. A continuación se presenta el pseudo código de la tarea vSendAck: void vSend_Ack(void * pvParameters) { Creacion de la estructura tipo stBufferBESA y su respectivo apuntador; Creación de las variables necesarias; for(;;) { while(no llegue un evento a la cola xQueueRxFromISR, se espera el máximo tiempo posible (portMAX_DELAY)){} if( la trama recibida es una trama ackBESA ) { if( se estaba esperando una trama ackBESA ) { se envía la trama a la cola xQueueRxAck para desbloquear al comportamiento que estaba esperando el ackBESA; } else { se libera el semáforo xSemaphoreSendProtection; } } else { Se inicializa la variable check_sum en cero; Se apunta pBuffer_rx a la primera posición de la estructura que acaba de llegar Se calcula el check_sum; if( el check_sum calculado no es igual al recibido ) { en el campo de ack de la trama AckBESA se coloca la causa de recepción corrupta de datos; 57 } else { se realiza un envío de los datos recibidos al agente interno correspondiente, y si el envió es exitoso en el campo correspondiente de la trama AckBESA se coloca recepción exitosa; } Luego de tener lista la trama AckBESA para enviar, se intenta tomar el semáforo xSemaphoreBufferProtection solamente 3 veces, cada una de estas durante un tiempo de espera igual a X_BLOCK_TIME_SEMAPHORE_BUFFER if( se pudo tomar el semáforo xSemaphoreBufferProtection? ) { Se arma toda la trama AckBESA para ser enviada al agente que realizó el envió; if( el bus está ocupado) { El sistema espera la liberación del bus I2C un tiempo igual a X_BLOCK_TIME_WAITING_FOR_BUS_I2C; if( el bus ya fue liberado?) { Se realiza el envío; } else { No se realiza el envió y se libera el semáforo xSemaphoreBufferProtection. Es decisión del programador lo que se realiza en este caso; } } } } } Diagrama de Flujo de la Comunicación entre Agentes en BESA-ME El diagrama de flujo que se muestra en la figura 21 representa los dos esquemas que se llevan acabo para el envió y la recepción de eventos en determinado contenedor. La sección sombreada (derecha) muestra el proceso de recepción externa, mientras que los bloques no sombreados y de colores (izquierda) muestran los pasos que se llevan a cabo en el envió de eventos, tanto internos como externos. Cuando el agente X (amarillo) realiza una transferencia de datos al agente Y (amarillo), la comunicación se ejecuta internamente como los muestra la figura 21 en la parte superior izquierda. La búsqueda de la ubicación del agente destino la realiza el administrador local como se explicó anteriormente. Si el agente X desea enviar un evento a un agente que se encuentra fuera del contenedor (agente Z), la secuencia de sucesos que realiza la plataforma BESA-ME es ahora mas compleja y se hace necesario utilizar los servicios de sincronización (bloques naranjas). Luego de enviar los datos al agente externo, el comportamiento del agente X espera la contestación AckBESA de Z. Cuando dicho suceso ocurre, las interrupciones necesarias se llevan a cabo (bloque azul de la parte inferior derecha) para recibir toda la trama. Una vez completa la recepción, se confirma que la trama sea de tipo AckBESA, de ser así, el comportamiento del agente X, quien generó el evento, finaliza la espera y se desbloquea (si la contestación indica que Z recibió exitosamente). 58 Los pasos realizados por el agente Z, durante la recepción, son los indicados por los bloques sombreados, pero en el microcontrolador donde se encuentra contenido Z. Cuando la trama recibida está completa, se observa que el tipo de mensaje no es AckBESA sino un evento externo, de modo que se realiza lo correspondiente para que dicho evento llegue al agente Z. Una vez recibido, este agente genera la trama AckBESA que se enviará a X. Este envío debe utilizar también los servicios de sincronismo para lograr colocar su trama en el bus I2C, de modo que toma los mismos semáforos propios de los envíos de eventos externos. Para el envío de contestación no se espera respuesta (ovalo verde). 59 Behavior x cQueueReceive cQueueReceive SendEvent El Agente detino es local ? Agente W Agente Y Agente X SI NO Se retorna un valor según el motivo Se recibío el mensaje ? SI Se finaliza la comunicación El mensaje se recibió ? Se realiza un envío local ( cQueueSend ) NO La acción que se realiza depende del usuario Se busca la dirección del contenedor en el que se encuentra el Agente destino Se construye el mensaje de contestación positivo SI Se realiza un envío local ( cQueueSend ) NO NO N intentos ? NO SI Se toma el semáforo de protección de envio externo Fue la confirmación positiva ? Se construye el mensaje de contestación negativo según el motivo SI Se toma el semáforo de proteccion del Buffer para envio externo Desbloquea el comportamiento x Se arma el mensaje en el buffer de transmisión Se construye el mensaje de contestacion negativo por mal check sum Se desencapsula en mensaje Se analiza el contenido y se libera el semaforo de envio externo NO SI N intentos NO Está libre el bus i2c ? SI Llegó la confirmación BESA ? NO SI N intentos El mensaje enviado era de tipo Ack BESA ? Se generan las interrupciones propias de i2c para enviar el mensaje externo en paquetes de 1 byte (SendEventRemoto) NO SI NO Check sum correcto ? El tipo de mensajes es un ack BESA? No se espera contestación y finaliza la comunicación SI Se libera el semáforo de escritura en el Buffer NO SI N intentos Hubo ack negativo de Hardware después del byte anterior ? Se genera interrupción por i2c (entrada de mensaje) BUS I2C Figura 21. Diagrama de flujo de la comunicación entre agentes en BESA-ME. 60 4. PRUEBAS Y ANÁLISIS DE RESULTADOS El objetivo de las pruebas es comprobar el funcionamiento final de la plataforma BESA-ME y establecer los límites y los rangos normales de operación. Se pretende también que el programador pueda contar con un soporte al cual referirse en el momento de crear una aplicación. Para lograr resultados satisfactorios que proporcionen información relevante respecto al desempeño de la plataforma en general, se procedió a establecer un protocolo de pruebas para luego continuar de manera ordenada con la evaluación del sistema y realizar un posterior análisis de los resultados obtenidos. 4.1. Protocolo de Pruebas El primer paso para lograr este objetivo es determinar las variables que intervienen en el sistema, y con base en ellas se deben determinar las pruebas que se van a realizar. 4.1.1. Identificación de Variables Para las pruebas se consideran tres tipos de variables: las variables independientes o de control, las variables dependientes o de medición y las variables intervinientes. Las primeras son aquellas que se varían para crear diferentes situaciones de evaluación, las segundas son las que se miden a la salida de la prueba y las terceras son aquellas variables que están presentes inevitablemente y afectan el resultado de la prueba. Estas últimas se controlan tratando de dejarlas invariantes para que su influencia sea mínima o constante a lo largo de los experimentos. Variables Independientes Tamaño del Stack Cada tarea creada en el sistema tiene asignado un Stack o espacio de memoria donde se guarda la información necesaria para que una vez reestablecida después de un cambio de contexto, pueda seguir ejecutandose con los datos e información correcta. El tamaño del Stack puede ser modificado para cada tarea, y su valor depende del espacio mínimo en memoria requerido para su creación, del tamaño de las variables creadas y de las que accede durante su ejecución. El tamaño del Stack es un parámetro crítico cuando se quiere crear una aplicación con un consumo de memoria cercano al límite de la capacidad disponible. Entre mayor sea su valor, 61 menor cantidad de estructuras pueden ser creadas. Es un parámetro importante para comprobar la máxima capacidad del sistema, el cual debe ser llevado al mínimo valor posible con el que la aplicación funcione correctamente. Número de elementos en el sistema Se entiende por elementos el número de Agentes, Comportamientos, Puertos, Guardas y Tipos de Eventos existentes en el sistema. Dependiendo del tipo de elemento creado, puede aumentarse considerablemente el espacio reservado en memoria. En el caso de los Agentes, la creación de una nueva entidad implica la creación de un Canal, un Comportamiento, un Puerto y una Guarda como mínimo; en estos casos un nuevo elemento está ligado a otro, siendo mayor el consumo de memoria requerido. Al crear un nuevo Agente o un Comportamiento, se están creando tareas adicionales. Cada tarea adicional implica tiempo de procesador para su ejecución y una mayor carga de procesamiento en el sistema, lo cual debe verse reflejado en un aumento en los tiempos de respuesta a eventos. En la creación de una nueva estructura como una Guarda o un Puerto, el aumento en los tiempos de respuesta no debería ser significativo para incrementos pequeños en el número de elementos. Esto debido a que no hay implícito ningún cambio de contexto, sino un poco de procesamiento adicional. Si la cantidad de elementos se incrementa notablemente, seguramente se producirá un cambio en el tiempo de procesamiento y de respuesta. Periodo de envío de Eventos Según la aplicación es posible que se requiera enviar periódicamente eventos a los agentes presentes en el sistema. La frecuencia con que son enviados los eventos puede ser variada según se necesite. Si el periodo de envío es muy pequeño, algunos de los eventos generados pueden no ser entregados si la cola de recepción del destinatario se encuentra llena. Es conveniente determinar, bajo un entorno controlado, la frecuencia máxima de envío con la que se asegura que los eventos lleguen a su destino. Los tiempos de respuesta pueden también variar dependiendo de los envíos realizados, pues el tiempo que mantienen ocupado el procesador puede aumentar o disminuir según la frecuencia utilizada. 62 Variables Intervinientes Funciones de Tratamiento Las funciones de tratamiento a los eventos generados varían dependiendo de la aplicación a implementar por el programador. Una función donde se ejecuten gran cantidad de instrucciones, puede aumentar significativamente los tiempos de respuesta del sistema. La función de tratamiento es una variable que incide en el desempeño de la plataforma y que no se puede generalizar como constante para todos los casos. No es posible ni conveniente definir entonces, rutinas de tratamiento estándar en función de las cuales se realicen las pruebas. Sin embargo para las pruebas realizadas y dependiendo del caso, se debe implementar una función sencilla que se mantenga como una constante interviniente controlada. Tamaño de los datos de los eventos BESA En el tamaño de los eventos se presenta el mismo caso anterior. Establecer un tamaño fijo de datos es una limitante en el desempeño de la plataforma BESA-ME, pues depende totalmente de la aplicación que el usuario final desarrolle. Tampoco es conveniente tratarla como una variable independiente, ya que no es posible determinar valores estándar de tamaño de datos en función de los cuales realizar las pruebas. Por estas razones se considera el tamaño de los datos como una variable interviniente que afecta el resultado de las pruebas, en especial en los casos en que haya comunicación entre agentes de distintos contenedores, pero que puede mantenerse constante permitiendo observar la influencia de otros parámetros más relevantes. Velocidad de Procesamiento La velocidad de procesamiento es una variable relacionada directamente con el tiempo de respuesta a los eventos y con la cantidad de eventos que son enviados correctamente a su destino. Si el tiempo de respuesta aumenta, seguramente no todos los eventos generados serán recibidos por la tarea correspondiente. Está variable está ligada a la velocidad del oscilador seleccionado y a la cantidad de instrucciones que tenga que ejecutar el procesador para lograr un resultado en la aplicación creada. Interviene en los resultados de las pruebas, afectando directamente cualquier variable dependiente del tiempo de procesamiento. Para todas las pruebas se utilizará la misma velocidad de reloj (oscilador microcontrolador @ 20 MHz, reloj de transmisión I2C @ 100 kHz), logrando así que su efecto en los resultados sea constante. Variables Dependientes 63 Se quiere observar el desempeño de la plataforma BESA-Micro Edition en cuanto al tiempo de Respuesta a eventos, el funcionamiento y capacidad del sistema, y el número de errores y envíos exitosos, es decir el número de envíos que se completan en la comunicación entre agentes y en las interrupciones. Es en estos parámetros en los que se espera se presenten variaciones significativas en función de las variables independientes. El tiempo de Respuesta a eventos, como se explicó anteriormente, está relacionado con el porcentaje de uso de la capacidad máxima del sistema y con la frecuencia de envío de eventos. Al igual que el número de errores y envíos exitosos, que dependen del tiempo de procesamiento necesario para que un envío se pueda completar y del periodo con el que se envíen. El funcionamiento y la capacidad del sistema están estrechamente relacionados. El funcionamiento del sistema depende de que no se excedan los límites bajo los cuales BESA-ME opera correctamente, entre ellos, los límites de capacidad, dados por el número máximo de elementos a partir del cual la operación de la plataforma se torna inestable. 4.1.2. Pruebas a Realizar Para la realización de las pruebas se han definido tres grupos generales que comprenden las variables identificadas anteriormente. Pruebas de Capacidad Las pruebas a realizar son simplemente una verificación de las capacidades del sistema. Esta verificación se divide en dos partes, la primera a nivel de agente y la segunda a nivel de sistema. A nivel de agente, se busca el número máximo de comportamientos, guardas, puertos y eventos que soporta el microcontrolador para un sólo agente. A nivel de sistema, se busca el número máximo de agentes que soporta el sistema para cada microcontrolador. Para cada caso se debe tratar de reducir al valor mínimo el tamaño del Stack asignado a cada tarea, y así maximizar el espacio disponible para nuevas estructuras. Además se hace importante observar para cada prueba, cómo influye el aumento del número de elementos del sistema, en los tiempos de respuesta a eventos del mismo. Pruebas de Comunicación Las pruebas de comunicación incluyen envíos entre agentes de distintos contenedores y del mismo contenedor. El objetivo principal de las pruebas es, entre otros, observar los tiempos de 64 respuesta a eventos periódicos y los errores o envíos fallidos que se presentan en las comunicaciones locales y externas. Para estas pruebas no es relevante reducir el tamaño del Stack de las tareas al menor valor posible, simplemente se debe asegurar un tamaño adecuado para su correcta operación. El número de elementos en el sistema debe ser el mínimo necesario para que el sistema funcione en cada prueba y se logren los resultados esperados. Pruebas de Interrupciones Las pruebas de Interrupciones pretenden establecer los tiempos de respuesta a eventos periódicos generados desde la rutina de interrupción, y observar para diferentes frecuencias, los tipos de errores que se presentan y el número de envíos que no se pueden completar. Al igual que en las pruebas de comunicación, el tamaño del Stack de las tareas y el número de elementos en el sistema, no son parámetros relevantes para el caso, simplemente se deben ajustar para asegurar el funcionamiento de la plataforma durante las pruebas. 4.2. Análisis de los Resultados Obtenidos Es importante mencionar que para la mayoría de las pruebas, se creó una tarea adicional Prueba que enviaba eventos constantemente a los agentes existentes en el Sistema. La creación de una tarea auxiliar es una solución para cuando se requiere enviar eventos periódicamente. Además, la función de tratamiento a los eventos fue una función sencilla creada igual para todos los agentes. El tamaño de los datos de los eventos BESA se dejó igual que el utilizado en las pruebas realizadas durante la implementación de la comunicación entre contenedores (tamaño máximo de datos igual a 6). 4.2.1. Pruebas de Capacidad En las pruebas de capacidad se utilizó la tarea Prueba para enviar eventos a una frecuencia constante. Se realizó primero una pequeña prueba con diferentes tamaños datos y de Stack para evaluar el funcionamiento de la plataforma. Luego se procedió a hallar los valores máximos de cada tipo de elemento o entidad que puede existir en el sistema, manteniendo las demás en el mínimo valor posible. Al obtener estos valores máximos especificados para la programación y diseño de futuras aplicaciones, se procedió a analizar simultáneamente los cambios en los tiempos de repuesta que ocurrían en el sistema respecto a la variación de entidades, es decir, al aumento de cada una de las tareas y esquemas de la plataforma. 65 Tamaño del Stack Para la siguiente prueba, se crearon las tres tareas que aparecen en la Tabla 4. La tarea Behavior y Channel pertenecientes al agente y la tarea adicional Prueba. Los valores mínimos para los que funciona correctamente el sistema fueron hallados a través del método de prueba y error, hasta acercarse a los valores óptimos. Entre menor sea el Stack, menos recursos de memoria consume y da cabida a más datos o tareas adicionales según se requiera. Tamaño del Stack Tarea Prueba 120 Tarea Behavior 120 Tarea Channel 120 MAX_DATA_SIZE Funcionamiento 130 120 150 130 130 150 130 150 130 6 failed failed ok 130 ok 10 15 16 ok ok ok 17 105 131 116 108 18 failed failed 17 ok 105 107 106 107 failed failed ok 1 ok ok Tabla 4. Valores de los Stacks. En la Tabla 4 se observan las pruebas realizadas para diferentes tamaños de datos, variando el tamaño del Stack donde cada tarea almacena los datos a los que accede antes de un cambio de contexto. Cuando el stack es muy pequeño el cambio de contexto no se produce correctamente, ocasionando la perdida de los datos y el funcionamiento incorrecto del sistema. Existe una relación entre el tamaño del Stack y el tamaño de los datos. Si el tamaño de los datos aumenta, el Stack de las tareas que utilicen la variable debe aumentar al menos en la misma proporción. Esto se debe a que el número de datos que deben ser guardados en un cambio de contexto aumenta al incrementarse el tamaño de los datos. Sin embargo, se aconseja según la documentación del RTOS 24 , definir el tamaño del Stack calculando el tamaño de todas las variables que accede y crea la función y utilizar el doble al menos, para después mediante pruebas acomodarlo a un valor más cercano al límite. Cantidad de Agentes por Contenedor En la Tabla 5 se observan diferentes tiempos de respuesta obtenidos a partir del momento en que se le envía un evento al primer agente. A su vez, se fue incrementando el número de agentes en el Contenedor, dejando las otras variables constantes. Los tiempos fueron medidos utilizando un osciloscopio, a partir del momento en que se enviaba el dato desde la tarea Prueba, hasta cuando comenzaba a ejecutarse la función de tratamiento correspondiente en el comportamiento de cada agente. 24 FreeRTOSPTM, www.freertos.org. Mayo 25 de 2005. 66 Variable Tiempo de Respuesta (ms) Cantidad de agentes Agente Referido al primer envío 1 a 0.512 a 0.512 b 3.22 b 1.26 2.02 c 3.22 1.96 2 3 4 5 Referido a su propio envío 0.52 2.708 a 5.24 c 1.26 1.98 d 3.24 2 2.04 a 5.24 b 7.28 d 1.2 2 e 3.2 2.05 a 5.25 2 b 7.25 2.05 c 6 Diferencia de Tiempo 0.52 Constantes Comportamientos 1 Guardas 1 Guardas por puerto 1 Puertos 1 Funciones 1 5.24 5.24 Cantidad Stacks Prueba 70 Comportamiento 130 Canal 140 5.28 9.3 No funciona No funciona Tabla 5. Tiempos de Respuesta para distintas cantidades de Agentes en un Contenedor. Todos los tiempos en milisegundos. Referidos al Primer Envío En el momento de hacer el primer envío de un evento desde la tarea Prueba al primer agente, se cambiaba el estado de una bandera (se conmutaba el valor de un puerto de salida entre un cero lógico y un uno lógico); en seguida se enviaban los demás eventos a los agentes restantes. Cuando el comportamiento de cada agente iniciaba la ejecución de la función asociada, se cambiaba el estado de una bandera diferente para cada agente. A través del osciloscopio se obtuvo el tiempo de respuesta al observar el tiempo transcurrido entre los cambios en los puertos de salida para los casos descritos anteriormente. Como se observa en la Tabla 5, aunque los tiempos no son constantes en todos los casos, si se presenta una tendencia a repetirse cada tiempo según el orden en que han sido enviados. La diferencia entre un valor mayor y el inmediatamente inferior tiende a 2 ms, por lo que hay cierta constante entre los tiempos de respuesta. Sin embargo se puede apreciar que el orden en que el planificador del RTOS otorga el procesador a cada tarea no depende del orden en que es enviado el evento. Referidos a su Propio Envío En el momento en que se enviaba un evento desde la Tarea Prueba a cada agente, se cambiaba el estado de una bandera diferente (un puerto de salida diferente) por cada envío. Cuando comenzaba a ejecutarse la función asociada desde el comportamiento de cada agente, se 67 cambiaba el estado de una bandera distinta para cada agente y utilizando un osciloscopio, se medía el tiempo transcurrido entre el envío del evento al agente y la respuesta por parte del mismo. Se puede observar en la Tabla 5 que los tiempos obtenidos de esta forma, son los mismos según el número de agentes en el sistema. El tiempo de respuesta obtenido entre el envío del evento a un agente determinado y el comienzo de la ejecución de la función por parte del comportamiento de dicho agente, es igual para cada uno, y aumenta de acuerdo al número de agentes en el sistema, hasta hacerse casi estable a partir de tres agentes. Cantidad de Comportamientos Variables Tiempo de Respuesta (ms) Constantes Comportamientos 1 Guardas por Agente 1 2 2 3 3 4 4 5 5 6 6 Todos los comportamientos asociado a un solo tipo de evento 0.512 - 0.888 1.4 - 0.12 1.52 - 0.20 7 7 8 8 9 9 10 10 11 11 2.04 12 12 No funciona Cantidad Agentes por contenedor 1 Guardas 1 Guardas por puerto 1 Puertos 1 Funciones Tamaño de la Cola de recepción 1 1 Stacks 1.72 - 0.296 1.816 - 0.224 Prueba 70 Comportamiento 105 Canal 105 Tabla 6. Tiempos de Respuesta para distintas cantidades de Comportamientos en un Contenedor. Por cada comportamiento adicional es necesario crear una Guarda que relacione un tipo de Evento y la función de tratamiento para el mismo con cada comportamiento. En la Tabla 6 se puede observar como aumenta el tiempo de respuesta obtenido según aumenta el número de comportamientos. El tiempo es medido a partir del momento en que se envía el Evento al agente desde la tarea Prueba, hasta el momento en que la función de tratamiento igual para todos los comportamientos, es ejecutada por el primer comportamiento. Los tiempos fueron tomados únicamente para números impares de comportamientos. Al restar un valor con respecto al inmediatamente anterior, obtenemos una diferencia de 0.2 ms aproximadamente, exceptuando la diferencia de tiempos de respuesta entre uno y tres comportamientos, que es aproximadamente cuatro veces mayor. Se podría afirmar según los resultados que después de tres comportamientos, por cada comportamiento agregado, el tiempo de respuesta aumenta entre 0.1ms y 0.15ms. 68 Cantidad de Guardas Variable Funcionamiento Constantes Cantidad # Guardas en un solo puerto Todos las Guardas asociadas a un sólo tipo de evento Agentes por contenedor 1 Comportamientos 1 1 ok 5 ok 10 ok 15 ok 20 ok 21 No funciona Puertos 1 Stacks Prueba 70 Comportamiento 105 Canal 105 Tabla 7. Cantidad máxima de Guardas en un contenedor En las pruebas realizadas para hallar el máximo número de Guardas con las que el sistema funciona correctamente, no se hicieron pruebas de tiempo de respuesta. Como las guardas están asociadas a un mismo comportamiento, se repetiría la función de tratamiento al Evento tantas veces como número de Guardas haya, por cada Evento que sea enviado al agente. Si se quiere evitar que se pierdan los mensajes enviados al comportamiento, se debe crear su cola de recepción, del mismo tamaño del número de Guardas. Como se observa en la Tabla 7, las Guardas fueron creadas en un mismo Puerto, es decir, para un sólo tipo de Evento. El sistema funcionó correctamente hasta 20 Guardas. Cantidad de Puertos Valores Constantes Tiempo de Respuesta (ms) # Puertos = Tipos de Eventos Un evento activa todas las Guardas 1 Valores Constantes Agentes por contenedor Cantidad 1 Guardas por puerto 1 0.52 Funciones 1 10 2.1 Variables por función 1 20 2.9 Comportamientos 30 3.48 40 4.16 Prueba 50 5.1 Comportamiento 105 Canal 105 51 1 Stacks No funciona 70 Tabla 8. Tiempos de respuesta a eventos con distintas cantidades de Puertos Cada puerto creado significa un tipo de evento diferente en el sistema. Como se observa en la Tabla 8, el máximo número de puertos en el canal del agente con el que el sistema funcionó correctamente fue 50. El tiempo de respuesta fue medido desde el momento en que se envía un 69 tipo de Evento hasta que es ejecutada la función asociada al mismo Evento. A medida que aumenta el número de Puertos el tiempo de respuesta, como se esperaba, se incrementa también. Este incremento se debe al tiempo adicional de procesamiento que conlleva la existencia de un puerto más en el canal del agente. El aumento más significativo de tiempo al incrementar el número de Puertos, se obtuvo al pasar de un puerto a diez. Este resultado es coherente con los anteriores donde el mayor cambio en los tiempos de respuesta se tiene en el incremento posterior a la prueba con el mínimo de elementos en el sistema. Síntesis de Resultados Obtenidos Luego de hallar los valores máximos a condiciones optimas, es decir, manteniendo el resto de variables en el menor valor posible, se tiene que: A nivel Agente Número máx. de comportamientos = 11; Número máx. de Guardas en un sólo Puerto = 20; Número máx. de Puertos = 50; A nivel Sistema Número máx. de Agentes por Contenedor = 5; 4.2.2. Pruebas de Comunicación Las pruebas de comunicación realizadas, contenedores y del mismo contenedor. incluyen envíos entre agentes de distintos El objetivo principal de las pruebas es, entre otros, observar los tiempos de respuesta a eventos periódicos y los errores o envíos fallidos que se presentan en las comunicaciones locales y externas. En su realización se utilizó la tarea Prueba, desde la que se envían eventos periódicamente a un agente, utilizando la función del RTOS vTaskDelay ( t (ms) ). Esta función duerme la tarea por el tiempo t dado en milisegundos. El agente que recibe el evento lo envía de nuevo a otro agente que dependiendo de la prueba realizada, puede estar en el mismo contenedor o no. Es importante aclarar que el tiempo por el que la tarea se atrasa, el cual es introducido desde el programa, varía respecto al tiempo real observado en un osciloscopio. La exactitud del tiempo depende de elementos externos como lo es la velocidad del Oscilador y en general las características del Hardware en el que se implementa. 70 Envíos de Eventos por el Canal de Comunicación Para las siguientes pruebas se tuvo en cuenta: - Tiempo de bloqueo del canal. Dado en milisegundos. Suspende la ejecución de la tarea para permitir un cambio de contexto y dar la posibilidad de que el comportamiento pueda recibir el mensaje de la cola, y de esta forma, no se pierda el siguiente evento que se envíe. - Tamaño de Cola. Al aumentar la cola del canal o del comportamiento aumenta la probabilidad de que los envíos sean exitosos y que el número de envíos que se pierden sea menor. Para estos datos constantes se probó con diferentes periodos de envío para observar como afecta en el número de envíos exitosos de eventos. Tiempo de bloqueo del canal (ms) 0 0 0 8 Tamaño de la cola de recepción del canal 1 2 3 1 Tamaño de la cola de recepción del comportamiento Periodo entre envío de mensajes usando vTaskDelay (ms) Eventos NO enviados por I2C (%) Eventos enviados por I2C (%) 2 71 29 4 50 50 6 33 67 8 0 100 0 82 18 2 71 29 4 50 50 6 7 93 1 2 3 1 8 0 100 50 0 100 100 0 100 0 86 14 2 67 33 4 50 50 6 0 100 2 75 25 4 50 50 6 34 66 8 0 100 Tabla 9. Envíos de Eventos por el puerto I2C con diferentes tamaños de colas y periodos de envío. 71 Las variaciones en los tamaños de las colas se realizaron únicamente para el agente transmisor, el cual recibía el evento proveniente de la tarea Prueba, para enviarlo luego desde el comportamiento al agente destino ubicado en otro contenedor. Es importante resaltar que una vez el evento es recibido por el comportamiento del agente transmisor, se asegura su envío por el puerto de comunicaciones. Los datos obtenidos se pueden observar en la Tabla 9. Para la prueba se consideró como un envío bueno o completado, los envíos que se realizaron por el canal de comunicaciones I2C, sin tener en cuenta si eran entregados con éxito al agente destino. Por el contrario, un envío que no se pudo realizar por el puerto de comunicaciones, fue considerado como fallido. Se puede ver que a medida que se aumenta el tamaño de la cola, el número de envíos no recibidos por el comportamiento disminuye para los diferentes periodos. Esto se hace más notorio cuando el tamaño de la cola es tres; en este caso, para un periodo de envío igual a 6ms, todos los envíos son recibidos por el comportamiento y por lo tanto transmitidos por I2C (ver figura 24). Para los casos en los que el tamaño de la cola es uno y dos, sólo se completan todos los envíos para un periodo de generación de eventos igual a 8 ms (ver figuras 22 y 23). Sin embargo cuando el tamaño de la cola es dos, un porcentaje mayor de envíos se completa en tiempos inferiores. Por lo tanto una estrategia de asegurar que el comportamiento reciba la mayor cantidad de envíos posible para que así puedan ser enviados, es aumentando el tamaño de las colas del canal y/o de los comportamientos, con lo cual se pueden almacenar eventos mientras se está atendiendo algún otro. Otra forma de garantizar que todos los envíos de eventos sean recibidos por el agente, es aumentando el periodo en que le son generados los eventos, para que de esta forma pueda ejecutar la transmisión por I2C y desocupar la cola de recepción a tiempo para el siguiente envío que le llegue. En el último caso, en el que el tiempo de bloqueo del canal se aumenta a 8ms, el significado de los datos obtenidos cambia un poco. Al bloquearse la tarea canal durante un tiempo, los eventos que le sean enviados durante ese mismo tiempo no podrán ser almacenados en la cola del canal, que en este caso es de tamaño uno. La cola únicamente podría recibir uno cada vez que la tarea retome el control del procesador y vacíe su cola. Para este caso los datos mostrados como no enviados al comportamiento, son en realidad el número de eventos que no fueron enviados al canal y por lo tanto nunca llegaron tampoco al comportamiento. En la Figura 19 se pudo ver que el tiempo mínimo para un envío por I2C para el tamaño de datos establecido es de 7.15 ms aproximadamente. El tiempo de bloqueo de la tarea canal es entonces 8ms para darle tiempo al comportamiento de hacer la transmisión y estar listo para 72 recibir un nuevo envío. Esta es otra estrategia para evitar que los envíos se pierdan, sin embargo, no es la más adecuada, pues bloquear el canal, retardaría el envío de eventos a otros comportamientos que podrían ejecutarse en paralelo. Porcentaje de Enviados Vs Periodo de Envío % Tam año de Cola = 1 120 100 80 60 40 20 0 Enviados No Enviados 2 4 6 8 ms - Generados con vTaskDelay Figura 22. Envíos exitoso para diferentes frecuencias de envío y tamaño de cola igual a uno. Porcentaje de Enviados Vs Periodo de Envío % Tam año de Cola = 2 120 100 80 60 40 20 0 Enviados No Enviados 0 2 4 6 8 50 100 ms - G ener ad o s co n vT askD el ay Figura 23. Envíos exitoso para diferentes frecuencias de envío y tamaño de cola igual a dos. 73 % Porcentaje de Enviados Vs Periodo de Envío Tamaño de Cola = 3 120 100 80 60 40 20 0 Enviados No enviados 0 2 4 6 m s - Generados con vTaskDelay Figura 24. Envíos exitoso para diferentes frecuencias de envío y tamaño de cola igual a tres. Tiempos de Respuesta a Eventos Periodo entre envío de mensajes (ms) Tiempo de respuesta (ms) 200 9.2 100 9.2 30 9.2 25 9.2 22 9.2 21 9.2 20 9.2 19 9.2 15 9.2 Tabla 10. Tiempos de respuesta a un envío remoto por I2C. Los tiempos de respuesta de la Tabla 10 fueron medidos a partir del momento en que en el comportamiento de un agente origen comienza a hacer el envío externo por I2C a un agente destino, hasta que finaliza la trama de datos de un evento enviado por el agente destino al agente origen, como respuesta al evento que recibió. A partir de los resultados se deduce que sin importar la frecuencia de envío de eventos, el tiempo que transcurre entre el envío de un evento a un agente remoto y el final de la respuesta por parte de este, es constante. 74 Periodo de eventos (ms usando vTaskDelay) Periodo de la atención al evento (ms) 0-9 10.4 10 11.2 12 12.8 15 16 20 21 25 26 30 31.2 35 36.8 40 41 Tabla 11. Tiempos de atención a los envíos externos de eventos generados periódicamente. El tiempo de atención al evento obtenido en la Tabla 11, indica la periodicidad con la que se ejecuta la función de tratamiento desde el comportamiento, es decir, el tiempo que transcurre desde que se ejecuta la función hasta que vuelve a ejecutarse de nuevo, para diferentes periodos de generación de eventos. Debido a que la función de tratamiento corresponde a envíos externos por I2C, el menor tiempo obtenido sigue siendo mayor al mínimo requerido para un envío remoto, el cual es 7.2 ms aproximadamente incluyendo la confirmación (trama AckBESA), como se observa en la figura 19. Entonces, para tiempos menores a 9 ms en la generación de eventos, el periodo en que se atienden en los comportamientos se hace constante. Se puede concluir que en las pruebas realizadas el tiempo mínimo que requiere un comportamiento para ejecutar un envío externo periódicamente es de 10.4ms aproximadamente. En la Figura 25 se observan con mayor claridad los resultados. Periodo de atención al Evento Vs. Periodo de envío 50 ms 40 30 20 10 0 0 9 10 12 15 20 25 30 35 40 ms Figura 25. Tiempos de atención a eventos periódicos de envíos externos, desde los comportamientos. 75 Periodo de eventos (ms usando vTaskDelay) Periodo de la atención al evento (ms) 1 2 2 3 3 4 4 5 5 6 6 7.8 7 8 8 9 9 10 10 11.5 12 12 15 16 20 21 25 26 30 31 35 36.8 40 41 Tabla 12. Tiempos de atención a los envíos locales de eventos generados periódicamente. Los tiempos obtenidos en la Tabla 12 a diferencia de los anteriores, corresponden a funciones de tratamiento de envíos locales. Por esta razón el periodo de atención es mucho menor; los comportamientos se demoran menos en ejecutar un envío local que uno remoto. Los datos indican una variación de aproximadamente 1ms entre la periodicidad con la que se generan y se atienden. Es importante recordar que para generar los eventos se esta utilizando una función proporcionada por el RTOS, donde el tiempo que se introduce en el programa, varía ligeramente con el tiempo real obtenido. En la Figura 26 se observan los datos obtenidos. Periodo de atención al Evento Vs. Periodo de envío 50 ms 40 30 20 10 0 1 2 3 4 5 6 7 8 9 10 12 15 20 25 30 35 40 ms Figura 26. Tiempos de atención a eventos periódicos de envíos locales, desde los comportamientos. 76 Tipos de Errores en la Comunicación Externa Un agente transmisor y un agente receptor ubicados en distintos contenedores Las colas de recepción de los comportamientos y de los canales, de los dos agentes intervinientes, son de tamaño 2. La tarea Prueba se encarga de generar eventos con un determinado periodo. Sin embargo, no todos estos envíos son recibidos con éxito por el agente transmisor, el cual envía eventos externos, según su capacidad de recepción y envío lo permitan. Los resultados plasmados en la figura 27 corresponden a 500 intentos de envío realizados por el agente 'a' hacia el agente 'c' a través del bus i2c, para cada periodo de envío de eventos. Figura 27. Envíos exitosos vs periodo de envío, para dos agentes ubicados en distintos contenedores. Cada punto representa un grupo de 100 envíos Cuando el periodo de generación de los eventos es inferior a 10.4ms aproximadamente, el agente 'a' no es capaz de transferirlos todos al bus I2C, por esta razón, muchos de esos eventos no pueden ser atendidos por el agente 'c'. El número de envíos exitosos para periodos menores a 10.4 ms aproximadamente es entonces aleatorio, según el estado de procesamiento del microcontrolador, es decir, depende de qué tarea se esta ejecutando actualmente, y de cuáles otras están pendientes por ser atendidas. Igual ocurre entonces con la frecuencia con la que el comportamiento del agente 'c' puede ejecutar su acción. La razón más frecuente por la cual los envíos no logran alcanzar con éxito su destino es debido a que se cumple el tiempo límite de espera del mensaje de confirmación (TIME_OUT_ACK) del agente receptor, en este caso el agente 'c'. La segunda razón más frecuente por la cual los envíos no se completan satisfactoriamente la transmisión, es la finalización del tiempo de espera para poder realizar envíos externos (TIME_OUT_SEND), debido a que otro agente ha tomado anteriormente este semáforo. Los resultados que sustentan las anteriores afirmaciones 77 se pueden observar en las figuras 28, 29, 30 y 31. En estas figuras se ven los diferentes tipos de errores que se encontraron para varias pruebas realizadas para diferentes periodos de generación de eventos. Porcentaje de tipos de error TIPOS DE ERRORES 3.5 3 2.5 2 TIME OUT ACK TIME_OUT_SEND 1.5 1 0.5 0 -0.5 0 TIME_OUT_BUFFER CHK_SUM_BAD BUS_COLLITION 2 4 6 8 Número de la prueba Figura 28. Porcentaje de causas de error para un xDelayTime de 2ms. Porcentaje de tipos de error TIPOS DE ERRORES 60 50 TIME OUT ACK 40 TIME_OUT_SEND 30 TIME_OUT_BUFFER 20 CHK_SUM_BAD 10 BUS_COLLITION 0 0 2 4 6 Número de la prueba Figura 29. Porcentaje de causas de error para un xDelayTime de 11ms. Porcentaje de tipos de error TIPOS DE ERRORES 70 60 50 40 30 20 10 0 -10 0 TIME OUT ACK TIME_OUT_SEND TIME_OUT_BUFFER CHK_SUM_BAD BUS_COLLITION 2 4 6 Número de la prueba Figura 30. Porcentaje de causas de error para un xDelayTime de 14ms. 78 Porcentaje de tipos de error TIPOS DE ERRORES 70 60 50 40 30 20 10 0 TIME OUT ACK TIME_OUT_SEND TIME_OUT_BUFFER CHK_SUM_BAD BUS_COLLITION 0 2 4 6 Número de la prueba Figura 31. Porcentaje de causas de error para un xDelayTime de 20ms. Cabe anotar que los tiempos de espera de los envíos, como el de la confirmación de acknowledge BESA (TIME_OUT_ACK), el de espera a la liberación del semáforo de envío (TIME_OUT_SEND) y el del buffer de transmisión (TIME_OUT_BUFFER), son valores que el usuario, según su necesidad en la aplicación y la longitud de las tramas externas definidas, puede llegar a modificar fácilmente. Por la seguridad del funcionamiento de la plataforma se recomienda hacer los cambios de acuerdo a las consideraciones hechas anteriormente y a las instrucciones dadas en el archivo configuration.h. Dos Agentes Transmisores en un Contendor y un Agente Receptor Ubicado en otro Contenedor. En este caso, son dos agentes, 'a' y 'b', los que envían eventos a un sólo agente 'c', ubicado en otro contenedor. Como es de esperarse, cuando la frecuencia de generación de envíos es muy alta (periodo pequeño), los eventos que logran llegar con éxito al agente externo son muy pocos. A medida que el periodo de envío aumenta, es mayor el lapso de tiempo dado al agente 'c' para que atienda todos los mensajes recibidos y poder ejecutar las funciones asociadas. El periodo de generación de eventos para el cual se alcanza un 100% de envíos exitosos, es mayor que cuando sólo se tenía un agente transmisor (ver figura 32). Esto se debe a que ya son dos los agentes que compiten por el uso del bus de comunicaciones, aumentando la carga de procesamiento e incrementado como consecuencia el número de posibles errores en los envíos. Como lo muestra la figura 32, solamente cuando el retardo en la tarea Prueba alcanza un valor de 26ms, el 100% de las transferencias se culminan exitosamente. 79 Envios Exitosos por I2C 120.00 100.00 % 80.00 60.00 40.00 20.00 0.00 0 5 10 15 20 25 30 Periodo de Generación de Eventos (ms) Figura 32. Envíos exitosos vs periodo de envío, para 2 agentes productores y un consumidor. El valor del periodo de envío correspondiente a 26ms es aproximadamente el doble del valor en el cual se estabilizaba el sistema cuando existía un sólo productor y un sólo consumidor. Este era un valor esperado, ya que se están generando el doble de envíos por parte de los agentes 'a' y 'b', por lo cual se aumenta también la carga de recepción para el agente 'c'. Tipos de Errores (Periodo de Envio = 3 ms) % 40.00 30.00 TIME OUT ACK 20.00 TIME OUT SEND 10.00 TIME OUT BUFFER CHK SUM_BAD 0.00 0 2 4 6 BUS COLLITION Tipo de Muestras Figura 33. Porcentaje de Causas de error para un xDelayTime de 3 ms. 80 Tipos de Errores (Periodo de Envio = 10 ms) 30.00 TIME OUT ACK % 20.00 TIME OUT SEND 10.00 TIME OUT BUFFER 0.00 -10.00 0 2 4 6 CHK SUM_BAD BUS COLLITION Tipo de Muestras Figura 34. Porcentaje de Causas de error para un xDelayTime de 10 ms. Tipos de Errores (Periodo de Envio = 14 ms) 60.00 TIME OUT ACK % 40.00 TIME OUT SEND TIME OUT BUFFER 20.00 CHK SUM_BAD 0.00 -20.00 0 2 4 6 BUS COLLITION Tipo de Muestras Figura 35. Porcentaje de Causas de error para un xDelayTime de 14 ms. Las causas por las cuales se presentan errores en la comunicación son variadas. Sin embargo se observa que de nuevo la causa que presenta mayor porcentaje en la aparición de errores de la comunicación es el agotamiento del tiempo de espera del mensaje de confirmación BESA (TIME_OUT_ACK). Cuando son dos los productores que ubican eventos en el bus i2c, aumentan las colisiones, y por consiguiente es más frecuente la recepción de tramas con alteración en los bits, es decir, un checksum erróneo. También es considerable el número de casos en los que se agota el tiempo de espera para la liberación del buffer de envío. Las figuras 33, 34 y 35 muestran la distribución de las causas de los errores, para los tiempos en los que más se presentaron. 4.2.3. Pruebas de Interrupciones Para las pruebas realizadas con Interrupciones se programó un modulo del microcontrolador (Timer4) utilizado para que genere las interrupciones periódicas. Desde la rutina de Interrupción se hace el envío de un evento a un agente local, cambiando el estado de una señal en el momento de enviarlo. Cuando el evento es recibido por el agente y este ejecuta la función asociada al comportamiento respectivo, se cambia de nuevo una bandera indicando su correcta 81 recepción. Los tiempos de respuesta fueron calculados promediando entre el mayor y el menor tiempo obtenido en el osciloscopio. Se realizaron cinco series de cien envíos periódicos para cada tiempo seleccionado, calculando el promedio de los envíos correctos, los fallidos y el número de veces que se generó la interrupción, después de las cinco repeticiones. Cada repetición termina en el momento en que la tarea vAdaptor, encargada de recibir los eventos provenientes de interrupciones y enviarlos al agente destino, intenta 100 envíos al agente, sin importar si fueron exitoso o no. Tiempo de Interrupción (ms) Promedio Envíos Correctos Promedio Envíos Fallidos Promedio Interrupciones Tiempo Promedio de Respuesta (ms) 10,48 100 0 100 3,7 9,83 100 0 100 3,7 9,17 100 0 100 3,7 8,51 100 0 100 3,7 7,86 100 0 100 3,7 7,2 100 0 100 3,7 6,55 100 0 100 3,7 5,89 100 0 100 3,7 5,24 100 0 100 3,7 4,58 100 0 100 3,7 3,93 100 0 100 3,6 3,27 100 0 100 3,6 2,62 86 14 100 3,6 1,96 68 32 113 3,6 1,31 62 38 140 3,6 0,65 41 59 231 3,6 0,32 27 73 325 3,6 Tabla 13. Promedio de Envíos exitosos y fallidos generados desde una rutina de interrupción a un agente local. Los resultados obtenidos en la Tabla 13, indican que para tiempos de interrupción menores de 3,27ms aproximadamente, los envíos realizados al agente desde una interrupción no son atendidos en su totalidad. Para tiempos inferiores, no todos los envíos generados por la rutina de interrupción llegan a la cola de recepción de la tarea vAdaptor (cuando el tamaño de la cola de recepción es uno), y no todos los que son recibidos pueden ser enviados al agente destino. Es posible observar que desde envíos periódicos cada 1,96ms aproximadamente, se necesitan mayor número de envíos desde la rutina de interrupción para generar 100 envíos desde la tarea vAdaptor, bajando notablemente el nivel de efectividad a medida que el tiempo se hace más pequeño. 82 Envíos desde Interrupciones 350 300 Promedio Envíos Correctos 250 200 Promedio Envíos Fallidos 150 100 Promedio Interrupciones 50 0.32 0.65 1.31 1.96 2.62 3.27 3.93 4.58 5.24 5.89 6.55 7.2 7.86 8.51 9.17 9.83 10.5 0 (m s) Figura 36. Envíos generados desde interrupciones periódicas. A su vez, se concluye que una vez la tarea recibe los eventos provenientes de Interrupción, para tiempos inferiores a 3,27ms aproximadamente, los envíos realizados al agente no son 100% exitosos. El número de veces que encuentra la cola de recepción del canal del agente ocupada (cola de recepción de tamaño uno), aumenta cuando el tiempo se hace inferior. Esto se debe a que el tiempo de procesamiento necesario para que el canal atienda el evento no es suficiente cuando el periodo de las interrupciones es muy pequeño; además las interrupciones propias del funcionamiento del RTOS, sobrecargan también el sistema. En la Figura 36 se observa claramente la tendencia de aumento para pequeñas reducciones en el tiempo, de los envíos fallidos desde la tarea hacia el agente y del número de interrupciones necesarias para generar cien envíos exitosos a la tarea vAdaptor. Para tiempos inferiores al mínimo utilizado en las pruebas, el sistema se torno inestable y no funcionó correctamente. Por lo anterior es recomendable utilizar las interrupciones para la generación de eventos aleatorios. Si se quieren generar envíos periódicos a un agente, se recomienda crear una tarea adicional (la tarea Prueba por ejemplo), de mayor prioridad si es el caso, de donde se realicen los envíos cada determinado tiempo utilizando la función vTaskDelay ( t (ms) ). 83 4.3. Aplicación de Demostración Para demostrar el funcionamiento de la plataforma desarrollada, se establecieron aspectos que debían tenerse en cuenta para demostrar cada una de las características y cualidades de la plataforma. Además, esta aplicación puede servir como punto de partida para el diseño de nuevas aplicaciones, ya que le da al programador una idea de cómo puede abordar los problemas que desee solucionar con enfoque multi-agente en un sistema distribuido. Las siguientes son las características presentes en la aplicación: • Sistema distribuido. • Evento sincrónico. • Evento asincrónico. • Recursos compartidos. • Varios agentes. Situación Hardware Se desea medir y mostrar la amplitud y el promedio de una señal que se encuentra alejada físicamente de la interfaz con el usuario. El promedio y la amplitud desean ser mostrados en dos pantallas de LED que son controladas por microcontroladores diferentes. Como la señal que se está observando presenta varios rangos de frecuencia, se debe poder cambiar la frecuencia de muestreo para obtener un cálculo más preciso. Inicialmente se determinan las capacidades ofrecidas por el hardware con el que se cuenta. El microcontrolador que contiene el ADC debe ubicarse cerca de la señal que se desea medir, igualmente sucede con la pantalla de LED. La otra pantalla esta ubicada en otro lugar para mostrar el periodo de la señal, junto con un interruptor que cambiará el periodo de muestreo de la señal observada. Diagrama de Agentes Debido a que la lectura del ADC se realiza de forma sincrónica, se implementará entonces como una tarea periódica, y no dentro de una rutina de interrupciones. El valor instantáneo de la lectura será mostrado en la pantalla de LED. También se calcula el promedio de dicha señal para ser enviado al microcontrolador que contiene la otra pantalla. Una posible solución a este problema, con enfoque multiagente, en este caso para la plataforma BESA-SE ME encuentra en la figura 37. 84 Figura 37. Distribución de los agentes y sus respectivos comportamientos para la aplicación de demostración. Cuando la información mostrada por la pantalla promedio no es estable debido a la frecuencia de muestreo, el usuario puede oprimir la tecla de cambio de frecuencia, de esta forma se modifica el estado de este agente, y determinado comportamiento realiza un envío al agente del ADC, para que incremente la frecuencia de muestreo, logrando así una comunicación permanente entre los agentes y todos sus recursos, para lograr un resultado optimo. La distribución de los agentes se muestra en la figura 38. Finalmente, para probar la comunicación entre más de dos contenedores, se conectó un tercer microcontrolador al bus de comunicaciones, el cual genera envíos de evento tipo 1, el cual es el correspondiente a la lectura del adc. Estos envíos se los hace a uno de los agentes interfaz, que también recibe información del agente calculador. El código fuente de esta aplicación se encuentra en el anexo B, en la carpeta demo_besa, dentro de la cual se encuentra como proyecto base para iniciar cualquier desarrollo. 85 Figura 38. Distribución de los agentes según los recursos físicos disponibles. 86 5. CONCLUSIONES A partir de las experiencias recogidas durante el desarrollo e implementación de la plataforma BESA-ME y de los resultados obtenidos en las pruebas realizadas, se ha podido llegar a dos grupos generales de conclusiones, referentes al producto desarrollado y a los sistemas MultiAgente en general. BESA-Micro Edition se ofrece como un enfoque que facilita la solución de problemas complejos. La manera en que permite esquematizar y dividir los grandes objetivos en pequeños oficios, para luego distribuirlos en agentes dedicados y, lo más importante, implementarlos rápidamente sobre plataformas hardware, permite brindar ahora una forma de afrontar problemas de control. Los diseñadores de hardware dedicado pueden contar con un nuevo modelo de programación, que muy seguramente con el paso del tiempo, desplazará los antiguos métodos de diseño electrónico digital. La implementación del modelo BESA-Micro Edition para dispositivos microcontroladores permite la creación de aplicaciones orientadas a sistemas Multi-Agente de una manera sencilla y eficiente. El tiempo invertido en el desarrollo del código de aplicación se disminuye una vez se conozca la plataforma, se entienda el concepto Multi-Agente y cómo enfocarlo en una aplicación determinada. En BESA-ME se redujo al máximo el uso de variables globales en el sistema sin sacrificar robustez y seguridad. Con lo cual se maximizó la memoria de datos libre que puede ser usada por las tareas y en consecuencia se aumentó el número de comportamientos y agentes que pueden ser creados por el programador. La creación de tareas adicionales como los son el adaptador de interrupciones a eventos BESA y el administrador de mensajes externos, no hacen parte del modelo abstracto BESA, sin embargo, brindan mayor robustez al sistema y gran utilidad al programador cuando la aplicación lo requiera, evitando trabajo adicional por parte de él. El tiempo que tarda la plataforma en iniciar determinada función de tratamiento, luego de la aparición de un evento (tiempo de respuesta), es una variable importante en cualquier sistema en que se requiera control de un ambiente. Sin embargo en BESA-ME la prioridad está en que todos los eventos lleguen a su destino para luego ser atendidos. Para lograrlo BESA-ME permite el uso de prioridades y ejecuta concurrentemente las tareas asignadas gracias al RTOS que la soporta. De esta forma se asegura que todos los eventos se reciben y son procesados dando apariencia de paralelismo, respondiendo con mayor eficiencia a los sucesos ocurridos interna y externamente al sistema. 87 La plataforma fue desarrollada procurando siempre una alta robustez, con lo cual se sacrificó en aspectos como velocidad de respuesta y memoria libre, para facilitarle así al usuario, la toma de decisiones en el momento en que el sistema detecte las fallas. Los errores que se presenten en el sistema, BESA-ME tiene la capacidad, no sólo de detectarlos, sino de darle la oportunidad al programador de tomar la decisión más prudente según su aplicación. Los posibles errores que se puedan presentar en el sistema son errores de comunicación, falla en la detección de agentes o en el envío y recepción de eventos. Las restricciones presentadas por los microcontroladores en cuanto a recursos físicos, en especial la limitación de memoria disponible, fue de los factores más importantes a tenerse en cuenta en el momento de realizar cambios respecto al modelo original para adaptarlo al hardware seleccionado. Las modificaciones realizadas estuvieron orientadas a la adaptación de BESA a las estructuras y servicios prestados por el RTOS, y al ahorro de recursos limitados. Estos cambios no representaron una variación en cuanto al concepto planteado por el modelo abstracto BESA. Estas mismas restricciones existentes, hacen que BESA-Micro Edition cuente con un número limitado de agentes y comportamientos en un sólo contenedor, tal como se observa en el protocolo de pruebas. Sin embargo esta necesidad es resuelta al implementarlo como un sistema distribuido, incluyendo nuevos contenedores (microcontroladores) en el sistema. Esta expansión del sistema sólo requiere modificaciones en la configuración del sistema, facilitando así al usuario la creación de aplicaciones complejas para ambientes distribuidos. En BESA-Micro Edition sólo se implementó la creación estática de agentes, a diferencia del modelo abstracto donde se plantea la gestión del ciclo de vida de los agentes. Esta restricción depende directamente del modelo de manejo de memoria utilizado por el RTOS seleccionado, que no permite liberar memoria una vez ha sido reservada, imposibilitando la creación, destrucción y movilidad de los agentes entre diferentes contenedores, de forma dinámica. La portabilidad de la plataforma BESA-ME a otra familia de microcontroladores, esta directamente relacionada con el RTOS seleccionado. Debe verificarse que el RTOS se pueda implementar en el dispositivo escogido, de no ser así, deben realizarse los cambios necesarios para lograr su adaptación y garantizar su funcionamiento. Además, el procesador debe tener la capacidad suficiente de memoria para soportar la plataforma y un puerto de comunicaciones para permitir que el sistema sea distribuido. La implementación del protocolo de comunicación escogido se realizó de tal forma que la adopción de uno nuevo no implique grandes cambios en la plataforma. 88 Sin embargo es indispensable respetar la estructura y el procedimiento establecido a nivel de trama de datos, asegurando así la correcta operación del nivel superior. Los cambios a realizar serán entonces mínimos, dependiendo de las limitaciones y ventajas ofrecidas por cada protocolo de comunicación en particular. Proyecciones Futuras Dentro del desarrollo futuro de la plataforma BESA-ME planteamos los siguientes proyectos: • Diseño e implementación de mecanismos que permitan la creación dinámica de agentes. Esta característica será de gran utilidad para aplicaciones de inteligencia artificial. • Desarrollo de un directorio de páginas amarillas que acerque más el modelo BESA-ME al BESA. • Inclusión de mecanismos para la gestión del ciclo de vida de los agentes. • Adaptación de otros protocolos de comunicación, como blue tooth, wi-fi, para proveer la comunicación entre contenedores. • Diseño e implementación de un módulo de comunicación para conectar una plataforma diseñada sobre BESA-ME a una construida sobre BESA en versión Java permitiendo salida a una red de computadores. 89 90 6. BIBLIOGRAFIA CASTO GUTIÉRREZ, Alberto, “Migración de un Sistema Operativo De Tiempo Real, MaRTE OS, a un microcontrolador”, http://marte.unican.es/alberto_slides.ppt, Septiembre 5 de 2004. Foundation For Intelligent Physical Agents, http://www.fipa.org, Noviembre 5 del 2004. FreeRTOSTM, www.freertos.org. Mayo 25 de 2005. GONZALEZ, Enrique, AVILA, Jamir, BUSTACARA, César. “BESA” Bogotá, Colombia. 2003. LIU, Jiming. “Multi – Agent Robotic Systems”. CRC Press, Boca Ratón, Fl. 2001. MICROCHIP, PIC18FXX2 Data Sheet, Microchip Technology Inc 2002. MICROCHIP, PIC18F6520/8520/6620/8620/6720/8720 Data Sheet, Microchip Technology Inc 2002. MICROCHIP, Inter-Integrated Circuit™ (I2C™). Microchip Technology Inc 2004. MICROCHIP, I2C™ Master Mode, Overview and Use of the PICmicro® MSSP I2C Interface with a 24xx01x EEPROM. Abril 15 de 2005. MILENKOVICH, Milan. “Sistemas Operativos: Conceptos y Diseño”. Mc. Graw Hill, Madrid, España. 1998. Robocup Federation, “RoboCup Home Page”. http://www. robocup.org. SALVOTM, http://www.pumpkinc.com, Febrero 15 de 2004. SIRP, Sistemas Inteligentes, Robótica y Percepción. Grupo de Investigación de la Faculta de Ingeniería Electrónica, Pontifica Universidad Javeriana. STALLINGS, William. “Sistemas Operativos”. Prentice Hall. Madrid, España. 2001. WEISS, Gerhard. “Multiagent systems: A modern approach to Distributed Artificial Intelligence”. Masachussets, U.S.A 1999. 91 92 7. ANEXOS ANEXO A. MANUAL DEL USUARIO. 93 ANEXO B. CODIGO DE PROGRAMACION. El código completo que se desarrolló se encuentra en el CD que se adjunta con este documento. Los archivos propios de BESA-ME SE encuentran a continuación. 94 ANEXO C. CAMBIOS REALIZADOS EN EL RTOS (freeRTOSTM). CAMBIO EN EL ARCHIVO LINKER Código Original (Para PIC18F452) // $Id: 18f8620.lkr,v 1.1 2003/12/16 14:53:08 GrosbaJ Exp $ // File: 18f8620.lkr // Sample linker script for the PIC18F8620 processor LIBPATH . FILES c018i.o FILES clib.lib FILES p18f8620.lib CODEPAGE NAME=vectors START=0x0 END=0x29 CODEPAGE NAME=page START=0x2A END=0xFFFF CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED CODEPAGE NAME=eedata START=0xF00000 END=0xF003FF PROTECTED ACCESSBANK NAME=accessram START=0x0 END=0x5F DATABANK NAME=gpr0 START=0x60 END=0xFF DATABANK NAME=gpr1 START=0x100 END=0x1FF DATABANK NAME=gpr2 START=0x200 END=0x2FF DATABANK NAME=gpr3 START=0x300 END=0x3FF DATABANK NAME=gpr4 START=0x400 END=0x4FF DATABANK NAME=gpr5 START=0x500 END=0x5FF DATABANK NAME=gpr6 START=0x600 END=0x6FF DATABANK NAME=gpr7 START=0x700 END=0x7FF DATABANK NAME=gpr8 START=0x800 END=0x8FF DATABANK NAME=gpr9 START=0x900 END=0x9FF DATABANK NAME=gpr10 START=0xA00 END=0xAFF DATABANK NAME=gpr11 START=0xB00 END=0xBFF DATABANK NAME=gpr12 START=0xC00 END=0xCFF DATABANK NAME=gpr13 START=0xD00 END=0xDFF DATABANK NAME=gpr14 START=0xE00 END=0xEFF ACCESSBANK NAME=accesssfr START=0xF60 END=0xFFF SECTION ROM=config NAME=CONFIG PROTECTED PROTECTED STACK SIZE=0x100 RAM=gpr14 Código Modificado ( Para PIC18f8720) // $Id: 18f8620.lkr,v 1.1 2003/12/16 14:53:08 GrosbaJ Exp $ // File: 18f8620.lkr // Sample linker script for the PIC18F8620 processor LIBPATH . FILES c018i.o FILES clib.lib FILES p18f8620.lib CODEPAGE NAME=vectors START=0x0 95 END=0x29 PROTECTED CODEPAGE NAME=page START=0x2A END=0xFFFF CODEPAGE NAME=idlocs START=0x200000 END=0x200007 PROTECTED CODEPAGE NAME=config START=0x300000 END=0x30000D PROTECTED CODEPAGE NAME=devid START=0x3FFFFE END=0x3FFFFF PROTECTED CODEPAGE NAME=eedata START=0xF00000 END=0xF003FF PROTECTED START=0x0 END=0x5F ACCESSBANK NAME=accessram DATABANK NAME=BIG_BLOCK START=0X60 END=0XDFF ACCESSBANK NAME=accesssfr START=0xF60 SECTION ROM=config NAME=CONFIG STACK SIZE=0x60 END=0xFFF PROTECTED RAM=BIG_BLOCK CAMBIO EN EL CÓDIGO DE LA TAREA IdleTask Este archivo no se modificó en su totalidad. El cambio mostrado a continuación representa solo a la IdleTask, que hace parte del archivo tasks.c propio de freeRTOSTM. Código Original (Para cualquier aplicación) /*----------------------------------------------------------* The Idle task. *----------------------------------------------------------*/ static void prvIdleTask( void *pvParameters ) { /* Stop warnings. */ ( void ) pvParameters; for( ;; ) { /* See if any tasks have been deleted. */ prvCheckTasksWaitingTermination(); if( sUsingPreemption == pdFALSE ) { /* If we are not using preemption we keep forcing a task switch to see if any other task has become available. If we are using preemption we don't need to do this as any task becoming available will automatically get the processor anyway. */ taskYIELD(); } } } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */ 96 Código Modificado (Para BESA-ME) /*----------------------------------------------------------* The Idle task. *----------------------------------------------------------*/ static void prvIdleTask( void *pvParameters ) { /* Stop warnings. */ ( void ) pvParameters; if(NUM_OF_CONTAINERS>1) { Config_Extern_Communication(); } if(CONTAINER_ID==0X60) { OpenTimer_4(); } for( ;; ) { /* See if any tasks have been deleted. */ prvCheckTasksWaitingTermination(); if( sUsingPreemption == pdFALSE ) { /* If we are not using preemption we keep forcing a task switch to see if any other task has become available. If we are using preemption we don't need to do this as any task becoming available will automatically get the processor anyway. */ taskYIELD(); } } } /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */ Proyecto Final de BESA-ME en MPLAB La inclusión en el proyecto de MPLAB de archivos propios de BESA-ME implica la inclusión de los archivos .h. El anexo A (manual de usuario) muestra cuales son los archivos que debe contener el proyecto que el programador debe incluir para su aplicación. main_besa que se muestra a continuación. /************************************************************** BESA-ME v. 1.0 - Junio 2005 PONTIFICIA UNIVERSIDAD JAVERIANA-INGENIERÍA ELECTRÓNICA David Magín FLÒREZ RUBIO Juan Manuel ORTIZ GÓMEZ Guillermo Andrés RODRÍGUEZ CANTOR 97 Uno de estos archivos es el BESA-ME v. 1.0 Fue desarrollada sobre freeRTOS (marca registrada) **************************************************************/ /* Scheduler include files. */ #include "projdefs.h" #include "portable.h" #include "task.h" #include "semphr.h" /* Demo app include files. */ #include "partest.h" /* BESA-ME include files. */ #include "public_besa.h" #include "user_besa.h" /* Creates the tasks, then starts the scheduler. */ void main( void ) { /* Initialise the required hardware. */ vParTestInitialise(); vPortInitialiseBlocks(); /* Initialise BESA (agents, beahviors, events, etc). */ SetupContainer(); Inicio(); /* Start the scheduler. Will never return here. */ vTaskStartScheduler( portUSE_PREEMPTION ); } /*-----------------------------------------------------------*/ CAMBIO EN EL CÓDIGO DE PORTMACRO.h Las siguientes líneas corresponden a una de las secciones de configuración de freeRTOS en el archivo portmacro.h, adecuadas para el contexto de este proyecto. /* These are the only definitions that can be modified!. */ #define portUSE_PREEMPTION 1 #define portTICK_RATE_HZ ( ( portTickType ) 1000 ) #define portCPU_CLOCK_HZ ( ( unsigned portLONG ) 20000000 ) #define portMAX_PRIORITIES (1) #define portMINIMAL_STACK_SIZE ( 110 ) #define portGLOBAL_INT_ENABLE_BIT 0x80 #define portTOTAL_HEAP_SIZE ( 3100) 98