Sunteți pe pagina 1din 42

Bitcloud es la última generación de software embebido totalmente funcional de

Atmel para Zigbee.


La pila proporciona una plataforma de desarrollo de firmware seguro y de
confianza para aplicaciones wireless que corren en hardware Atmel. Bitcloud ha
sido diseñado para soportar un extenso ecosistema de aplicaciones de usuario
que atienden a diversas necesidades y que permiten un amplio espectro de
personalización

Bitcloud se ha desarrollado para cumplir con las expecificaciones de ZigBee y


Zigbee PRO de sensorización y control wireless.

(pag6)

2 Arquitectura de de la pila BitCloud

2.1 Lineas Generales de la Arquitectura Bitcloud

La arquitectura interna de BitCloud persigue la separacion de la pila de red en


las capas lógicas descritas por la IEE802.15.4 y la especificación Zigbee. A
pesar de que el núcleo de la pila contiene la implementación propia del
protocolo, BitCloud contine capas adicionales que implementan los servicios
compartidos ( por ejemplo, la seguridad, el task manager, y el power
manager), la capa de abstración hardware (Hardware Abstraction Layer → HAL)
y el paquete de soporte a la placa (Board Suppoprt Package → BSP). Las API's
proporcionadas por estas capas están fuera del ámbito de la funcionalidad del
núcleo de la pila. Sin embargo, estas capas adicionales ayudan a reducir
significativamente la complejidad y simplifican la integración. El manual de
referencia del API de BitCloud da información detallada tanto de todas las API's
públicas como de su uso.
La capa más alta del núcleo de la pila, APS, proporciona el nivel visible de
aplicación más alto relacionada con la API de networking . ZDO proporcionada
un set totalmente compatible con la API de Zigbee Device Object(ZDO) que
permite el manejo principal de la red (iniciarla, resetearla, formarla, unir
elementos...). ZDO también define el tipo de dispositivo Zigbee y mantiene los
comandos de red que implementa la pila

(Pag 7)
Se incluye tres servicios verticales: el task manager, la seguridad, y el power
manager. Estos servicios están disponibles para el aplicación de usuario, pero
también pueden ser utilizados por las capas más bajas.

El Task Manager, que es el scheduler de la pila, gestiona el uso del MCU por los
componentes internos de la pila y por la applicación de usuario. El Task
Manager implementa un scheduler cooperativo basado en prioridad
especifícamente diseñado para el tipo de pila multicapa y las demandas de
tiempo crítico de los protocolos de red.

Las rutinas del “power manager “ son las responsables del apagado de todos
los componentes de la pila y el salvado del estado del sistema cuando éste se
echa a dormir y de sus restaurado cuando éste se levanta

El HAL incluye una set completo de API's para el uso de los recursos (EEPROM,
sleep, y watchdogs) asi como de los drivers...

BSP incluye un set completo de drivers para el manejo de periféricos estandar


incluidos en una placa de desarrollo.

2.2 Convenio de Nombres

Para manejar el alto numero de funciones de API disponibles al usuario, se


emplea una conveccion de nombres que simplifique la tarea de manejar y
comprender las aplicaciones de usuario. Estas son sus reglas básicas:

1. El nombre de cada función del API lleva el prefijo de la capa en la cual


reside. Por ejemplo la función ZDO_GetLqiRssi reside en la capa ZDO de
la pila
2. Cada prefijo del nombre es seguido por un guion bajo, _, que separa el
prefijo del nombre descriptivo de la funcionalidad
3. El nombre descriptivo de la función debe contener un prefijo Get o Set,
indicando si la función devuelve el parámetro solicitado o si ésta fija un
parámetro de la capa subyacente.
4. El nombre descriptivo de la función puede contener uno de los siguientes
sufijos:
1. Req o Request se corresponde con una solicitudo asícrona desde la
aplicación de usuario
2. Ind se corresponde con una indicación asíncrona o evento propagado
por la pila al espacio de usuario.
3. Los nombres terminados en Conf son callbacks definidas por el usuario
para peticiones asincronas que confirman la ejecución de una petición.
5. Cada nombre de tipo o estructura termina con un sufijo _t, indicativo de
tipo.
6. Los nombres de variables enumeradas y de macros van siempre en
mayusculas.

(Pag 8)

2.3 Layout del sistema de ficheros

El layout del sistema de ficheros sigue la arquitectura de la pila, con algunas


carpetas extras que constituyen las subcapas añadidas. Entre los componentes
distribuidos en forman de binarios, se incluyen los directorios “lib” e “include”
que contienen los ficheros de cabecera y las librerias. Entre los componentes
distribuidos en forma de código fuente se incluyen los subdirectorios “obj” y
“src”. El fichero Makefile continen el script necesario para construir dichos
componentes.

Las aplicaciones se proporcioanan siempre como ficheros fuente y ficheros


cabecera, el script Makefile, así como los ficheros de proyecto para los IDEs
soportados. La misión pricipal del Makefile es compilar la apllicación usando los
ficheros de cabecera que se encuentran en los respectivos directoriso de
compoennetes y linkar el fichero objeto resultante con las librerias. El
resusltado de la image binaria es una aplicación de compilación cruzada que
pude ser grabada y depurada en la plataforma final. Para más información
sobre cómo modificar el del entorno de desarrollo y compilación se debe
consultar [4]

Carpeta Codigo Descripción


fuente
presente?
BitCloud Raiz de la pila
Components
APS No Subcapa de soporte a la aplicación
BSP Si Drivers de referencia para placas de desarrollo
soportadas
ConfigServer Si Subcapa para almacenamiento de parámetro
genéricos
HAL Si Drivers de referencia para plataformas
soportadas
MAC_PHY No Capas fisica y de control de acceso al medio
NWK No Capa de red
PersistDataServ Si Acceso a EEPROM y al manejo de parámetro
er persistentes
Security No Servicios de seguridad
SystemEnviron No Función Main y Task Manager
ment
ZDO No Subcapa Zigbee Device Object
WSNDemo Si Aplicación completa para que demuestra la
adquisición de datos, seguridad y el power
management.
(Pag 09)

3 Programando aplicaciones de Usuario

3.1 Programación basada en eventos

Los sistemas de basados en eventos son un paradigma de programación muy


comunos en sistemas embebidos de pequeño tamaño en los que existe una
significativa limitación de memoria y un pequeño espacio para el
desenvolvimiento de todo el sistema operatibo. Programación basada en
eventos hace referencia a la arquitectura y estilo de programación basados en
pares de invocaciones de una función API funto con una notificación asícrona
resultado de la llamada a la API.....
En lenguaje de programación esto significa que la aplicación de usuario provee
unas capas subyacente con un puntero a función, que las capas más altas
llaman cuando una petición es atendida.

En un sistema completamente basado en eventos, todo el codigo de usuario se


ejecuta en callbacks

(Pag 10)

3.2 Mecanismo de Peticion/Confirmación e Indicación

Todas las aplicaciones basadas en el SDK de BitCloud se escriben en un estilo


de programación basada en eventos. De echo todas la interfaces internas de la
pila son definidas en terminos de solicitudes y su correspondiente callback.
Cada capa define un numero de callbacks para ser invocadas por capas
inferiores, e invoca callbacks definidas por capas superiores. Existe un tipo
genérico de callbacks definidas por el usuario que son responsables de la
ejecución del codigo de la aplicación que son ejecutadas por el task hadler.
APL_TaskHandler es el nombre reservado a la callback que la pila conoce como
task handler.

El mecanismo de petición/confirmación es una instancia particular del modelo


de programación basado en eventos. La petición es una llamada asícrona a la
pila subyacente para ejecutar una acción en medio de la aplicación de usuario.
La confirmación es el callback que se ejecuta cuando dicha acción es
completada y el resultado de esa acción está disponible.

El mecanismo de Petición/Confirmación es una instancia particular del modelo


de programación basado en eventos. Puesto de forma simple, una petición es
una llamada asícrona a la capa subyacente para ejecutar una acción en medio
de la aplicación de usuario; la confirmación es la función de callback que se
ejecuta cuando dicha acción se ha completado y el resultado está disponible
para la aplicación usuario

Por ejemplo considerese la petición ZDO_StartNetworkReq(&networkParams),


que solicita a la capa ZDO iniciar la red. El argumento networkParams es un
struct definido en zdo.h como ZDO_StartNetworkReq_t:

typedef struct
{
ZDO_StartNetworkConf_t confParams;
void (*ZDO_StartNetworkConf)(ZDO_StartNetworkConf_t *conf);
} ZDO_StartNetworkReq_t;

El primer campo es una estructura que se utiliza para la devolver una


respuesta desde la pila (los parámetros actules de la red) a la petición. El
último campo es un puntero a función con el valor de la callback actual. La
petición ZDO_StartNetworkReq(&networkParams) está emparejada con una
función de callback definida por el usuario que corresponde a la siguiente
declaración

static void ZDO_StartNetworkConf(ZDO_StartNetworkConf_t *confirmInfo)


{
}

por lo tanto la petición debe ser precedida de una asignación del puntero de
callback:

networkParams.ZDO_StartNetworkConf = ZDO_StartNetworkConf;

Este ejemplo ilustra una instancia particular del uso del mecanismo petición/confirmación, pero
todos usos siguen el mismo proceder.

Fijese en que la necesidad de desacoplar la petición de la respuesta es especialmente importante


cuando la petición puede tomar una cantidad de tiempo no especificada. Por ejemplo, cuando se
solicita el inicio de la red, las capas subyacentes puede realizar un escaneo que puede tomar un
cantidad de tiempo significativamente mayor que el que estamos dispuestos a esperar bloqueados.
Solo algunas llamadas al sistema, especialmente aquellas cuyo tiempo de ejecución es previsible,
son síncronas. También las llamadas de una funcion definida por el usuario a otra son síncronas.

