5.5 Lifting collections
7.2.4 Lessons for language embedders
Debido a nivel de versatilidad a la que se apunta como parte de los objetivos. El programa principal es un simple recolector de tareas pendientes. Ya que la red está a orientada a la comunicación todas las tareas básicamente se realizarán en pequeñas maquinas de estado teniendo la capacidad de quedar en algún estado congeladas mientras entradas o salidas de datos por el nrf_24L01 son requeridas.
El programa principal llama diferentes librerías con diferentes funciones implementadas exclusivamente para este proyecto. Por esta razón primero se explicará en orden desde la librería base hasta el “main()” (aplicación) de acuerdo a la gráfica mostrada a continuación. En la implementación capas superiores no utilizan o “descontinúan” funciones de capas inferiores pero estas igual serán documentadas ya que permiten el rastreo de errores. Y fueron utilizadas en todo momento durante las pruebas.
76
Hasta la siguiente sección se omiten detalles sobre cómo las funciones descritas influyen en los protocolos de comunicación creados para este proyecto. Estos protocolos serán descritos de forma puntual en su sección correspondiente.
Esta es la librería que STMicroelectronics provee para desarrollar programas en los microcontroladores que tiene en venta. En estos archivos están todas las definiciones y sub librerías necesarias para utilizar cualquier periférico interno de la familia de microcontroladores smt32f10x. Para este proyecto solo se usaron los periféricos GPIOA, GPIOB, SPI1, NVIC.
nrf_24L01.c:
Esta librería contiene todos las funciones definiciones básicas para que el micro controlador interactúe con el hardware nrf_24L01. Funciones de escritura y lectura de registros por spi se encuentran en esta librería. También hay funciones de configuración del módulo de radio frecuencia.
Función stm32f10x_nrf24l01(void): utilizando la librería propia del micro controlador se configuran las salidas y entradas de propósito general. GPIOA para el nrf_24L01. Líneas 4 5 6, 7, 3 y GPIOB_0 para chip_select, clock,
MasterInSlaveOut, MasterOutSlaveIn, chipEnable y interrupción
respectivamente. Se configuran los registros del periférico SPI. El periférico trabajará en modo a dos líneas fullplex, modo maestro, tamaño de dato 8bits, bit más significativo por delante y el reloj de sincronización por defecto en bajo.
77
Función SPI2_readWrite(unsigned char byte): Función de intercambio de bytes para el spi, devuelve como unsigned char el valor intercambiado con el periférico externo.
Función SPI2_readReg(unsigned char reg): Funcion basada en
SPI2_readWrite devuelve un byte leído de la dirección ingresada como argumento.
Función pollute_channel(unsigned char channel): Activa por comandos SPI la función de generar ruido en el canal. Esta función es utilizada para saber si el nrf_24L01 esta transmitiendo en el canal asignado.
Función detect_carrier(unsigned char channel): Lee el valor del periférico externo que indica si el canal de trabajo está siendo ocupado por otra fuente de transmisión.
Función put_packet(unsigned char *buffer, unsigned char *addr, unsigned
char channel): ingresa un paquete al buffer de salida del transceptor y espera
a que termine de emitirlo. En primer argumento será el buffer que necesariamente debe ser de 32 bytes, se indica la dirección a la que se enviará el paquete (segundo argumento) y se indica por cual canal se ha de enviar (tercer argumento).
Funcion get_packet(unsigned char *buffer,unsigned char pipe_x, unsigned
char channel,int timeout): Recoge UN solo paquete del buffer de recepción, si
se desea retirar mas paquetes es necesario utilizar otra vez la función. Retorna en formato de entero con signo 1 si logro sacar un paquete, cero si no encontró paquete que retirar del buffer. La función cuenta con un bloque de seguridad
78
(bandera timeout_flag) para dejar de esperar un paquete en caso no previsto este ocurriendo. Esta uso de esta bandera está diseñada para tener un medio de escape en caso esta función se use como mono tarea, similar a un scanf(). El programa principal ya no utiliza este medio de seguridad ya que revisa el buffer por interrupción.
Función CONFIGURE_NRF(unsigned char *raw_address,unsigned char
*net_address): Escribe en la memoria del nrf_24L01 las direcciones de las
entradas de datos 0 y 1 ( datapipe_0, datapipe_1) net_addr y raw_addr respectivamente.
Función nrf_control( int arg ): función que recibe como argumentos las macros “listen” y “stop_listen”. Estas macros representan valores para apagar el modulador de nrf_24L01 y encenderlo de nuevo. Utilizado antes de cambiar cualquier información relacionada con envíos en el módulo.
dome_stack.c:
Esta librería contiene todas funciones para establecer comunicaciones de capa 2 y 3. También contiene las funciones de mantenimiento controlar los reintentos, éxitos y fracasos de comunicaciones. Esta librería cuenta con las definiciones utilizadas para los primeros protocolos de comunicación equivalentes a capas 2 y 3. Estos protocolos serán explicados en otra sección de este documento a detalle a detalle.
79
Función test_success(void): function de prueba. Imprime “:)!!!”.
(descontinuada)
Función show_comms(comm_list_item *comm_list): Muestra las
comunicaciones pendientes. Sera explicado más adelante junto con los protocolos.
Función control_comms(comm_list_item *index): Atiende las
comunicaciones previamente ingresadas, estas función atiende una comunicación a la vez, al terminar de atenderla retorna uno. Comm_list_item es una estructura que contiene los datos de una comunicación. Será detallada en la sección de protocolos. Es esta la función que se encarga de retransmitir paquetes o reintentos pendientes.
Función clean_comms(comm_list_item **comm_list): Elimina
comunicaciones caducadas o ya terminadas.
Función flag_ticks(comm_list_item *flag_list): Resta los contadores de inicio de envío o timeouts de las comunicaciones pendientes.
Función add_cf(void (* fun)(int),unsigned char *contenido,unsigned char
q,unsigned char *flags): Añade un elemento a la lista de comunicaciones
ingresando un id aleatorio, un tiempo de 100 milisegundos, timeouts indicados como argumento (q), y una función de que recibiría como argumento 1 si la la comunicación es exitosa y -1 en caso no lo sea.
80
Función set_ack(comm_list_item *list,unsigned char id): Levanta el flag de “served” de una comunicación cuyo id sea igual al del argumento ingresado.
Función layer_3_send(unsigned char *data): Coloca un paquete en el buffer de salida del módulo de radiofrecuencia con la dirección correspondiente en base al contenido del argumento ingresado: el paquete armado. Esta función ya cuenta con los criterios correspondientes para interpretar los protocolos de capa 2 y 3 escritos en el paquete. Cualquier salida de paquete hacia el nrf_24L01 se hace a través de esta función.
discovery.c
Esta librería tiene codificados los handlers y variables para el protocolo de discovery.
app_layer.c
App_layer.c cuenta con todas las funciones y estructuras necesarias para enviar o tratar comandos puntuales a nivel de aplicación. No es conveniente describir las funciones puntuales debido a que el código esta desarrollado para agregar más de 256 instrucciones puntuales y variables. En esta librería se definen y agregan todas las funciones que podrían necesitarse para una aplicación. El handler está definido como “int (*comandos_app[])(unsigned char *);” en este arreglo de funciones están añadidas funciones básicas como prender o encender Leds o GPIOs en las tarjetas. Es este el handler que podría ser direccionado a cualquier paquete de funciones de acuerdo perfil sin tener que modificar el resto del programa.
81
main.c
Una vez explicado las librerías base ya es posible hablar un poco del código del programa principal. Debido a que el programa estas centrado en llamadas a interrupciones, el programa principal se comporta como un gran reloj para pequeñas maquinas de estado cuyos etapas son movidas por interrupciones producidas por usuario: comandos seriales, o comandos externos: transmisiones de otros nodos.
En la primera etapa del programa nombrada INICIO en el diagrama mostrado se configuran los relojes y periféricos internos y externos necesarios para la operación adecuada del nodo.
En la etapa init_all_periph se configuran los periféricos internos, esta etapa es completamente secuencia y no posee ningún bucle interno. De igual forma siguen external_hw_setup y Systick_Config. Este último habilita los ticks de un reloj interno en el micro controlador.
Pasado un anuncio de seguridad se entra al bucle principal en donde se encuentran todos los handler a nivel de aplicación.
La primera sección encontrada es la de comandos o funciones de soporte escritas por la línea de comandos. De forma asíncrona se presenta el diagrama de flujo del la interrupción por serial.
Una vez activada com_call el main() entenderá este bloque siempre y cuando el primer carácter ingresado en la cadena no sea “#”, al finalizar com_call será desactivado y se seguirá con las siguientes banderas. El paquete de funciones en esta sección permitió desarrollar las pruebas para avanzar el desarrollo de
82
los nodos. Aún son funciones vigentes para la búsqueda de errores en las últimas versiones.