Aparte de los pares petición/confirmación, hay casos en los que la aplicación necesita ser avisada de
la existencia de un evento externo. Estos casos no son una replica a una petición especifica. Para
estas situaciones, existen la posibilidad de crear callbacks definidas por usuario con un nombre
especifico que son invocadas por la pila de forma asícrona. Entre estas se encuetran los eventos para
indicar la perdida de conectividad, la disposición de una subcapa para echarse a dormir, o la
notificación de que el sistema está ya en pie.

(Pag 11)
Regla 1: todas las aplicaciones de usuario se organizan en un conjunto de callbacks que se ejecutan
al termino de una solicitud a la capa subyacente.
Regla 2: La aplicación del usuario es la responsable de declarar las callbacks que maneja los
eventos no solicitados del sistema que interesen.

3.3 Planificador de tareas, prioridades y desalojo.

Un aspecto importante del desarrollo de aplicaciones es la gestión del flujo de programa y el


aseguramiento de que las diferentes partes de la aplicación no interfieren con otras en ejecución. En
aplicaciones no embebidas, el sistema operativo gestiona tipicamente en el acceso a los recursos del
sistemas y coordina, por ejemplo, que toda aplicación reciba su parte equivalente de recursos.
Debido a la multiple concurrencia de aplicaciones que coexisten en el mismo sistema ( algo
conocido como multitasking), un sistema operativo como windows es muy complejo en
comparación a un sistema monotarea como es BitCloud. En el contexto de BitCloud, sólo hay una
tarea ejecutandose en la cima de la pila, de modo que la pelea por obtener los recursos del sistema
no se da entre aplicaciones simultaneas sino entre la aplicación de usuario y la pila que hay por
debajo. Ambas, pila y aplicación deben ejecutar su codigo en el mismo microcontrolador.

En contraste con S.O. con desalojo en los cuales es más adecuado un manejo múltiple de
aplicaciones que sin embargo requiere una mayor sobrecarga de éstos, los sistemas multitarea
cooperativos son más livianos. Sin embargo, requieren una cooperación entre la aplicación y el
sistema operativo. Los sistemas con desalojo dividen el tiempo de CPU entre las diferentes
aplicaciones (multiplexando por lo tanto transparentemente la CPU) de modo que a los
desarrolladores les parezca que sus aplicaciones tienen el control exclusivo de la CPU. En cambio
una aplicación corriendo en un sistema multitarea cooperativo debe ser cuidadosa con la necesidad
de ceder los recursos de los que dispone (principalmente, la CPU) a la capa subyacencte. Otro
beneficio es que solo se necesita una capa. Lo que se traduce en un ahorro considerable de
memoria.

Volviendo al ejemplo de petición/confirmación, si ZDO_StartNetworkConf (una callback de


usuario) se toma un tiempo muy largo en ejecutarse el SO estará bloqueando esperando que la
callback le devuelva el control. Tenga en cuenta que las callback corren bajo la prioridad de la capa
envolvente. Asi que ZDO_StartNetworkConf corre bajo el nivel de prioridad ZDO. Los usuarios
deben ser cautos ejecutando largas secuencias de instrucciones, incluido instrucciones en funciones
anidadas, en el entorno de una callback invocadada desde otra capa.

Regla 3: Todas las callbacks de usuario se debe ejecutar en menos de 10 ms


Regla 4: Las callbacks corren bajo el nivel de prioridad de la capa envolvente.

La estrategia para que las callbacks se ejecuten en menos de 10 ms es aplazar su ejecución. La


ejecución aplazada es una estrategia que parte del contexto de ejecucion entre la callback y el
planificador de tareas. El modo de conseguir una ejecución aplazada es preservar el estado de la
aplicación y fijar una tarea en la cola de tareas con la llamada:

SYS_PostTask(APL_TASK_ID);

La acción de fijar un tarea es síncrona, y el efecto de la llamada es notificar al planificador que en la


cola de tareas hay una tarea aplazada por ejecutar. Para la aplicación usuario, la cola de tareas se
identifica siempre por APL_TASK_ID. El resultado de fijar una tarea es crear una llamada aplazada
al manejador de tareas APL_TaskHandler, que, a diferencia de otras callbacks, corre bajo el nivel de
prioridad de la aplicación.

(Pag 12)
En otras palabras, el manejador de tareas de la aplicación corre solo cuando todas las capas de
mayor prioridad se han completado. Esto permite tiempos de ejecución mayores en el contexto del
manejador de tareas, que en el contexto de la callback.

Regla 5: El manejador de tareas de la aplicación corre solo cuando todas las capas de mayor
prioridad se han completado

Regla 6: El manejador de tareas de la aplicación debe ejecutarse en menos de 50ms

Otras ID de tareas interesantes son HAL_TASK_ID y BSP_TASK_ID, que hacen referencia a las
tareas pertenecientes a la capa de abstración hardware y al paquete de soporte de la placa. Cuando la
aplicación de usuario conlleva modificaciones en las capas HAL o BSP, en la ejecución aplazada de
callbacks de HAL o BSP debe utilizarse estos ID.

3.4 Aplicaciones con Timers

Hasta ahora, las tres formas de que el control de flujo se introdujera en el codigo de aplicación eran:
(1) a través del manejador de tareas a continuación de una invocación de SYS_PostTask, (2) a
través de la callback de confirmación invocada por la capa subyacente tras la ejecución de una
solicitud, y (3) a través de notificaciones de eventos asíncronos invocados por el SO. Hay que tener
en cuenta que para ninguno de tres metodos existe un momento en el cual se sabe va a ser
ejecutado. Una forma de asegurarse la ejecución de una callback definida por el usuario en un
momento específico del futuro es el uso de timers.

La pila provee de un interfaz de alto nivel para timers, que hace uso de un timer hardware de bajo
nivel. Dicha interfaz es parte del HAL y su uso esta ilustrado en muchas aplicaciones de usuario
( BlinkApp.c). La idea general es que una estructura HAL_AppTimer_t contiene el intervalo del
timer, (ya sea un timer cíclico o que se dispara una sola vez) y la función de callback a ejecutar
cuando el timer se dispara. La estructura se debe pasar a HAL_StartAppTimer y a
HALStopAppTimer para iniciar y parar el timer.
3.5 Concurrencia e interrupciones
El concurrencia es el término que se utiliza para referirse a los distintos threads independendientes
que se ejecutan a la vez. En un sistema que utiliza desalojo con multiplexado en el tiempo de la
CPU y en el cual corren multiples treads, la ejecución de una función puede ser interrumpida por el
planificador del sistema en un punto aleatorio, dando el control a otro thread en ejecución que
potencialmente puede ejecutar una función diferente de la misma aplicación. Debido a la
imposiblidad de predecir una interrupción y al hecho de que dos funciones pueden compartir datos,
el desarrollador debe asegurarse que el acceso a datos compartidos sea totalmente atómico.

Como se explicó previamente, en una aplicación BitCloud un único thread se comparte para
ejecutar la aplicación y el S.O. Cuando este thread realiza una tarea en una capa de la pila, éste
adquiere la prioridad de la capa, pero éste es siempre el mismo. Simplemente está ejecutando un
secuencia de funciones (no intercaladas entre ellas) de las diferentes capas de la pila y la aplicación.
Por lo tanto el control del flujo de ejecución no puede encontrarse en más de un callback de usuario
en un mismo tiempo. En general, la ejecución de multiples callbacks no puede ser intercalada, cada
callback se ejecuta como un bloque de código atómico.

(Pag 13)
A pesar de que el multiplexado de CPU no se usa, hay condiciones especiales donde se puede crear
otro thread de control. Ocurre cuando emerge una interrupción hardware, que puede interrumpir la
ejecución en un punto arbitrario ( el principal thread de control debe estar ejecutando codigo de la
pila o de la aplicación cuando esto ocurre ) para gestionar un evento físico proveniente de un
periferico del MCU. ( p.e. La USART o el canal SPI). Esto es análogo al manejo de interrupciones
hardware en otro tipo de sistemas.
En la anterior figura se ilustra un ejemplo de interacción entre la aplicación, la pila, el planificador
de tareas, y las interrupciones hardware. En un principio el planificador ejecuta una tarea mediante
la llamada a APL_TaskHandler. Cuando la aplicación usuario se está ejecutando, ésta es
interrumpida por un evento hardware ( en gris). A la función que se ejecuta con la llegada de la
interrupción se la denomina servicio de interrupción. Tras la ejecución del servicio de interrupción,
se devuelve el control a la aplicación de usuario, y una vez que ésta última termina, el control es
devuelto a planificador de tareas. Éste selecciona una tarea de la capa MAC para ser ejecutada a
continuación. Mientras la función MAC_TaskHandler corre, invoca una callback de confirmación
en la capa ZDO que es interrumpida por otro evento hard. Notese que la capa MAC invoca otra
callback en ZDO que a su vez invoca otra callback registrada por la aplicación de usuario. Por lo
tanto este último callback se ejecuta con la prioridad de la capa MAC o MAC_TASK_ID.

Las aplicaciones BitCloud puede crear rutinas de servicio de interrupción que se ejecuten con la
llegada de un evento hardware. Esto se usa, típicamente, para la gestión de perifericos adicionales
cuyos “drivers” no son parte del SDK … y son, en cambio, añadidos por el usuario. La llamada para
definir un servicio de interrupción es

HAL_RegisterIrq(uint8_t irqNumber, HAL_irqMode_t irqMode, void(*)(void) f);

irqNumber es el identificador correspondiente a una de las lineas IRQ hardware disponibles,


irqMode especifica cuando el servicio de la interrupción hardware se puede ejecutar, una vez el
evento se ha notificado, y f es la callback definida por el usuario como servicio de interrupción.
Naturalmente, la ejecución de un servicio puede ser interrumpida por la ejecución de otra callback.
Así que si el servicio tiene acceso a una variable global que puede ser modificada por otra callback,
este acceso a la variable compartida se debe realizar en acciones atómicas. Si existe un fallo en la
ejecución un acceso atómico, este puede desencadenar una condición de carrera.

(Pag 14)
El acceso atómico se puede asegurar dividiendo cada acceso individual con las macros
ATOMIC_SECTION_ENTER y ATOMIC_SECTION_LEAVE. Estas macros inician y terminan los
que se conoce como una sección crítica, un bloque de código que ininterrumpible. Estas macros
operan desabilitando las interrupciones hardware. Las secciones debe ser lo mas cortas posibles
para reducir el tiempo que las interrupciones hardware son enmascaradas. En los
microcontroladores AVR mediante el uso de flags, las interrupciones enmascaradas son salvadas
para gestionarlas más adelante.

Regla 7: Las secciones críticas no deven sobrepasar los 50us de duración.

3.6 Estructura típica de una aplicación


La estructura de una aplicación BitCloud es significativamente diferente a la de un típico programa
en C que se ejecuta en una plataforma no embebida. Como anteriormente se dispuso:

1 Cada aplicación define un unico gestor de tareas de aplicación, que contiene el total del
código de la aplicación de usuario ( incluido el código accesible a través llamadas a
subfunciones)

2 Toda aplicación define un numero de callbacks que se ejecutan cuando se completa una
petición asíncrona de la capa subyacente.

3 Toda aplicación define un numero de callbacks de nombres conocidos que se ejecutan con
el procesamiento de un evento por la pila

4 Toda aplicación mantiene un estado global que es compartido ente las callbacks y el
manejador de tareas de usuario.

La función main está embebida dentro de la pila. Una vez la pila se inicializa, el control es
transferido de main a planificador de pila, que comienza a invocar, los distintos manejadores de
tarea en un order de prioridad ( de mas alto a más bajo), invocando eventualmente al
APL_TaskHandler, que es el punto de entrada a la aplicación. Tras la llamada inicial al manejador
de tareas de la aplicación, el control es transferido continuamente entre la pila y las callbacks como
se ha mostrado en la figura anterior.

Una aplicación puede ser dividida en un conjunto de archivos escritos en C. Para simplificar, aquí
se considera la existencia de un único archivo.

/*******************************
#include directives
*******************************/
...
#include <taskManager.h>
#include <zdo.h>
#include <configServer.h>
#include <aps.h>
/*******************************
FUNCTION PROTOTYPES
*******************************/
...
/*******************************
GLOBAL VARIABLES
*******************************/
AppState_t appState = APP_INITING_STATE;
...
/*******************************
IMPLEMENTATION
*******************************/
/*******************************
Application task handler
*******************************/
void APL_TaskHandler()
{
switch (appState)
{
case APP_IN_NETWORK_STATE:
...
break;
case APP_INITING_STATE: //node has initial state
...
break;
case APP_STARTING_NETWORK_STATE:
...
break;
}
}

/*******************************
Confirm callbacks
*******************************/
static void ZDO_StartNetworkConf(ZDO_StartNetworkConf_t *confirmInfo)
{
...
if (ZDO_SUCCESS_STATUS == confirmInfo->status)
{
appState = APP_IN_NETWORK_STATE;
...
SYS_PostTask(APL_TASK_ID);
}
}

void ZDP_LeaveResp(ZDP_ResponseData_t *zdpRsp)


{
...
}

/*******************************
Indication callbacks
*******************************/
void ZDO_WakeUp_Ind(void)
{
...
if (APP_IN_NETWORK_STATE == appState)
{
appState = APP_STARTING_NETWORK_STATE;
...
SYS_PostTask(APL_TASK_ID);
}
}

void ZDO_MgmtNwkUpdateNotf(ZDO_MgmtNwkUpdateNotf_t *nwkParams)


{
...
}

(Pag 16)
El anterior esqueleto de código es representativo de la mayoria de aplicaciones.

Invariablemente, hay un estado global, representado en este caso por la variable appState al cual
acceden desde las callbacks y desde el manejador de tareas. En aplicaciones del mundo real, el
estado se representa por un determinado número de variables. Adviertase que un típico manejador
de tareas cambia el estado de las variables al ejecutar código para un estado particular, que es una
plantilla de programación compartida por todas las aplicaciones ejemplo incluidas en el SDK. El
desarrollador debe primero considerar su aplicación en términos de máquina de estados. El
mapeado de esa máquina de estados es el método natural de programación basada en eventos.

Tengase en cuenta también el uso de la función del gestor SYS_PostTask. p.e. la aplicación aplaza
a propósito el procesamiento de la indicación de pérdida de conectividad.(:::). La callback
simplemente cambia el valor de la variable de estado appState y devuelve el control a la capa desde
la que fue invocada (ZDO). Este estilo de programación es totalmente consistente con un sistema
multitarea cooperativo, y permite a la pila manejar tareas de una prioridad más alta antes de
devolver el control a la tarea aplazada
(Pag 17)

4 La interfaz ConfigServer

la pila de BitCloud provee de un extenso set de parámetros de configuración que determinan los
diferentes aspectos del comportamiento de la red y sus nodos. Estos parámetros son accesibles a
través de la interaz ConfigServer (abreviado CS). Este capitulo introduce ligeramente la interfaz
CS. Un completo listado y descripción se puede encontrar en la documentación de la API.

Todos los parámetros CS se pueden dividir en dos categorias: persistentes y no persistentes. Los
persistentes se almacenan en la memoria EEPROM y sus valores son accessibles por la aplicación y
la pila tras el reset HW del nodo. Los parámetros no persistentes son almacenados en la memoria
RAM y tras un reset HW son reinicializados a sus valores por defecto. El fichero ConfigServer.h
incluye un comentario seguido de cada ID de parámetro indicando si éste es persistente o no.

4.1 Leyendo/escribiendo parámetros CS


ConfigServer.h contiene la definición de todos los parámetros CS y su valores por defecto.
Sin embargo, si es necesario la aplicación puede de asignar nuevos valores a los parámetros
mediante cualquiera de los métodos que se describen a continuación:
– Definiendolos en el Makefile de la aplicación
– Mediante funciones de lectura/escritura de CS

4.1.1 Definición de parámetros CS en el makefile


El método más simple para asignar un valor a un parámetro CS es definirlo en el makefile de la
aplicación. En este caso el valor por defecto asignado en configServer.h es obviado y el valor
asignado por el makefile es el que se aplica en el parámetro. Por ejemplo, al añadir la siguiente linea
al makefile, se fija la energía de emisión de RF en 3dBm:

+= -DCS_RF_TX_POWER=3

En las aplicaciones BitCloud las variables de entorno CFLAGS son automaticamente inicializadas
durante el proceso de compilación del proyecto de modo que el simple hecho de añadir la línea de
arriba es suficiente para asignar el valor deseado al parámetro.

A pesar de que el método es simple, solo permite la configuración del parámetro en tiempo de
compilación y no permite modificaciones en tiempo de ejecución.

4.1.2 Funciones de Lectura/Escritura


Para permitir la lectura/escritura en tiempo de ejecución ConfigServer provee de las
correspondientes funciones API: CS_ReadParameter y CS_WriteParameter. Ambas funciones
requieren del ID del parámetro y de un puntero a un valor de parámetro como argumentos. El ID de
parámetro identifica el a que parámetro se aplica la función y se construye añadiendo “_ID” al final
del nombre del parámetro.
(Pag 18)
El siguiente código ejemplifica como una aplicación puede leer y escribir el parámetro de energía
de salida de RF. (CS_RF_TX_POWER)

int8_t new_txPwr=3; // variable for writing new value


int8_t curr_txPwr; // variable for reading current value
CS_ReadParameter(CS_RF_TX_POWER_ID, &curr_txPwr);
CS_WriteParameter(CS_RF_TX_POWER_ID, &new_txPwr);
(Pag 19)

5 Un vistazo a la red

Como se vio con anterioridad la pila de BitCloud sigue la estructura de la especificación de Zigbee
PRO que permite a las aplicaciones interactuar directamente solo con las componentes APS y ZDO
del núcleo de la pila. Este enfoque simplifica significativamente el desarrollo de aplicaciones a la
vez que garantiza que la aplicación no interfiere en el protocolo de red y por lo tanto el
comportamiento siempre cumple la especificación Zigbee PRO.

En este capitulo se introducen brevemente las principales características de la red de la pila


BitCloud, y se describe las correspondientes interacciones entre la aplicación y el núcleo de la pila.

5.1 Creación y unión a una red

A pesar del uso del termino “inicio de red” desde el punto de vista de la aplicación no hay
diferencia entre los procedimiento que se sigue para crear un red y el que se sigue para unirse a ésta.
La aplicación BitCloud deberá ejecutar el procedimiento de red en los tres pasos que se describen
con detalle en esta sección:

1- Configurar los parámetros del nodo


2- Especificar los parámetros de la red
3- Realizar una petición de inicio de red
4- Recibir la confirmación de inicio de red

Adviertase que todos los parámetros CS mencionados en la sección 5.1 no se podrá modificar si el
dispositivo ya está unido a la red. Sin embargo los parámetros no mencionados en la sección 7.1 se
pueden modificar una vez el nodo ha abandonado la red.

5.1.1 Parámetros del Nodo

5.1.1.1 Tipo de Dispositivo

La especificación Zigbee diferencia entre tres tipos de dispositivos que pueden estar presentes en
una red: coordinador, router y dispositivo final.

• la principal responsablilidad del nodo coordinador (C) es la de formar la red con las
características deseadas. Tras la formación de la red otros nodos se pueden unir a ella vía el
coordinador o los routers ya presentes en la red. El nodo coordinador puede ejecutar
funciones de enrutado. Debido a que la dirección estática asociada al coordinador es
0x0000, solo un único dispositivo de este tipo es permitido en la red.

• Un nodo router (R) permite el envio transparente de datos a través de él desde otros nodos a
la dirección de destino. Pero por supuesto el también puede enviar su propia información. Al
igual que el coordinador el nodo router puede ser capaz de añadir nuevos nodos a la red.
• Un nodo final (ED) solo puede enviar y recibir datos que han sido reenviados hacia o por el
nodo destino a través de los nodos padres del nodo final al que actualmente esta asociado.
Solo los nodos finales tienen la capacidad de echarse a dormir.

(Pag 20)
El tipo de dispositivo se define por el parámetro CS_DEVICE_TYPE de tipo DeviceType_t. Este
parámetro se puede fijar a uno de los siguientes valores: DEVICE_TYPE_COORDINATOR (o
0x00) para el coordinador, DEVICE_TYPE_ROUTER (o 0x01) y DEVICE_TYPE_END_DEVICE
(o 0x02) para el router y el dispositivo final respectivamente.
Adicionalmente el parámetro booleano CS_RX_ON_WHEN_IDLE se debe fijar a true en los nodos
coordinador y router mientras que en los dispositivos finales que pueden echarse a dormir, este se
deberá fijar a falso para indicar la recepción indirecta mediante peticiones sonda como se describe
en la sección 5.3.4.1 El código que sigue a continuación es un ejemplo de como configurar un
dispositivo como nodo final:

DeviceType_t deviceType = DEVICE_TYPE_END_DEVICE;


bool rxOnWhenIdle = false;

CS_WriteParameter(CS_DEVICE_TYPE_ID, &deviceType;

5.1.1.2 Direccionado de un dispositivo

En concordancia con el standard Zigbee, cada dispositivo debe ser identificado


unívocamente mediante una dirección extendida (de 64 bits), también llamada
dirección MAC o dirección IEEE. En la pila BitCloud la dirección extendida se
determina con el parámetro CS_UID y como cualquier otro parámetro CS puede
ser fijado como se describe en la sección 4.1. Es la responsabilidad del usuario
el asignar una dirección única a cada dispositivo antes de ejecutar los
procedimientos de inicio de red.

Téngase en cuenta que en algunas placas entrenadoras (ejemplo, RZRaven, o MeshBean), si


CS_UID se fija a 0 en tiempo de compilación, la dirección extendida se asignará al valor obtenido
por el UID del chip EEPROM externo localizado en la placa, lo que asegura la unicidad de todos
los dispositivos que se tenga de la misma placa de desarrollo.

Cuando se une a una red Zigbee, cada dispositivo es identificado por lo que se conoce como
dirección corta (16 bits), también denominada como dirección de red (NWK). Esta es la dirección
usada en las cabeceras de cada frame durante el intercambio de datos.

En BitCloud las direcciones cortas puede ser seleccionadas aleatoriamente por la pila durante la
unión a la red o asignadas por la aplicación de usuario a un valor deseado antes de proceder a unirse
a una red. Es crítico asegurarse de que todos los nodos de la red usan el mismos mecanismo de
adquisición de dirección.

El parámetro booleano CS_NWK_UNIQUE_ADDR especifica si la dirección se asignará al unirse


a la red (false), o si el nodo ya especifica su dirección antes de unirse (true). En este último caso la
dirección deseada se asignará a CS_NWK_ADDR. Si se utiliza este tipo de mecanismo de
adquisición de dirección siempre se deberá dar el valor 0x0000 al coordinador de red, cosa que la
pila hace con el direccionamiento automático. Después de unirse a una red, un dispositivo puede
leer su propia dirección corta del campo shortAddr en el argumento de la función de callback
ZDO_StartNetworkConf registrada para la solicitud de inicio de red como se describe en la sección
5.1.3 Solicitud de inicio de red y confirmación

(Pag 21)
En el esquema de asignación automática aleatoria de dirección un mecanismo de resolución de
conflictos detecta y resuelve situaciones en las que la dirección escogida aleatoriamente parece no
ser única, como por ejemplo cuando se une a la red un nodo con las misma dirección ya presente en
la red. Despues de que la dirección de red es actualizada, la aplicación del nodo correspondiente es
informada vía ZDO_MgmtNwkUpdateNotf() con el status ZDO_NWK_UPDATE_STATUS
(0X8E) y el nuevo valor de dirección en el argumento. En redes de direccionamiento manual la
aplicación de usuario es la responsable de resolver dichos conflictos. Aún así, Bitcloud ofrece
asistencia en estos casos mediante la llamada a la función ZDO_MgmtNwkUpdateNotf() con el
status ZDO_STATIC_ADDRESS_CONFLICT_STATUS (0x95) en el nodo que ha detectado el
conflicto ( que puede diferrir del nodo que tiene el conflicto de dirección)

Adviertase que la organización de la red (topología) que se muestra en la figura 5-1a) casi siempre
difiere del que se usa en realidad de enlaces de transmisión directa que se utiliza para enrutar los
datos a través de la red.. En la figura 5-1b se muestra un modelo de enlaces de transmisión directa
en la que todos los nodos se encuentran en el rango de señal de cada otro.

5.1.1.3 Parámetros relacionados con la topología

Además de los parámetros de nodo y de red de destino descritos en este capítulo es fundamental que
antes de unirse a una red, el nodo configure los parámetros que tienen un impacto sobre la
organización de la red y por lo tanto pueden ser utilizados para lograr el comportamiento y
rendimiento adecuando en la red.

Para un nodo final el CS_NEIB_TABLE_SIZE es el primordial de estos parámetros, pues determina


el número máximo de potenciales padres que este nodo puede elegir durante el proceso de unión a
la red. Entre los nodos detectados capaces de tener un nodo hijo, aquel con las mejores cualidades
de enlace es el elegido. Sin embargo para un nodo enrutador CS_NEIB_TABLE_SIZE tiene efectos
adicionales, también limita el numero de padres entre los que puede escoger.

Los nodos coordinadores y enrutadores pueden limitar el número de hijos directos que les pueden
enlazar configurando el parámetro CS_MAX_CHILDREN_AMOUNT que define el número de
hijos totales (enrutadores + nodos finales) que puede tener.
CS_MAX_ROUTER_CHILDREN_AMOUNT define el máximo de enrutadores entre los hijos, y
por lo tanto, la diferencia entre estos dos parámetros especifica el número máximo de dispositivos
finales que se pueden directamente conectar a esto nodo al mismo tiempo. Adviertase que la
siguiente relación debe cumplirse siempre en nodos coordinadores y routers:
CS_NEIB_TABLE_SIZE > CS_MAX_CHILDREN_AMOUNT >= CS_MAX_ROUTER_CHILDREN

(Pag 22)
La profundidad máxima de la red se define mediante CS_MAX_NETWORK_DEPTH, que
especifica el máximo número de saltos posibles en la red, desde un nodo perteneciente al
coordinador. Si este límite es alcanzado en la unión de un router a la red, este no será capaz de
enlazar ningún hijo, aunque cualquiera de los anteriores parámetros se lo permitiera.
CS_MAX_NETWORK_DEPTH tienen un impacto directo en muchos de los intervalos de tiempo
de espera dentro de la pila, por lo tanto para que el correcto funcionamiento de la red esté
garantizado éste debe tener el mismo valor en todos los nodos de la red.

5.1.2 Parámetros de red destino

Antes de proceder a iniciar una red, el nodo es responsable de fijar los parámetros que deciden si
este nodo desea formar la red (coordinador) o si el nodo desea unirse a la red. Estos parámetros son:

– Tipo de modulación, también llamado página del canal.(CS_CHANNEL_PAGE)


– Frecuencia del canal, que se especifica via máscara del canal (CS_CHANNEL_MASK)
– PAN ID extendido de 64 bit (CS_EXT_PAN_ID)
– Los parámetros de seguridad.

CS_CHANNEL_PAGE define el tipo de modulación a ser usado por el dispositivo. Este parámetro
se ignora para frecuencias de 2.4GHz, mientras que en la banda 868/915 Mhz solo se aceptan los
valores 0 y 2. Para la banda de 780 Mhz debe ser siempre 5.

CS_CHANNEL_MASK es un campo de 32-bit que determina los canales de frecuencia soportados


por el nodo. Los 5 bits superiores deben ser siempre 0, los 27 restantes indican el estatus de
disponibilidad para cada uno de estos 27 canales ( 1 = soportado, 0 = no soportado)

(Pag 23)
La tabla 5-1 muestra la distribución de canales a través de toda la banda de frecuencias de la
IEE802.15.4, y muestra la velocidad de transmisión del medio físico para las distintas páginas del
canal.
CS_EXT_PAIN_ID es el identificador extendido de 64-bit de la red que es verificado durante el
proceso de asociación. Por lo tanto los dispositivos que desean unirse a cierta red deben configurar
su PAN ID igual al del coordinador de la red. Si CS_EXT_PAN_ID es fijado a 0x0 en un router o
dispositivo final, entonces el nodo se unirá a la primera red detectada en el aire.

Durante la formación de la red el coordinador selecciona otro identificador de red: este nuevo
PAN_ID de red de 16 bit es usa en las cabeceras de las tramas durante el proceso de intercambio de
datos en vez del de 64 bit que es mas pesado. Por defecto el PAN_ID de red (16-bit) se genera de
forma aleatoria, y si un coordinador durante la formación de la red detecta otra red con el mismo
PAN_ID extendido (64-bit) entonces selecciona de forma automática un PAN_ID de red (16-bit)
diferente para evitar conflictos durante la transmisión de datos.

(Pag 24)
Sin embargo este mecanismo conlleva un comportamiento indeseado en ciertas ocasiones: si se
resetea el nodo coordinador, y este reinicia la red con el mismo PANID extendido y en el mismo
canal, puede encontrarse con un router de la anterior red y por lo tanto formará una red con un
PANID de red diferente. Sin embargo se requiere que el coordinador se una a la misma red donde
anteriormente actuaba y que participe en el intercambio de datos. Por lo tanto, para forzar a que el
coordinador se una a la antigua red, se recomienda que el PANID se predefina en el nivel de
aplicación antes de iniciar la red tal y como se muestra en el siguiente ejemplo:

bool predefPANID=true;
uint16_t nwkPANID=0x1111;

CS_WriteParameter(CS_NKW_PREDEFINED_PAN_ID, &predefPANID);
CS_WriteParameter(CS_NWK_PANID_ID, &nwkPANID);

Si el PANID de red se predefine en un nodo no coordinador, solo será posible el ingresar en una red
con el mismo PANID extendido y de red configurado en el nodo.

5.1.3 Solicitud de Inicio de red y Confirmación

La aplicación BitCloud es totalmente responsable de inicializar la red. La figura 5.2 muestra un


diagrama con la secuencia del procedimiento de inicio de red, secuencia que es idéntica en todo tipo
de dispositivos. Una vez los parámetros de red se han fijado adecuadamente, la aplicación puede
comenzar con el procedimiento de inicio de red ejecutando la llamada asícrona
ZDO_StartNetworkReq(). Tras finalizar el procedimiento de inicio/unión a red, el componente
ZDO informa a la aplicación sobre el resultado del procedimiento de acuerdo a la función de
callback registrada con el argumento de tipo ZDO_StartNetworkConf_t que contiene el status del
procedimiento ejecutado, así como información de la red iniciada, obteniendo la dirección de red
del nodo, etc. Se recibe el status ZDO_STATUS_SUCCESS si el procedimiento se ejecutó con éxito
, mientras que ZDO_FAIL_STATUS indica que el inicio de red fallo.
Después de que un nodo final se une a la red su nodo padre recibe una notificación via
ZDO_MgmtNwkUpdateNotf() con el campo ZDO_CHILD_JOINED_STATUS (0X92). Las
direcciones de red y extendida se devuelve como campo del argumento también. Sin embargo dicho
notificación no es emitida cada vez que un router se une a la red porque no existen padres dedicados
para los nodos hijo tipo router.

(Pag 25)

5.2 Perdida del padre y abandono de la red


Los nodos presentes en una red Zigbee pueden abandonar ésta por dos razones:

– Perdida del padre. Como en una topología de malla, un router no tiene nodos padres
dedicados, este causa solo se dá en nodos finales
– Se solicita el abandono de la red. Esta solicitud puede ser emitida tanto (a) por la aplicación
que corre en el nodo como (b) por un nodo remoto

La primera razón (a) es válida para todo tipo de dispositivos. Mientras que la segunda (b) se aplica a
routers y dispositivos finales unicamente.

5.2.1 Perdida de padre por un nodo final.


En la figura 5-3 se muestra los mensajes de notificación emitidos por la pila en un nodo final si la
conexión con su padre se pierde. La primera notificación ZDO_NETWORK_LOST_STATUS es
expedida por la función ZDO_MgmtNetworkUpdateNotf() cuando un nodo final no puede alcanzar
su nodo padre. Tras recibir este mensaje la aplicación puede relizar cualquier acción pero no debe
iniciar un proceso de unión a la red. Este se iniciará automaticamente cuando el hilo de la pila
reciba el control. La pila intentará encontrar un nuevo padre para el nodo. El resultado es
transmitido a la aplicación via ZDO_MgmtNwkUpdateNotf(). El status
ZDO_NETWORK_STARTED_STATUS significa que el nodo ha conseguido unirse de nuevo a la
red con los parámetros indicados en el argumento de ZDO_MgmtNwkUpdateNotf(). Si el
procedimiento de reintento de unión falla la aplicación recibe una notificación con el estatus ZDO-
NETWORK_LEFT_STATUS. Tras esto, la aplicación es responsable de cambiar los parámetros de
red y si es necesario iniciar un nuevo procedimiento de formación de red como se describe en
“Formación y unión a la red”
5.2.1.1 Notificación de pérdida de hijo
Con asiduidad es importante para un nodo padre poder registrar cuando se ha perdido un hijo.
Como se mencionó anteriormente debido a que solo los dispositivos finales se pueden asociar como
nodos hijo, esta nofificación no será expedida en un nodo router si otro router se apaga o deja de
emitir señal.

La principal dificultad del seguimiento de eventos de p´rrdida de hjos viene del hecho de que un
nodo final es propenso a tener periodos de inactividad (sleep) y por lo tanto no se realizan
intercambio de información durante intervalos largos de tiempo incluso si el nodo final se encuentra
en la red y preparado para enviar información en cuanto finalize su periodo de inactividad.

(Pag 26)
Por lo tanto, para asegurar que un nodo hijo está fuera de la red y simplemente no se ha echado a
dormir, el nodo padre debe conocer la duración de los intervalos de inactividad del nodo hijo ( p.e.
Tener el mismo CS_END_DEVICE_SLEEP_PERIOD). Par un nodo padre esto implica que sus
hijos se levanten periodicamente y envien alguna solicitud. Si durante el intervalo de tiempo
calculado como:
CS_NWK_END_DEVICE_MAX_FAILURES * (CS_END_DEVIE_SLEEP_PERIOD + CS_INDIRECT_POLL_RATE)
un hijo no entrega ninguna trama de solicitud, el nodo padre asume que ese hijo ha abandonado la
red y por lo tanto se lanza la callback ZDO_MgmtNwkUpdateNotf() con el status
ZDO_CHILD_REMOVED (0x93). Y en sus argumentos, se indica la dirección extendida del nodo
hijo que abandonó la red

5.2.2 Abandono de la red


En muchas situaciones es conveniente que un nodo abandone la red en respuesta a ciertos eventos.
(o incluso forzar a un nodo que se desasocie de la red el mismo). BitCloud permite que la aplicación
de cualquier tipo de nodo inicie este proceso usando la función ZDO_ZdpReq():

static ZDO_ZdpReq_t zdpLeaveReq;



//set corresponding cluster ID
zdpLeaveReq.reqCluster = MGMT_LEAVE_CLID;
zdpLeaveReq.dstAddrMode = EXT_ADDR_MODE;
zdpLeaveReq.dstExtAddr = 0; // for own node address shall be 0
zdpLeaveReq.ZDO_ZdpResp = ZDO_ZdpLeaveResp; // callback

//for own node address shall be 0


zdpLeaveReq.req.reqPayload.mgmtLeaveReq.deviceAddr = 0;
//specify whether to force children leave or not
zdpLeaveReq.req.reqPayload.mgmtLeaveReq.removeChildren = 0;

//specify whether to perform rejoin procedure after network leave


zdpLeaveReq.req.reqPayload.mgmtLeaveReq.rejoin = 1;
ZDO_ZdpReq(&zdpLeaveReq); // request network leave

Si en el código de arriba la dirección de destino se fija a la dirección de un nodo remoto. Entonces


después de llamara a ZDO_ZdpReq (&zdpLeaveReq), el nodo transmitirá una trama comando al
nodo destino solicitandole el abandono de la red.

El diagrama de secuencia para el procedimiento de abandono de red se muestra en la figura 5.4 (el
nodo abandona la red de motu propio) y en la figura 5.5 (el nodo abandona la red debido a una
solicitud remota).

(Pag 27)
5.3 Intercambio de información
Obviamente el proposito de establecer una red Zigbee es el realizar un intercambio de información
entre nodos remotos según los solicite la funcionalidad de la aplicación. En esta sección se da un
vistazo a la configuración del nodo, los parárametros de transmisión y las funciones del API
Bitcloud responsbles de la comunicación en el nivel de aplicación.

5.3.1 Registro de puntos finales


Dentro de la Zigbee la información es intercambiada entre los llamados puntos finales. Para que sea
posible la comunicación en el nivel de aplicación cada nodo debe registrasr al menos un punto final
mediante el uso de la función APS_RegisterEndPoint() con el argumento de tipo
APS_registerEndPointReq_t. El argumento especifica un descriptor de punto final (campo
simpleDescriptor) que incluye tanto parámetros como un ID de punto final (número del 1 al 240),
ID de perfil de aplicación, numero y lista de grupos de entradas y salidas. Además el campo
APS_DataInd señala la función callback a ser llamada cada vez que se reciban datos destinados a
este punto final.

(Pag 28)
El fragmento de código que sigue ejemplifica como registrar y definir un punto final ep1 con un ID
de perfil 1 y sin ningún tipo de limitación en cuanto a I/O.

// Specify endpoint descriptor


static SimpleDescriptor_t simpleDescriptor = {1, 1, 1, 1, 0, 0, NULL, 0, NULL};
// variable for registering endpoint
static APS_RegisterEndpointReq_t endpointParams; …
// Set application endpoint properties

endpointParams.simpleDescriptor = &simpleDescriptor;
endpointParams.APS_DataInd = APS_DataIndication;

// Register endpoint
APS_RegisterEndpointReq(&endpointParams);

5.3.2 Configuración del ASDU


Para poder realizar la transmisión de datos por si misma, la aplicación primero deberá crear una
solicitud de transmisión del tipo APS_DataReq_t, que especifica la longitud del ASDU (campos
asdu y asduLength), fijar varios parámetros de transmissión y definir la función de callback (campo
APSDataConf) que será ejecutada para informar a la aplicación del resultado de la transmisión.

Debido a que la pila necesita que el ASDU se guarde en la memoria RAM como un bloque continuo
de datos con unas características especificas, la aplicación deberá construir dicha estructura como se
muestra en la figura 5.6

La maxima longitud permitida para el frame de datos es de 53 bytes en datos cifrados y 84 bytes
para transmisiones no seguras.

(Pag 29)
El siguiente extracto de código ejemplifica como crear una solicitud de envío con la correcta
estructura ASDU:

// Application message buffer descriptor


BEGIN_PACK
typedef struct
{
uint8_t header[APS_ASDU_OFFSET]; // Header
uint8_t data[APP_ASDU_SIZE]; // Application data
uint8_t footer[APS_AFFIX_LENGTH - APS_ASDU_OFFSET]; //Footer
} PACK AppMessageBuffer_t;
END_PACK
static AppMessageBuffer_t appMessageBuffer; // Message buffer
APS_DataReq_t dataReq; // Data transmission request

dataReq.asdu = appMessageBuffer.data;
dataReq.asduLength = sizeof(appMessageBuffer.data);

Si se usa el esquema de asignación manual de direcciones el nodo fuente deberá tener un
conocimiento total del destinatario de los datos, tanto su dirección de red como el ID del perfil, el
punto final y los grupos de entrada soportados. En el esquema de asignación automática estos
parámetros se fijan durante el proceso de binding.

5.3.3 Transmisión del ASDU


Tras crear la estructura correcta de envio y que todos los parámetros sean fijados como se requiere,
la aplicación puede transferir el ASDU a la capa APS para ejecutar la trasmisión por el aire usando
la función APS_DataReq().

La figura 5.7 ilustra el diagrama de secuencia en el nodo fuente durante la transmisión


Si es la primera vez que la aplicación envía datos entonces APS_DataReq() automáticamente
realizara una petición de enrutado y encontrará el camino directo al destino deseado. Es más, en
todo momento la ruta se mantiene actualizada teniendo en cuenta los posibles cambios en la
topología de la red y en la calidad de los enlaces radio. La aplicación puede fijar un máximo
número de saltos permitidos para la trasmisión de datos ( y por lo tanto una latencia máxima)
fijando el correspondiente campo de radio en la petición de trasmisión (APS_DataReq_t).

(Pag 30)
Como el protocolo Zigbee permite una comunicación bidireccional, la aplicación puede solicitar un
reconocimiento de la recepción de la trama en el nivel de aplicación (APS ACK) fijando
acknowledgedTransmission en el campo txOption del la solicitud de envio a 1. En este caso a la
aplicación se la notifica el éxito de la entrega de la trama (APS_SUCCESS_STATUS) mediante la
función callback de confirmación que se registró, solo si despues de que el ACK de la trama
correspondiente haya sido recibido. Si durante el intervalo CS_ACK_TIMEOUT no se recibe ACK
entonces se emite la función callback con APS_NO_ACK_STATUS.

Las transmisiones sin APS ACK's tienen una mayor tasa de envío pero no son seguras, puesto que
no se puede confirmar el envío de una trama. En estos casos si todos los parámetros se fijan
correctamente, se llama a la callback con APS_SUCCESS_STATUS tras la emisión de la trama por
el medio físico (aire).

La instancia de APS_DataReq_t solo puede ser reutilizada tras la confirmación de que la callback a
sido ejecutada.

5.3.3.1 Transmisiones Broadcast


Además de trasmisiones nodo a nodo, las aplicaciones pueden enviar datos en modo broadcast
donde las tramas de datos son enviadas con destino a todos los nodos de la red o a nodos con
características especificas. Los siguientes enumerados se pueden usar en la aplicación BitCloud
como dirección destino para un mensaje de broadcast:
– todos los nodos de la red: BROADCAS_ADR_ALL (o 0xFFFF)
– todos los nodos con el parámetro rxOnWhenIdle igual a 1:
BROADCAST_ADDR_RX_ON_WHE_IDLE (o 0xFFFD)
– todos los nodos router: BROADCAS_ADDR_ROUTERS (o 0xFFFC)
Las tramas broadcas no pueden ser confirmadas y se deben trasmitir con
acknowledgedTransmission en el campo txOptions de la solicitud de envío fijado a 0

A nivel de red, el procedimiento broadcast se ejecuta de la siguiente manera: después de llamar a


APS_DataReq(), el dispositivo envía la trama tres veces. Cada nodo, tras recibir una copia de la
trama (las demás son ignoradas) decrementa el radio de trasmisión en uno y si es mayor que cero
reenvía la trama otras tres veces a sus vecinos. Este procedimiento se repite en los demás nodos
hasta que el radio de trasmisión llega a cero.

Además de difundir la trama sobre la red, la aplicación puede configurar la transmisión de modo
que la trama sea entregada a todos los puntos finales registrados en los nodos destino. Esto se puede
realizar fijando el campo dstEndpoint en la solicitud de envío a APS_BROADCAS_ENDPOINT ( ó
0xFF). Esta difusión a nivel de nodo también se puede ejecutar mediante transmisiones punto a
punto.

Al igual que las tramas unicast, el mensaje broadcast puede ser enviado con un limite de saltos
( configurando el campo radio). Si el radio es fijado a 0 el mensaje llegará a todos los nodos de la
red.

5.3.4 Recepción del ASDU


Como se indicó en el parágrafo 5.3.1 para permitir el intercambio de información en el nivél de
aplicación, todo nodo receptor deberá registrar al menos un punto final con la indicación de una
función de callback para el procedimiento de recepción de datos.

Tras la recepción de una trama por el nodo, la pila verifica si el destino indicado en la cabecera de la
trama coincide con los distintos puntos finales registrados en el nodo. En caso de coincidencia, la
correspondiente callback, especificada en el campo APS_DataInd de la solicitud de registro de un
punto final (APS_RegisterEndpointReq_t), se ejecutará con un argumento de tipo APS_DataInd_t.
Este argumento contiene el mensaje de la aplicación (el campo ASDU) así como información sobre
las direcciones fuente y destino, punto final, perfil, etc.

(Pag 31)

5.3.4.1 Escrutinio del nodo final


En las redes Zigbee se usa un mecanismo de escrutinio (polling) para entregar los datos a los
dispositivos finales. La figura 5.8 muestra el principio general del mecanismo pollig
Una vez se ha recibido una trama destinada a un nodo hijo o una trama broadcast con el radio de
transmisión por encima de cero y con la dirección de destino igual a 0XFFFF, el nodo padre
almacena la trama y espera a una solicitud del hijo.

Cuando el nodo final despierta, pregunta a su nodo padre cada CS_INDIRECT_POLL_RATE


milisegundos. Adviertase que este escrutinio es realizado en la capa de red y es transparente a la
aplicación. Después de recibir una solicitud de información desde un nodo final, el nodo padre debe
transmitir una única trama e indicar si hay más tramas para transmitir o no.

5.4 Gestión de energía


En las redes Zigbee, el nivel de consumo de energía es habitualmente una de las pricipales
preocupaciones porque en muchas aplicaciones no todos los dispositivos pueden ser alimentados de
red general. La pila BitCloud proporciona una API que permite cambiar entre modos despierto y
dormido así como apagar el chip de radio para reducír el consumo de energía.

Siguiendo el estandar ZigBee, PRO BitCloud mantiene mecanismos de gestión de la energía en


nodos finales únicamente. Para evitar consecuencias en la estabilidad de la red, los nodos routers y
coordinadores deberan siempre permanecer en modo activo.

(Pag 32)

5.4.1 Modos activo y suspendido para dispositivos finales


Independientemente de su status en red ( unido a una red o no) un dispositivo final puede estar en
modo activo o modo suspendido.

Tras ser alimentado, un nodo siempre comienza en modo activo y tiene su MCU alimentado y
activo, con el chip RF listo para realizar operaciones Rx/Tx. La aplicación puede llamar a cualquier
procedimiento BitCloud y puede ejecutar callbacks y recibir notificaciones.

En modo suspendido, el chip RF se apaga mientras que el MCU es puesto en un modo especial de
bajo consumo. La aplicación no podrá realizar ningun tipo operación radio, ni comunicar con
periféricos externos.

Para poner los dispositivos finales a dormir, la aplicación debe llamar a ZDO_SleepReq() con un
argumento de tipo ZDO_SleepReq_t. Tras la confirmación, la callback indicara el estado de
ejecución y si se devuelve ZDO_SUCCESS_STATUS el nodo entrara en modo suspendido.

Hay dos formas de levantar el nodo: una planificada y otra a través de una interrupción IRQ

De manera planificada, el nodo se levantará tras un intervalo de tiempo en milisegundos


especificado por CS_END_DEVICE_SLEEP_PERIOD. A la aplicación se la notifica que el nodo se
va a levantar a través de la función ZDO_WakeUpInd.CS_END_DEVICE_SLEEP_PERIOD no
deberá ser modificado en tiempo de ejecución. La figura 5.9 muestra el diagrama de secuencia de
llamadas de la pila para los procedimientos de dormir y levantar de forma planificada el nodo.
En el proceso de levantamiento por la llegada de una interrupción IRQ el MCU se activa tras recibir
el evento IRQ registrado. Sin embargo debido a que la notificación de este evento debe ser lanzada
directamente por el componente HAL, la pila de red no es consciente de ello. Por lo tanto para traer
toda la pila de vuelta a un estado operativo la aplicación deberá llamar a la función
ZDO_WakeUpReq. Despues de que la callback registrada para esta solicitud devuelva
ZDO_SUCESS_STATUS, la pila, el chip RF y el MCU estan completamente activos.

Adviertase que si se llama a IRQ_callback desde un estado de inactividad y el timer que controla el
tiempo de inactividad esta fijado deacuerdo a CS_END_DEVICE_SLEEP_PERIOD, este se parará
y comenzara de nuevo a la siguiente llamada a ZDO_SleepReq()

(Pag 33)
Ambos métodos pueden combinarse en una aplicación para gestionar el consumo de energía. Si
CS_END_DEVICE_SLEEP_PERIOD se fija a cero, solo una interrupción hardware puede levantar
el nodo de un estado suspendido a su estado activo.
5.4.2 Apagar el chip RF
En muchos escenarios se puede requerir que el MCU permanezca operando (p.e. para proposistos
de procesado de datos ) mientras que el chip de RF se apaga para reducir el consumo de energía.
Este caso es contemplado por la pila BitCloud, posibilitando el apagado del mecanismo de polling
en un dispositivo final y por lo tanto el del chip RF. Para apagar la radio, la aplicación deberá llamar
a la función ZDO_StopSyncReq(). Para encenderla de nuevo (y permitir el polling) la aplicación
deberá llamar a ZDO_StartSyncReq(). Cuando se use este mecanismo sera importante tener en
cuenta que el nodo padre espera solicitudes de polling de su nodo hijo, y que si no las recibiera
durante un cierto periodo de tiempo, eliminará el nodo de la red. Tengase en cuenta que este
mecanismo únicamente está disponible en nodos finales.

5.5 Seguridad
BitCloud proporciona dos niveles de seguridad en la red ZigBee; sin seguridad, y nivel de seguridad
standard. Por lo tanto existen dos tipos de librerias localizadas en el directorio lib/: una sin
seguridad y otra que incluye soporte a seguridad. La elección de una librería en particular se debe
realizar en el fichero Makefile cuando se compila la aplicación. En el ejemplo de aplicación de
BitCloud, esta elección se realiza basandose en los valores del parámetro SECURITY_MODE.

Si se requiere soporte a seguridad, ademas de incluir las librerías adecuadas, los parámetros
CS_ZDO_SECURITY_STATUS y CS_NETWORK_KEY deben ser configurados para permitir la
adecuada operación de la red.

CS_ZDO_SECURITY_STATUS=0. Todos los dispositivos en la red deben tener preconfigurado el


mismo parámetro CS_NETWORK_KEY en el Makefile

CS_ZDO_SECURITY_STATUS=3. Uno de los dispositivos de la red (por lo general el


coordinador) debe ser configurado como Centro de Confiabilidad (Trust center), y tener
CS_NETWORK_KEY definido en el Makefile. En todos los demás nodos en la red se debe fijar
CS_APS_TRUST_CENTER_ADDRESS para que sean capaz de establecer conexión con el Trust
Center, pero no deben tener CS_NETWORK_KEY definido.

Adviertase que activar la opción de seguridad incrementa el tamaño de la memoria de programa. Y


por lo tanto en muchas aplicaciones la memoria de programa puede agrandarse hasta no ser capaz
de entrar en la memoria disponible. En estos casos, se puede decrementar parámetros tales como
CS_NEIB_TABLE_SIZE, CS_ROUTE_TABLE_SIZE, CS_MAX_CHILDREN_AMOUNT y otros
parámetros que tienen impacto en la asignación de memoria tal y como se describe en la sección 6.
6. CONTROL DEL HARDWARE ADICIONAL

Además de la funcionalidad de red descrita en la sección 5, el API de BitCloud proporciona un


extenso soporte a las interfaces mas comunes de HW tales como USART, TWI, SPI, ADC, GPIO,
IRQ, etc. La Capa de Abstracción Hardware (HAL) de BitCloud es la responsable de interactuar
entre los módulos Atmel y los periféricos externos.

Este capítulo arroja un poco de luz sobre las principales interfaces HW soportadas en BitCloud.

6.1 Bus USART

La pila BitCloud proporciona un API para soporte de la interface serie Univerval Synchronous
/Asynchronous Receiver/Transmitter (USART).

Para permitir la comunicación mediante interfaz USART la aplicación primero debe configurar el
correspondiente puerto USART usando una variable global estática de tipo HAL_UsartDescriptor_t.
Se requiere fijar todos los parámetros USART más comunes tales como modo sincrono/asincrono,
baudrate, flow control, modo de paridad, etc. Adviertase que a pesar de que el nombre USART es
generalmente usado en este capitulo para hacer referencia al API. es lo mismo que para las
interfaces asincronas o sincronas (UART / USRT). Para modo de operación asincrono, el descriptor
debe ser fijado a USART_MODE_ASYNC.

La recepción y transmisión de datos a través de la USART se puede configurar para trabajar tanto
en modo callback o en modo polling como se describe más abajo.

Los ajustes de la USART se deben realizar usando la función HAL_OpenUsart() con un argumento
apuntando una la variable global de tipo HAL_UsartDescriptor_t con la configuración deseada del
puerto. El valor devuelto indica si el puerto se ha sido abierto de manera satisfactoria y puede ser
usado para el intercambio de datos.

Cuando no haya necesidad de mantener activo el puerto USART, la aplicación deberá cerrarlo
usando la función HAL_CloseUsart().

6.1.1 Modo callback de la USART


El siguiente fragmento de código muestra como configurar el puerto USART para que tanto las
operaciones Tx y Rx sean ejecutadas en modo callback.

HAL_UsartDescriptor_t appUsartDescriptor;
static uint8_t usartRxBuffer[100]; // any size maybe present

appUsartDescriptor.rxBuffer = usartRxBuffer; // enable Rx
appUsartDescriptor.rxBufferLength = sizeof(usartRxBuffer);
appUsartDescriptor.txBuffer = NULL; // use callback mode
appUsartDescriptor.txBufferLength = 0;
appUsartDescriptor.rxCallback = rxCallback;
appUsartDescriptor.txCallback = txCallback;

HAL_OpenUsart(&appUsartDescriptor);

La siguiente figura 6.1 ilustra el correspondiente diagrama de secuencia para el uso de la USART en
modo callback

Para la transmisión de datos se debe llamar a la función HAL_WriteUsart() con un puntero hacia el
buffer de datos a ser transmitido y con la longitud del buffer como argumentos. Si se devuelve un
valor mayor de cero, la función registrada como txCallback en el descriptor de la USART se
ejecutará despues de notificar a la aplicación que la transmisión ha finalizado.

La USART es capaz de recibir datos si los campos rxBuffer y rxBufferLength del correspondiente
descriptor de la USART no son NULL y cero respectivamente. Para el modo callback el campo
rxCallback deberá apuntar a la función que se ejecutará siempre que llegen datos al rxBuffer de la
USAR con el número de bytes recibidos como argumento. Conocido este número, la aplicación
debe reenviar los datos recibidos desde el rxBuffer de la USART hacia el buffer de la aplicación
usando la función HAL_ReadUsart()

6.1.2 USART en modo polling


En el modo polling las operaciones Tx/Rx de la USART utilizan los correspondientes buffers
cíclicos fijados por el descriptor USART. Así tanto el punter del buffer como la longitud de este
deben ser fijados a un valor distinto de cero para su uso en modo polling, mientras que las
correspondiente función de callback se fijará a NULL.

La figura 6.2 ilustra el diagrama de secuencia para Tx7Rx en modo polling. La principal diferencia
en la operación Tx entre los modos callback y polling reside en que en esta última tras la llamada a
HAL_WriteUsart() todos los datos utiizados en la transmisión como argumento, son movidos
cíclicamente del txBuffer al descriptor de la USART. Y por lo tanto la aplicación puede reusar la
memoria ocupada por los datos. La función HAL_IsTxEmpty() se usa para verificar tanto que hay
suficiente espacio en el txBuffer como para verificar cuantos bytes han sido realmente transferidos.

En contraste con el modo callback, a la aplicación no se la notifica el evento de recepción de datos.


Sin embargo, de la misma forma que en el método callback, los datos recibidos son guardados
automaticamente en el rxBuffer cíclico y la aplicación puede obtenerlos usando la función
HAL_ReadUsart().

En el caso del overflow de los txBuffer o rxBuffer, el resto de los datos se pierde. Para evitar la
pérdida de datos, la aplicación deberá controla el número de bytes escritos que devuelve
HAL_WriteUsart() y si es posible usar HW flow control.

6.1.2Gestión de las señales de control de flujo ( CTS/RTS/DTR )

Además de las operaciones de lectura/escritura de datos, BitCloud proporciona


una API para el manejo de las señales CTS/RTS/DTR del puerto serie que
soporte control de flujo HW (depende de plataformas). Mirar la documentación
de la API para una descripción detallada de las correspondientes funciones.

6.2Interface del Bus serie Two-wire


6.2.1 Definición del Bus serie Two-wire
La interface serie Two-wire (TWI) es compatible con el protocolo de Philips I2C.
El bus TWI es ideal para aplicaciones típicas de microcontrolador. El protocolo
TWI permite a los diseñadores del sistema conectar hasta 128 dispositivos
diferentes usando únicamente dos líneas de bus bidireccionales, una para el
reloj (SCL) y otra para datos (SDA), el único dispositivo hardware externo que
se necesita para implementar el bus es una resistencia pull-up por cada línea
del bus TWI. Todo dispositivo conectado al bus tiene su dirección y los
mecanismos para resolver la problemática del bus es inherente al protocolo
TWI.

6.2.2 Terminología TWI


Las siguientes definiciones son frecuentemente usadas en esta sección

6.2.3 Transferencia de datos y formato de trama


6.2.3.1 Transmitiendo Bits.
Cada Bit transmitido por un bus TWI es acompañado por un pulso de la señal
de reloj. Así pues el nivel de tensión de la línea de datos debe permanecer
estable mientas la señal de reloj este alta. La única excepción a esta regla es la
generación de las condiciones de inicio y parada de transmisión.
6.2.3.2 Condiciones de inicio y parada de transmisión
El Master inicia y termina cada transmisión de datos. La transmisión se inicia
cuando el master lanza la condición START en el bus, y termina cuando lanza la
condición de STOP. Entre estas dos condiciones, se considera que el bus está
ocupado, y ningún otro master debería intentar apoderarse del bus. Un caso
especial ocurre cuando se lanza una nueva señal de START entre dos
condiciones de START y STOP. A esto se le llama REPEATED START, y se usa
cuando el master desea iniciar una nueva transferencia sin renunciar al control
del bus. Tras un REPEATED START, el bus se considera ocupado hasta la
siguiente señal de STOP. Esto es idéntico al comportamiento de la señal START,
y por lo tanto START se usará de aquí en adelante para describir tanto START
como REPEATED START a no ser que se indique otra cosa. Como se representa
en la siguiente figura. Las condiciones de START y STOP se indican con un
cambio en el nivel de SDA cuando la señal de SCL está en alto.

6.2.3.3 Formato del paquete de dirección.

Todos los paquetes “dirección” transmitidos por el bus TWI son de 9 bits de
longitud, y consisten en 7 bits de dirección, un bit de control READ/WRITE, y el
bit ACK. Si el bit READ/WRITE está alto, indica operación de lectura, en otro
caso se ejecutará una operación de escritura. Cuando el esclavo reconoce que
está siendo direccionado, deberá realizar el reconocimiento, poniendo un nivel
bajo el la línea SDA en el noveno ciclo de SCL (el ACK). Si la esclavo
direccionado estuviera ocupado, o por alguna otra razón no puede responder a
la solicitud del master, la línea SDA debe permanecer alta en el ciclo de reloj de
ACK. El Master puede entonces transmitir la condición de STOP o la de
REPEATED START para iniciar una nueva transmisión. Un paquete de dirección
consistente en la dirección del esclavo mas el bit READ/WRITE se denomina
SLA+R o SLA+W respectivamente.

El MSB del byte de dirección es el que primero se transmite. Las direcciónes de


los esclavos se pueden fijar libremente, pero la dirección 0000 0000 se reserva
para broadcast.

Cuando se lanza un broadcast, todos los esclavos deben responder poniendo a


nivel bajo la señal SDA en el ciclo ACK. El broadcast se usa cuando el Master
desea transmitir el mismo mensaje a varios de los esclavos del sistema.
Tengase en cuenta que realizar un broadcast seguido de un bit Read carece de
significado y podría causar problemas si varios esclavos comienzan a trasmitir
diferentes datos.

Toda dirección con el formato 1111 xxxx se reserva para futuros propósitos.

6.2.3.4 Formato del paquete de datos

Todos los paquetes de datos transmitidos por el bus TWI son de 9 bits de
longitud, y consisten en un byte de datos y un bit ACK, durante la transmisión
de datos, el Master controla la línea de reloj y las condiciones START y STOP,
mientras que el receptor es responsable de la generación del ACK.
Como se dijo con anterioridad, el ACK se genera poniendo a nivel bajo la señal
ACK en el noveno ciclo de reloj SCL Si el receptor deja la línea SDA en alto, se
genera NACK. Cuando al receptor le llega el último byte, o por alguna razón no
puede recibir más bytes, deberá informar al transmisor enviando un NACK tras
el último byte.

6.2.3.5 Combinado paquetes de dirección y datos en una transmisión


Una transmisión consiste básicamente en una señal de START, un SLA+R/W,
uno o más paquetes de datos y una señal de STOP. Un mensaje vacio
consistente en una secuencia de START + STOP está prohibida. Adviertase que
la línea SCL se usa para implementar la gestión del bus entre el Master y el
Esclavo. El esclavo puede prolongar el tiempo que SCL permanece bajo. Esto es
útil si la velocidad del reloj marcada por el Master es demasiado rápida para el
esclavo, o si el esclavo necesita más tiempo para procesar la transmisión de
datos. El tiempo que el esclavo mantiene bajo la línea SCL no afecta al tiempo
que SCL permanece alto, tiempo controlado por el Master. Como consecuencia,
el esclavo puede reducir la tasa de transferencia prolongando el duty cycle de
SCL.

La figura 6.9 muestra una típica transmisión de datos. Adviertase que se


pueden transmitir más de un byte de datos entre SLA+R/W y la señal de STOP,
dependiendo del protocolo software implementado por la aplicación

La aplicación BitCloud solo puede desempeñar la funcionalidad del Master TWI.


Al igual que en otros interfaces HW, el interfaz TWI debe ser primero
configurado y activado para la comunicación. Tras esto, se puede ejecutar los
procedimientos de lectura/escritura con un dispositivo TWI esclavo.

Como se muestra en la anterior figura , las operaciones de lectura/escritura en


bus TWI se ejecutan de forma asíncrona, Tras la llamada a
HAL_WriteI2cPacket() o HAL_ReadI2cPacket() la aplicación no podrá ejecutar
ninguna acción con el bus TWI así como con la memoria asignada al argumento
de tipo HAL_i2cParams_t hasta que la función callback vuelva.

6.3Bus SPI
Dependiendo de la plataforma MCU, el componente HAL de la pila BitCloud
puede implementar el protocolo SPI sobre el bus USART (plataformas AVR) o un
bus SPI auténtico cuando éste este disponible. Sin embargo las
correspondientes llamadas a la API definida en el fichero spi.h son
independientes de la plataforma subyacente y la única diferencia aparece en la
configuración SPI, más concretamente en los campos de la variable estática de
tipo HAL_SpiDescriptor_t.

La aplicación Bitcloud soporta únicamente el modo Master SPI. En la figura 6.11


se muestra un diagrama de secuencia del las llamadas a la API relacionadas
con el bus SPI.

El mecanismo común en otras interfaces HW también se aplica en el bus SPI.


Lo primero que se debe hacer es configurar y abrir con éxito el puerto
( ejecutando HAL_OpenSpi() con argumento apuntando a la variable de tipo
HAL_spiDescriptor_t y la función callback).

Tras esto se puede proceder al intercambio de datos usando la función


asíncrona HAL_WriteSpi(). Para el intercambio de datos síncrono entre
dispositivos maestro y esclavo se debe usar la función HAL_ReadSpi. Si la
función de callback no se fijo a NULL, la aplicación sale de la función cuando
HAL_WriteSpi() o HAL_ReadSpi() se llama y tras esto la función de calback
informa a la aplicación de que la transacción SPI a terminado. Si el argumento
de la callback en HAL_OpenSpi() fue NULL, la transacción SPI se realizará
mientras dura la llamada a la función de lectura/escritura.

Por último, si no se espera más intercambio de datos, el bus SPI se debe cerrar
para liberar los recursos ocupados.

6.4 Interface GPIO


Bitcloud provee de un amplio set de comandos para la gestión de entradas y salidas, tanto I/O
standard como de aquellos pines que se reservan para otras interfaces pereo que pueden ser usados
también como I/O standard.

Las nombres de las funciones y macros relacionadas con las GPIO se definen en el fichero gpio.h
del componente HAL_HWD. Las llamadas a función tienen la forma
“GPIO_#pin_name#_#function_name#()”.

6.5 ADC
Bitcloud provee de una API independiente de la plataforma para el convertidor analógico-digital.
Como en otras interfaces, el ADC se debe configurar primero antes de ser usado mediante la
función HAL_OpenAdc() pasando un puntero a una variable global HAL_AdcParams_t que
contenga los parámetros de configuración. Dicha función devuelve el status del ADC indicando si la
operación de apertura se ha realizado correctamente. La operación puede fallar debido a alguna de
las siguientes razones:

– El puerto ADC se se abrió


– El argumento de la función es NULL
– La resolución es mayor de RESOLUTION_10_BIT
– Se le pasa un valor incorrecto para el voltaje de referencia (param->voltageReference)
– Se usan RESOLUTIO_10_BIT para frecuencias de muestreo mayores a 9600

Despues de inicializar el ADC con éxito, la lectura del canal que se desee muestrear se puede
realizar usando la función HAL_ReadAdc(). El resultado se devuelve mediante una función
callback a un buffer especificado como registro en la función HAL_OpenAdc().

Para cerrar el interface ADC se debe usar la función HAL_CloseAdc()


6.6 Otras funcionalidades del HAL.

El componente HAL de la pila BitCloud también provee soporte a las siguientes interfaces:

– 1-Wire
– IRQ
– Aplicaciones timer, tiempo del sistema
– Watchdog

La documentación de la pila contiene la información sobre las funciones API que se deben usar para
la gestión de las interfaces mencionadas.

A pesar de estar disponibles en el componente HAL, las siguientes funciones son únicamente
usadas para su ejecución interna dentro de la pila por lo que las aplicaciones de usuario deben
evitar en la medida de lo posible su uso:

– HAL_ReadEeprom/HAL_WriteEeprom
– Sleep Timer

7 MEMORIA Y ASIGNACIÓN DE RECURSOS.


7.1 RAM
La memoria RAM es un recurso usado por la Pila para almacenar parámetros runtime, tales como
tablas de vecinos, tablas de enrutado, tablas de hijos, etc. A petición de la pila, algunos valores de
ciertos parámetros almacenados en la EEPROM son almacenados frecuentemente en la RAM para
facilitar su posterior recuperación. La pila de llamadas reside también en la RAM y es compartida
tanto por el SO BitCloud como por la aplicación usuario. Para conservar la RAM, el usuario debe
abstenerse del uso de funciones recursivas, funciones que tomen muchos parámetros, funciones que
declaren extensas variables y/o arrays locales, o funciones que pasen extensos parámetros a la pila.

Regla del sistema 8: No se debe pasar ninguna estructura a la pila, como por ejemplo el paso de
estructuras como argumentos de funciones. Pasa un puntero en su lugar que apunte a esta.

Regla del sistema 9: Se deben usar variables globales en vez de variables locales, siempre y
cuando sea posible.
El uso de callbacks definidos por el usuario aseguran que las estructuras se pasen mediante puntero.
El usuario debe verificar que esto también se cumbple en las funciones locales que este defina.

Regla del sistema10: La aplicación de usuario no debe utilizar funciones recursivas. Es


recomendable que la máxima profundidd de llamadas invocadas por el usuario no sobrepase el
número de 10, teniendo cada función no más de 2 parámetros como argumento cada una.

En su conjunto, la demanda de RAM por la pila se debe consensuar con la demanda de la aplicación
de usuario. Afortunadamente, el consumo total de RAM usada para mantenimiento de datos de la
pila es un parámetro de usuario configurable. El ConfigServer (o CS) se distribulle con el código
fuente, para permitir al usuario afinar los parámetros runtime de la pila. Mediante estos parámetros
se puede manejal el tamaño total de los datos que la pila almacena en la RAM para tablas. La
siguiente lista muestra estos parámetros y proporciona una fórmula simple para calcular el consumo
de RAM basado en el valor del parámetro.

(1): Varios buffers (CS_NWK_ROUTE_DISCOVERY_OBJ_SIZE y


CS_JOIN_IND_OBJ_AMOUNT) pueden depender de CS_NWK_DATA_IND_BUFFER_SIZE. En
el peor de los caso se deben sumar 51*p bytes que serán asignados pro cada entrada. Las
condiciones exactas se pueden obtener de los ficheros configServer.h y configServer.c

La suma total de RAM consumida por la pila se puede calcular sumando la última columna a

S-ar putea să vă placă și