<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es">
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Edgardo</id>
		<title>Proyecto Butiá - Contribuciones del usuario [es]</title>
		<link rel="self" type="application/atom+xml" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Edgardo"/>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Especial:Contribuciones/Edgardo"/>
		<updated>2026-04-05T20:13:57Z</updated>
		<subtitle>Contribuciones del usuario</subtitle>
		<generator>MediaWiki 1.26.2</generator>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all_shield_butia&amp;diff=1566</id>
		<title>Usb4all shield butia</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all_shield_butia&amp;diff=1566"/>
				<updated>2011-12-26T13:23:01Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Este shield fue realizado para utilizarse con la placa de entrada/salida [[usb4all]], la cual puede realizarse con materiales disponibles en el mercado local. Dado que el circuito es muy sencillo y los componentes se obtienen en tamaños que permiten ser manipulados es posible realizarla manualmente por personas no expertas, bajando considerablemente los costos en relación a otras placas como arduino. Cabe destacar que la placa implementa el protocolo USB, no siendo necesario incluir un conversor USB/serial en el circuito. El proyecto USB4all es libre y se encuentra bajo licencia GNU/GPL 2.0 en el [http://sourceforge.net/projects/usb4all/ repositorio de sourceforge].&lt;br /&gt;
USB4all surge como un [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb proyecto academico de grado de la UdelaR].&amp;lt;br&amp;gt;&lt;br /&gt;
Lo primero que necesitamos para realizar un shield butiá USB4all es descargar el diseño del mismo, esto puede realizarse obteniendo los fuentes desde el [http://sourceforge.net/projects/usb4all/ repositorio en sourceforge].&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all1.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Los fuentes pueden encontrarse en el directorio ''shield_butia_rj45_rj11'', están realizados utilizando [http://www.lis.inpg.fr/realise_au_lis/kicad/ Kicad] el cual posee licencia GPL.&amp;lt;br&amp;gt;&lt;br /&gt;
Al igual que otros programas de diseño de circuitos, Kicad permite exportar a formato ''gerber''. Este formato permite su utilización por maquinas de producción de circuitos impresos, en el mercado local existen varias empresas brindan este servicio utilizando el formato gerber. También existen sitios en internet que fabrican y envían por correo el producto. Hay que tener en cuenta que el circuito cuenta con dos capas, lo que hace más complejo la realización con métodos manuales.&amp;lt;br&amp;gt;La lista de componentes necesarios para realizar un shield es la siguiente:&amp;lt;br&amp;gt;&lt;br /&gt;
* 1 PCB shield butiá USB4all&lt;br /&gt;
* 2 Conector tira zócalo 40 terminales&lt;br /&gt;
* 1 Bornera 2p BR102A through hole&lt;br /&gt;
* 8 Jack RJ45 para impreso TFN188P &lt;br /&gt;
* 1 MC14051BD  S016 &lt;br /&gt;
* 8 resistencias de 10K &lt;br /&gt;
* resistencias de diferentes valor para sensores&lt;br /&gt;
&lt;br /&gt;
Este shield busca solucionar los problemas indentificados en el [[Construccion_shield_v1.0|shieldv1]], como ser el gasto innecesario de pines para realizar la identificación del dispositivo conectado, asi como ser más robusto mecánicamente con los conectores.&amp;lt;br&amp;gt;Pistas y ruteo más amplio para evitar la introducción de corto circuitos debido a la imprecisión que muchas casas manejan a la hora de fabricar circuitos.&amp;lt;br&amp;gt;También intenta homogeneizar los conectores, utilizando para los motores el mismo tipo de conector que para el resto de los sensores/actuadores.&amp;lt;br&amp;gt; Por otro lado, mantiene muy buenas ideas que fueron incorporadas en el [[Construccion_shield_v1.0|shieldv1]] como ser la identificación de dispositivos mediante pines dedicados a esa tarea. Este mecanismo de plug&amp;amp;play permite conectar cualquier sensor/actuador en cualquier puerto del shield, evitando etapas de configuración en el software.&amp;lt;br&amp;gt;&lt;br /&gt;
La idea fundamental del shield es reducir la cantidad de pines de identificación a un solo pin del microcontrolador. Para esto se  utiliza un multiplexor analógico [http://www.ee.mut.ac.th/datasheet/doc/MC14051.pdf MC14051]. El multiplexor recibe como entrada los 8 pines de identificación (uno por cada conector físico), y mediante 3 pines de direccionamiento se multiplexa los valores de identificación de cada puerto. Para esta tarea se usan 4 bits de microcontrolador, uno para el pin de identificación multiplexado y tres para direccionamiento en el multiplexor.&lt;br /&gt;
&lt;br /&gt;
== Pasos ==&lt;br /&gt;
Fabricación del PCB:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all2.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all3.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Se utilizan conectores RJ45, lo que permite aumentar la robustez del conector y facilidad de fabricación.&amp;lt;br&amp;gt;&lt;br /&gt;
Se colocan en el circuito:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all4.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all5.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Se sueldan:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all6.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Se utilizan headers para permitir conexión con la placa USB4all:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all7.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all8.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Bornera para alimentación de motores:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all9.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all10.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all12.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Resistencias de 10K en cada uno de los puertos para permitir medir la tensión de cada uno de los id de los sensores:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all14.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all15.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Dado que la distancia entre los pines del multiplexor es muy pequeña utilizamos el procedimiento de estañar los pads.&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all13.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Colocamos el multiplexor sobre los pads estañados y aproximando el soldador vamos soldando cada uno de los pines del multiplexor.&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:shield_usb4all11.jpg|720px]]&amp;lt;br&amp;gt;&lt;br /&gt;
Finalmente se conecta el shield a la placa USB4all, el pin marcado con un cuadradito en el shield corresponde con el pin 1 de la USB4all y el microcontrolador pic18f4550 utilizado por la misma.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Divisor resistivo ==&lt;br /&gt;
Para poder identificar los distintos elementos que se van a utilizar, usamos un divisor resistivo como identificador.&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:divisor_resistivo.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
La resistencia R2 va conectada a tierra, la misma se encuetra en la placa ''USB4all shield butia'' y su valor es de 10kΩ.&amp;lt;br&amp;gt;&lt;br /&gt;
En cambio la resistencia R1 es variable lo que nos brinda un margen de acción que nos permite tener diferentes identificadores, lo que nos permite reconocer que sensor ha sido conectado.&amp;lt;br&amp;gt;&lt;br /&gt;
Esta resistencia se conecta a VCC(5V) y se encuentra en el lado del sensor.&amp;lt;br&amp;gt;&lt;br /&gt;
La tensión aproximada del identificador esta dada por la siguiente ecuación:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Archivo:divresistivo.png]]&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Ese voltaje es medido por el pin 10 de la PIC18f4550.&amp;lt;br&amp;gt;&lt;br /&gt;
El diseño e implementación de este circuito no hubiera podido ser realizado sin la ayuda e ideas aportadas por Santiago Reyes.&amp;lt;br&amp;gt;&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1258</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1258"/>
				<updated>2011-10-31T14:15:59Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* 4. Grabando el Firmware */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 1. Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== 2. Arquitectura (Firmware/Hardware)==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo relativo al hardware como las abstracciones necesarias para manejarlo mediante software.&amp;lt;br&amp;gt;&lt;br /&gt;
Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''2.1 USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|Fig.2.1.1: USB4all Baseboard 2.0]]&lt;br /&gt;
Es una placa de entrada/salida(E/S) configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de esta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''2.2 USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''2.3 USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== 3. Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
El protocolo está formado por un stack de protocolos que permiten abstraer al usuario de los detalles subyacentes de la arquitectura. &lt;br /&gt;
El objetivo final del protocolo de comunicación, es direccionar los mensajes provenientes desde la aplicación que se ejecuta en el computador, al ''usermodule'' correspondiente ejecutado en la placa USB4all.&lt;br /&gt;
Estos mensajes son solicitudes de ciertos servicios que los módulos exponen, por ejemplo en el caso de un dispositivo sonoro (buzzer) utilizado para una alarma, va a ser de interés poder emitir sonido (Prender el Buzzer) detener la emisón de sonido (Apagar el Buzzer), hacer sonidos cortos pasando por parámetro la cantidad de milisegundos que se desea esté prendido, etc.&lt;br /&gt;
Estos mensajes se tienen que codificar de alguna manera, el protocolo especifica que primero se debe indicar el comando que se desea se ejecute y luego en caso que sea necesario (como en el de los sonidos cortos) enviar los parámetros. En algunos casos va a ser necesario obtener respuestas, las cuales se codifican de forma análoga usando el mismo protocolo, enviando en lugar de un parámetro un valor de retorno.&lt;br /&gt;
Este protocolo es llamado ''user protocol'' y esta enfocado al usuario final, pero para que el sistema funcioné correctamente es necesario contar con otros protocolos los cuales transportan el protocolo ''user protocol''. Tal es el caso del handler manager protocol que se encarga de manejar el ruteo de los mensajes al ''user module'' correspondiente. Esto se debe a que en un momento determinado puede haber varios ''user modules'' ejecutando en la placa y el sistema debe permitir notificar al módulo del nuevo mensaje. La tarea fundamental de este protocolo es brindar los mecanismos para comunicar una aplicación con un ''user module''. Otro protocolo involucrado es el ''admin protocol'' el cual se encarga de gestionar el ciclo de vida de los ''user modules'', permitiendo poner a ejecutar un ''user module'', cerrarlo y también algunas funcionalidades como el listar los módulos presentes en la placa, cerrar todos los modulos abiertos o llevar al estado de reset al microcontrolador. Tanto el ''handler protocol'' como el ''admin protocol'' son implementados por las bibliotecas que se utilicen en el computador. Existiendo varias opciones, Java, Python o Lua. Actualmente la opción que se está manteniendo es la de Lua la cual puede estudiarse en profundidad en la sección bobot.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:protocolo.png|700px|Fig. 3.2 Protocolo USB4all]]&lt;br /&gt;
&lt;br /&gt;
Finalmente los paquetes USB4all se trasmiten por el protocolo de comunicación que disponga el ''baseboard'', para el caso típico del ''baseboard usb4all'' se trasmite mediante USB, pero puede ser trasmitido mediante otras tecnologías utilizadas para comunicarse con un computador, como ser serial o bluetooth (entre otros).&lt;br /&gt;
&lt;br /&gt;
== 4. Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador hardware, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux.&lt;br /&gt;
Microchip distribuye un bootloader para la familia de microcontroladores 18F. Un bootloader es un programa que se utiliza para grabar y/o actualizar el firmware. En nuestro caso, va a permitr grabar el firmware del proyecto USB4all sin la necesidad de disponer de un programador por hardware, para realizar esto es necesario dejar presionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset. Esto funciona siempre y cuando el microcontrolador tenga grabado el bootloader.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
Dado que Microchip no distribuye microcontroladores con el bootlader previamente grabado, es necesario utilizar un programador por hardware para grabar el bootloader.&lt;br /&gt;
USB4all actualmente utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de presionar los botones, útil a la hora de realizar actualizaciones remotas, pero responde a los mismos comandos que el bootloader de Microchip, lo cual permite reutilizar el software ya desarrollado para interactuar con el bootloader.&lt;br /&gt;
Los fuentes del bootloader pueden encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una vez compilado su grabación se realiza mediante un programador por hardware como picdem o pickit. &lt;br /&gt;
Una vez grabado el bootloader ya '''no es necesario utilizar programadores por hardware''' y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== 5 Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Fig. 5.1:Entorno de desarrollor con Piklab en GNU/Linux]][[Archivo:mplab.png|thumb|Fig. 5.2: Entorno de desarrollor con MPLab en GNU/Linux]]&lt;br /&gt;
El proyecto USB4all está desarrollado para el compilador C18 de Microchip, hoy día se dispone de un buen soporte del mismo para GNU/Linux puediendose descargar de [http://ww1.microchip.com/downloads/MPLAB/X_Beta/installer.html] también se dispone de un entorno de desarrollo llamado MPLab el cual también se encuentra disponible para GNU/Linux en la misma dirección.&lt;br /&gt;
Hace un tiempo atrás no existía compatibilidad para GNU/Linux de estas herramientas clásicas para los ambientes Windows en GNU/Linux. Debiendose recurrir a alternativas para trabajar en un ambiente GNU/Linux, una opción era Piklab. Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC similar a lo que es MPLab. Era muy común utilizar la versión de C18 de windows emulada mediante wine en GNU/Linux debiendose configurar en las opciones de toolchain de PIKLab correspondientes a C18 para que apunten correctamente a los directorios donde se encuentra el compilador C18. En el repositorio puede encontrarse un proyecto piklab configurado de esta manera. Más información sobre la configuración de c18 con piklab en linux (deprecated) ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
&amp;lt;br&amp;gt;Luego de compilar, cargar el binario generado (.hex) en la placa mediante el uso del bootloader que se incluye en el firmware. Esto puede realizarse utilizando la herramienta fsusb como se describe en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== 6. Escribiendo un ''usermodule'' ==&lt;br /&gt;
Un ''usermodule'' es el bloque sobre el cual se representa una realidad y se modela utilizando la arquitectura ''USB4all'', en esta sección se presentan sus características, estructura necesaria para especificar los servicios que brinda y de que forma se anexa al ''firmwarebase''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:user_module.png|thumb|Fig. 6.1: Tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
'''6.1 Estructura de un ''usermodule:'' '''&amp;lt;br&amp;gt;&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que el módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es una estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre. En la sección detalles de implementación en el firmware se puede comocer más sobre el significado de la instrucción #pragma romdata user, podemos por el momento asumir que sirve para almacenar la estructura uTab en un lugar conocido de memoria.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización. A continuación puede verse como ejemplo la inicialización de un módulo de usuario para controlar un buzzer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es una estructura tipo ''case'' en el que se espera por los diferentes comandos que pueden enviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt; COMANDO [argumento1] [argumento2]...[argumentoN] &amp;gt;. La respuesta debe ser del tipo &amp;lt; COMANDO [resultado1] [resultado2]..[resultadoN] &amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devuelven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''6.2 Entrada/Salida en user modules:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren sus rutinas de atención para ser invocadas cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Dentro de éste módulo además se pueden brindar operaciónes con mayor nivel de abstracción relacionadas con el componente a modelar. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el ''usermodule'' a la placa de entrada/salida ''usb4all baseboard'' se debe agregar al proyecto el módulo (utilizando el IDE preferido) y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== 7. Servicios de Timers - T0Service ==&lt;br /&gt;
&lt;br /&gt;
T0service es un módulo encargado de brindar primitivas a los ''user modules'' para ser notificados de eventos del timmer.&lt;br /&gt;
La API expuesta es la siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
	Registers a new event callback, to be called t time units in the future.&lt;br /&gt;
	This function must not be called from a callback handler.&lt;br /&gt;
*/&lt;br /&gt;
BOOL registerT0event(unsigned int t, void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Registers a new event callback, to be called t time units in the future.&lt;br /&gt;
	This function only can be called from a callback handler.&lt;br /&gt;
*/&lt;br /&gt;
BOOL registerT0eventInEvent(unsigned int t, void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Unregister a event callback. No pending event(s) will invoke it.&lt;br /&gt;
*/&lt;br /&gt;
BOOL unregisterT0event(void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Initialize the service&lt;br /&gt;
*/&lt;br /&gt;
void initT0Service(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes áreas que se mapean en secciones definidas dentro de la memoria ROM correspondiente a la memoria de programa del microcontrolador, para implementar esto se necesita especificar en un archivo llamado linker script dónde están alojadas físicamente (en memoria) estas secciones.&lt;br /&gt;
La forma de realizar este mapeo es editando el archivo lrk asociado al proyecto.&lt;br /&gt;
Existe la directiva CODEPAGE que es utilizada para trabajar con las secciones de programa, permite inicializar datos, constantes, y realizar referencias a las mismas. Tiene el siguiente formato&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
donde:&lt;br /&gt;
memName es un string ASCII utilizado para identificar una CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
También existe la directiva DATABANK que permite realizar un manejo similar pero sobre la memoria de datos.&lt;br /&gt;
&lt;br /&gt;
La directiva #pragma &lt;br /&gt;
El estándar ANSI C provee a cada implementación de un método para definir constructores únicos, según sea requerido por la arquitectura del procesador a utilizar. Esto es hecho utilizando la directiva #pragma. La directiva #pragma más común en el compilador utilizado (MPLAB C18) identifica la sección de memoria para ser utilizada en el PIC18XXXX. Por ejemplo #pragma code le indica al compilador MPLAB 18 que compile el código C en la sección de programa de la memoria de programa. La sección de código está definida en el linker script asociado para cada dispositivo PIC18XXXX, especificando en que áreas de la memoria de programa pueden ser ejecutadas instrucciones. &lt;br /&gt;
Esta directiva puede ser insertada directamente o puede ser seguida de la dirección en el área de código del procesador destino, permitiendo tener un control total del a memoria de código. &lt;br /&gt;
En el contexto del USB4all esto es muy utilizado, debido a que se separan varias áreas de memoria, las más importantes son la del bootloader, y la correspondiente a los módulos de usuario, tanto para la parte de programa (module_sec) como para la información del módulo que se almacena para gestionarlo (user_sec).&lt;br /&gt;
Otra directiva #pragma común que se utiliza es #pragma udata, la cual se utiliza cuando se aloja memoria para variables, las variables no inicianlizadas definidas después de esta declaración van a utilizar los registros de proposito general para almacenamiento. La arquitectura del PIC18XXXX, se basa en una arquitectura harvard la que a diferencia de la von neumann almacena las variables y las instrucciones en diferentes espacios de memoria. Por tanto las áreas de memoria deben ser explicitamente identificadas.&lt;br /&gt;
&lt;br /&gt;
Por más información, consultar con el manual del compilador C18 (http://www.kevin.org/frc/C18_3.0_getting_started.pdf) en la sección #pragma DIRECTIVE o SECTIONS.&lt;br /&gt;
&lt;br /&gt;
De la forma que se definieron las secciones en el archivo lkr del proyecto (18f4550.lkr) se debe colocar un #pragma code module al comenzar la declaración de los procedimientos del módulo, de esa forma se almacenan en memoria de programa (code section) dentro de la sección module. Si consultamos el linker script podemos ver que está definida la sección module como un alias del área en ROM llamada module_sec&lt;br /&gt;
&lt;br /&gt;
    SECTION	   NAME=module				ROM=module_sec&lt;br /&gt;
&lt;br /&gt;
a su vez module_sec es definida como:&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE   NAME=module_sec   START=0x40AB       END=0xFFFF PROTECTED&lt;br /&gt;
&lt;br /&gt;
Lo mismo se debe hacer cuando se definen las funciones que utiliza el módulo para atender eventos y su nombre (estructura uTab):&lt;br /&gt;
&lt;br /&gt;
   #pragma romdata user&lt;br /&gt;
   uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
Como vimos en el ejemplo presentado en la sección escribiendo un ''user module''.&lt;br /&gt;
Hay que tener cuidado de no olvidarse de los #pragmas correspondientes ya que de de lo contrario puede no dar el espacio para compilar el proyecto o no funcionar el mecanismo de callbacks.&lt;br /&gt;
Los archivos lkr también especifican otros conceptos, como ser tamaño de memoria de datos y registros que utiliza, como también tamaño del stack&lt;br /&gt;
&lt;br /&gt;
== 9. Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|Fig. 9.1 bobot logo]][[Archivo:componentes.png|thumb|Fig. 9.2 Arquitectura del bobot]][[Archivo:web_bobot.png|thumb|Fig. 9.3 Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010.&amp;lt;br&amp;gt; &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'', de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, primero se debe desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
&lt;br /&gt;
El driver se escribe en Lua, debe seguir un formato preestablecido y es implementado mediante el recurso de tablas que brinda Lua. Una característica de Lua es que las funciones son miembros de primer orden, esto permite (entre otras cosas) que una función pueda ser un tipo de datos válido, pasar funciones como argumento de funciones o como retorno de las mismas y almacenarla en una tabla. &lt;br /&gt;
Esta capacidad permite que dentro de la tabla que representa un driver se puedan almacenar funciones asociadas para cada servicio expuesto por un módulo. Estas funciones son invocadas al solicitarse servicios desde la aplicación que utiliza la biblioteca.&lt;br /&gt;
&lt;br /&gt;
Asociado a cada función se almacenan metadatos que describen los parámetros que la función recibe, su tipo, valor de retorno y valores aceptados.&lt;br /&gt;
Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, como se muestra en la figura 9.3. Este sitio describe al módulo de usuario y se puede usar como documentación y mecanismo de prueba del mismo. &lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''. En este driver podemos ver que se exportan los siguientes servicios:&lt;br /&gt;
* read_version&lt;br /&gt;
* prender&lt;br /&gt;
* apagar&lt;br /&gt;
* buzzer_corto&lt;br /&gt;
* buzzer_triple&lt;br /&gt;
&lt;br /&gt;
El siguiente código corresponde con la implementación de estos servicios en un driver bobot:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol'' y responde al formato de &amp;lt; COMANDO [argumento1] [argumento2]...[argumentoN] &amp;gt; para el pedido y mensajes del tipo &amp;lt; COMANDO [resultado1] [resultado2]..[resultadoN] &amp;gt; para la respuesta. &lt;br /&gt;
&lt;br /&gt;
Entre las características del bobot se encuentra la capacidad de abstraer al usuario del tipo de hardware de placa de E/S está conectada pudiendo ser placas que utilizan comunicación serial rs232c o USB u otra tecnología como también la cantidad de las mismas. En la figura 8.2 puede verse un caso posible, donde se encuentran diferentes ''usermodules'' cargados en una ''baseboard'' y ciertos drivers cargados en el bobot que van a permitir consumir los servicios expuestos por los ''usermodules''.&lt;br /&gt;
&lt;br /&gt;
Como se mencionó al comienzo de la sección, bobot expone un protocolo que puede utilizarse mediante conexiones TCP/IP, este protocolo se describe de esta forma:&lt;br /&gt;
&lt;br /&gt;
    LIST&lt;br /&gt;
    DESCRIBE moduleName&lt;br /&gt;
    CALL moduleName operation param1, param2, ...,paramN&lt;br /&gt;
    OPEN moduleName&lt;br /&gt;
    CLOSEALL&lt;br /&gt;
&lt;br /&gt;
Donde el comando:&lt;br /&gt;
* LIST despliega la lista de módulos disponibles en la placa por su nombre.&lt;br /&gt;
* DESCRIBE muestra la información de que servicios expone el módulo de nombre moduleName e información sobre los parámetros.&lt;br /&gt;
* CALL es utilizado para invocar los servicios expuestos por un módulo.&lt;br /&gt;
* OPEN se utiliza para abirir un módulo, a partir de ese momento el baseboard le asigna tiempo de CPU y recursos al ''usermodule'', actualmente esta deprecado su uso ya que bobot se encarga de abrirlos de forma automática ante la primer invocación.&lt;br /&gt;
* CLOSEALL cierra todos los módulos abiertos en la placa, llevandola a un estado conocido.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
== ANEXO 1 ==&lt;br /&gt;
&lt;br /&gt;
En el enlace [http://sourceforge.net/p/usb4all/code/ci/6ecc2581f50519fe427f7a3947136c2a03108841/tree/firmware/u4a2/user/usr_buzzer.c] y [http://sourceforge.net/p/usb4all/code/ci/6ecc2581f50519fe427f7a3947136c2a03108841/tree/firmware/u4a2/user/usr_buzzer.h] puede descargarse el código completo del ejemplo presentado como caso de estudio. El mismo puede usarse como esqueleto para desarrollar otros ''user modules''&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1257</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1257"/>
				<updated>2011-10-31T12:53:44Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* 3. Protocolo de Comunicación */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 1. Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== 2. Arquitectura (Firmware/Hardware)==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo relativo al hardware como las abstracciones necesarias para manejarlo mediante software.&amp;lt;br&amp;gt;&lt;br /&gt;
Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''2.1 USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|Fig.2.1.1: USB4all Baseboard 2.0]]&lt;br /&gt;
Es una placa de entrada/salida(E/S) configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de esta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''2.2 USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''2.3 USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== 3. Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
El protocolo está formado por un stack de protocolos que permiten abstraer al usuario de los detalles subyacentes de la arquitectura. &lt;br /&gt;
El objetivo final del protocolo de comunicación, es direccionar los mensajes provenientes desde la aplicación que se ejecuta en el computador, al ''usermodule'' correspondiente ejecutado en la placa USB4all.&lt;br /&gt;
Estos mensajes son solicitudes de ciertos servicios que los módulos exponen, por ejemplo en el caso de un dispositivo sonoro (buzzer) utilizado para una alarma, va a ser de interés poder emitir sonido (Prender el Buzzer) detener la emisón de sonido (Apagar el Buzzer), hacer sonidos cortos pasando por parámetro la cantidad de milisegundos que se desea esté prendido, etc.&lt;br /&gt;
Estos mensajes se tienen que codificar de alguna manera, el protocolo especifica que primero se debe indicar el comando que se desea se ejecute y luego en caso que sea necesario (como en el de los sonidos cortos) enviar los parámetros. En algunos casos va a ser necesario obtener respuestas, las cuales se codifican de forma análoga usando el mismo protocolo, enviando en lugar de un parámetro un valor de retorno.&lt;br /&gt;
Este protocolo es llamado ''user protocol'' y esta enfocado al usuario final, pero para que el sistema funcioné correctamente es necesario contar con otros protocolos los cuales transportan el protocolo ''user protocol''. Tal es el caso del handler manager protocol que se encarga de manejar el ruteo de los mensajes al ''user module'' correspondiente. Esto se debe a que en un momento determinado puede haber varios ''user modules'' ejecutando en la placa y el sistema debe permitir notificar al módulo del nuevo mensaje. La tarea fundamental de este protocolo es brindar los mecanismos para comunicar una aplicación con un ''user module''. Otro protocolo involucrado es el ''admin protocol'' el cual se encarga de gestionar el ciclo de vida de los ''user modules'', permitiendo poner a ejecutar un ''user module'', cerrarlo y también algunas funcionalidades como el listar los módulos presentes en la placa, cerrar todos los modulos abiertos o llevar al estado de reset al microcontrolador. Tanto el ''handler protocol'' como el ''admin protocol'' son implementados por las bibliotecas que se utilicen en el computador. Existiendo varias opciones, Java, Python o Lua. Actualmente la opción que se está manteniendo es la de Lua la cual puede estudiarse en profundidad en la sección bobot.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:protocolo.png|700px|Fig. 3.2 Protocolo USB4all]]&lt;br /&gt;
&lt;br /&gt;
Finalmente los paquetes USB4all se trasmiten por el protocolo de comunicación que disponga el ''baseboard'', para el caso típico del ''baseboard usb4all'' se trasmite mediante USB, pero puede ser trasmitido mediante otras tecnologías utilizadas para comunicarse con un computador, como ser serial o bluetooth (entre otros).&lt;br /&gt;
&lt;br /&gt;
== 4. Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux.&lt;br /&gt;
Microchip disrtibuye un bootloader para la familia de microcontroladores 18F. Un bootloader es unprograma que se utiliza para grabar otro. En nuestro caso, va a permitr grabar el firmware del proyecto USB4all sin la necesidad de disponer de un programador por hardware, para realizar esto es necesario dejar prescionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset. Esto funciona siempre y cuando el microcontrolador tenga grabado el bootloader.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
Dado que Microchip no distribuye microcontroladores con el bootlader previamente grabado, es necesario utilizar un programador por hardware para grabar el bootloader.&lt;br /&gt;
USB4all acutalmente utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de prescionar los botones, útil a la hora de realizar actualizaciones remotas, pero responde a los mismos comandos que el bootloader de Microchip, lo cual permite reutilizar el software ya desarrollado para interactuar con el bootloader.&lt;br /&gt;
Los fuentes del bootloader pueden encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una vez compilado su grabación se realiza mediante un programador por hardware como picdem o pickit. &lt;br /&gt;
Una vez grabado el bootloader ya '''no es necesario utilizar programadores por hardware''' y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe de estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== 5 Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Fig. 5.1:Entorno de desarrollor con Piklab en GNU/Linux]][[Archivo:mplab.png|thumb|Fig. 5.2: Entorno de desarrollor con MPLab en GNU/Linux]]&lt;br /&gt;
El proyecto USB4all está desarrollado para el compilador C18 de Microchip, hoy día se dispone de un buen soporte del mismo para GNU/Linux puediendose descargar de [http://ww1.microchip.com/downloads/MPLAB/X_Beta/installer.html] también se dispone de un entorno de desarrollo llamado MPLab el cual también se encuentra disponible para GNU/Linux en la misma dirección.&lt;br /&gt;
Hace un tiempo atrás no existía compatibilidad para GNU/Linux de estas herramientas clásicas para los ambientes Windows en GNU/Linux. Debiendose recurrir a alternativas para trabajar en un ambiente GNU/Linux, una opción era Piklab. Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC similar a lo que es MPLab. Era muy común utilizar la versión de C18 de windows emulada mediante wine en GNU/Linux debiendose configurar en las opciones de toolchain de PIKLab correspondientes a C18 para que apunten correctamente a los directorios donde se encuentra el compilador C18. En el repositorio puede encontrarse un proyecto piklab configurado de esta manera. Más información sobre la configuración de c18 con piklab en linux (deprecated) ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
&amp;lt;br&amp;gt;Luego de compilar, cargar el binario generado (.hex) en la placa mediante el uso del bootloader que se incluye en el firmware. Esto puede realizarse utilizando la herramienta fsusb como se describe en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== 6. Escribiendo un ''usermodule'' ==&lt;br /&gt;
Un ''usermodule'' es el bloque sobre el cual se representa una realidad y se modela utilizando la arquitectura ''USB4all'', en esta sección se presentan sus características, estructura necesaria para especificar los servicios que brinda y de que forma se anexa al ''firmwarebase''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:user_module.png|thumb|Fig. 6.1: Tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
'''6.1 Estructura de un ''usermodule:'' '''&amp;lt;br&amp;gt;&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que el módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es una estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre. En la sección detalles de implementación en el firmware se puede comocer más sobre el significado de la instrucción #pragma romdata user, podemos por el momento asumir que sirve para almacenar la estructura uTab en un lugar conocido de memoria.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización. A continuación puede verse como ejemplo la inicialización de un módulo de usuario para controlar un buzzer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es una estructura tipo ''case'' en el que se espera por los diferentes comandos que pueden enviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt; COMANDO [argumento1] [argumento2]...[argumentoN] &amp;gt;. La respuesta debe ser del tipo &amp;lt; COMANDO [resultado1] [resultado2]..[resultadoN] &amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devuelven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''6.2 Entrada/Salida en user modules:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren sus rutinas de atención para ser invocadas cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Dentro de éste módulo además se pueden brindar operaciónes con mayor nivel de abstracción relacionadas con el componente a modelar. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el ''usermodule'' a la placa de entrada/salida ''usb4all baseboard'' se debe agregar al proyecto el módulo (utilizando el IDE preferido) y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== 7. Servicios de Timers - T0Service ==&lt;br /&gt;
&lt;br /&gt;
T0service es un módulo encargado de brindar primitivas a los ''user modules'' para ser notificados de eventos del timmer.&lt;br /&gt;
La API expuesta es la siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
	Registers a new event callback, to be called t time units in the future.&lt;br /&gt;
	This function must not be called from a callback handler.&lt;br /&gt;
*/&lt;br /&gt;
BOOL registerT0event(unsigned int t, void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Registers a new event callback, to be called t time units in the future.&lt;br /&gt;
	This function only can be called from a callback handler.&lt;br /&gt;
*/&lt;br /&gt;
BOOL registerT0eventInEvent(unsigned int t, void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Unregister a event callback. No pending event(s) will invoke it.&lt;br /&gt;
*/&lt;br /&gt;
BOOL unregisterT0event(void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Initialize the service&lt;br /&gt;
*/&lt;br /&gt;
void initT0Service(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes áreas que se mapean en secciones definidas dentro de la memoria ROM correspondiente a la memoria de programa del microcontrolador, para implementar esto se necesita especificar en un archivo llamado linker script dónde están alojadas físicamente (en memoria) estas secciones.&lt;br /&gt;
La forma de realizar este mapeo es editando el archivo lrk asociado al proyecto.&lt;br /&gt;
Existe la directiva CODEPAGE que es utilizada para trabajar con las secciones de programa, permite inicializar datos, constantes, y realizar referencias a las mismas. Tiene el siguiente formato&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
donde:&lt;br /&gt;
memName es un string ASCII utilizado para identificar una CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
También existe la directiva DATABANK que permite realizar un manejo similar pero sobre la memoria de datos.&lt;br /&gt;
&lt;br /&gt;
La directiva #pragma &lt;br /&gt;
El estándar ANSI C provee a cada implementación de un método para definir constructores únicos, según sea requerido por la arquitectura del procesador a utilizar. Esto es hecho utilizando la directiva #pragma. La directiva #pragma más común en el compilador utilizado (MPLAB C18) identifica la sección de memoria para ser utilizada en el PIC18XXXX. Por ejemplo #pragma code le indica al compilador MPLAB 18 que compile el código C en la sección de programa de la memoria de programa. La sección de código está definida en el linker script asociado para cada dispositivo PIC18XXXX, especificando en que áreas de la memoria de programa pueden ser ejecutadas instrucciones. &lt;br /&gt;
Esta directiva puede ser insertada directamente o puede ser seguida de la dirección en el área de código del procesador destino, permitiendo tener un control total del a memoria de código. &lt;br /&gt;
En el contexto del USB4all esto es muy utilizado, debido a que se separan varias áreas de memoria, las más importantes son la del bootloader, y la correspondiente a los módulos de usuario, tanto para la parte de programa (module_sec) como para la información del módulo que se almacena para gestionarlo (user_sec).&lt;br /&gt;
Otra directiva #pragma común que se utiliza es #pragma udata, la cual se utiliza cuando se aloja memoria para variables, las variables no inicianlizadas definidas después de esta declaración van a utilizar los registros de proposito general para almacenamiento. La arquitectura del PIC18XXXX, se basa en una arquitectura harvard la que a diferencia de la von neumann almacena las variables y las instrucciones en diferentes espacios de memoria. Por tanto las áreas de memoria deben ser explicitamente identificadas.&lt;br /&gt;
&lt;br /&gt;
Por más información, consultar con el manual del compilador C18 (http://www.kevin.org/frc/C18_3.0_getting_started.pdf) en la sección #pragma DIRECTIVE o SECTIONS.&lt;br /&gt;
&lt;br /&gt;
De la forma que se definieron las secciones en el archivo lkr del proyecto (18f4550.lkr) se debe colocar un #pragma code module al comenzar la declaración de los procedimientos del módulo, de esa forma se almacenan en memoria de programa (code section) dentro de la sección module. Si consultamos el linker script podemos ver que está definida la sección module como un alias del área en ROM llamada module_sec&lt;br /&gt;
&lt;br /&gt;
    SECTION	   NAME=module				ROM=module_sec&lt;br /&gt;
&lt;br /&gt;
a su vez module_sec es definida como:&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE   NAME=module_sec   START=0x40AB       END=0xFFFF PROTECTED&lt;br /&gt;
&lt;br /&gt;
Lo mismo se debe hacer cuando se definen las funciones que utiliza el módulo para atender eventos y su nombre (estructura uTab):&lt;br /&gt;
&lt;br /&gt;
   #pragma romdata user&lt;br /&gt;
   uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
Como vimos en el ejemplo presentado en la sección escribiendo un ''user module''.&lt;br /&gt;
Hay que tener cuidado de no olvidarse de los #pragmas correspondientes ya que de de lo contrario puede no dar el espacio para compilar el proyecto o no funcionar el mecanismo de callbacks.&lt;br /&gt;
Los archivos lkr también especifican otros conceptos, como ser tamaño de memoria de datos y registros que utiliza, como también tamaño del stack&lt;br /&gt;
&lt;br /&gt;
== 9. Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|Fig. 9.1 bobot logo]][[Archivo:componentes.png|thumb|Fig. 9.2 Arquitectura del bobot]][[Archivo:web_bobot.png|thumb|Fig. 9.3 Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010.&amp;lt;br&amp;gt; &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'', de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, primero se debe desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
&lt;br /&gt;
El driver se escribe en Lua, debe seguir un formato preestablecido y es implementado mediante el recurso de tablas que brinda Lua. Una característica de Lua es que las funciones son miembros de primer orden, esto permite (entre otras cosas) que una función pueda ser un tipo de datos válido, pasar funciones como argumento de funciones o como retorno de las mismas y almacenarla en una tabla. &lt;br /&gt;
Esta capacidad permite que dentro de la tabla que representa un driver se puedan almacenar funciones asociadas para cada servicio expuesto por un módulo. Estas funciones son invocadas al solicitarse servicios desde la aplicación que utiliza la biblioteca.&lt;br /&gt;
&lt;br /&gt;
Asociado a cada función se almacenan metadatos que describen los parámetros que la función recibe, su tipo, valor de retorno y valores aceptados.&lt;br /&gt;
Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, como se muestra en la figura 9.3. Este sitio describe al módulo de usuario y se puede usar como documentación y mecanismo de prueba del mismo. &lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''. En este driver podemos ver que se exportan los siguientes servicios:&lt;br /&gt;
* read_version&lt;br /&gt;
* prender&lt;br /&gt;
* apagar&lt;br /&gt;
* buzzer_corto&lt;br /&gt;
* buzzer_triple&lt;br /&gt;
&lt;br /&gt;
El siguiente código corresponde con la implementación de estos servicios en un driver bobot:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol'' y responde al formato de &amp;lt; COMANDO [argumento1] [argumento2]...[argumentoN] &amp;gt; para el pedido y mensajes del tipo &amp;lt; COMANDO [resultado1] [resultado2]..[resultadoN] &amp;gt; para la respuesta. &lt;br /&gt;
&lt;br /&gt;
Entre las características del bobot se encuentra la capacidad de abstraer al usuario del tipo de hardware de placa de E/S está conectada pudiendo ser placas que utilizan comunicación serial rs232c o USB u otra tecnología como también la cantidad de las mismas. En la figura 8.2 puede verse un caso posible, donde se encuentran diferentes ''usermodules'' cargados en una ''baseboard'' y ciertos drivers cargados en el bobot que van a permitir consumir los servicios expuestos por los ''usermodules''.&lt;br /&gt;
&lt;br /&gt;
Como se mencionó al comienzo de la sección, bobot expone un protocolo que puede utilizarse mediante conexiones TCP/IP, este protocolo se describe de esta forma:&lt;br /&gt;
&lt;br /&gt;
    LIST&lt;br /&gt;
    DESCRIBE moduleName&lt;br /&gt;
    CALL moduleName operation param1, param2, ...,paramN&lt;br /&gt;
    OPEN moduleName&lt;br /&gt;
    CLOSEALL&lt;br /&gt;
&lt;br /&gt;
Donde el comando:&lt;br /&gt;
* LIST despliega la lista de módulos disponibles en la placa por su nombre.&lt;br /&gt;
* DESCRIBE muestra la información de que servicios expone el módulo de nombre moduleName e información sobre los parámetros.&lt;br /&gt;
* CALL es utilizado para invocar los servicios expuestos por un módulo.&lt;br /&gt;
* OPEN se utiliza para abirir un módulo, a partir de ese momento el baseboard le asigna tiempo de CPU y recursos al ''usermodule'', actualmente esta deprecado su uso ya que bobot se encarga de abrirlos de forma automática ante la primer invocación.&lt;br /&gt;
* CLOSEALL cierra todos los módulos abiertos en la placa, llevandola a un estado conocido.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
== ANEXO 1 ==&lt;br /&gt;
&lt;br /&gt;
En el enlace [http://sourceforge.net/p/usb4all/code/ci/6ecc2581f50519fe427f7a3947136c2a03108841/tree/firmware/u4a2/user/usr_buzzer.c] y [http://sourceforge.net/p/usb4all/code/ci/6ecc2581f50519fe427f7a3947136c2a03108841/tree/firmware/u4a2/user/usr_buzzer.h] puede descargarse el código completo del ejemplo presentado como caso de estudio. El mismo puede usarse como esqueleto para desarrollar otros ''user modules''&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1256</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1256"/>
				<updated>2011-10-31T12:33:32Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* 3. Protocolo de Comunicación */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 1. Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== 2. Arquitectura (Firmware/Hardware)==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo relativo al hardware como las abstracciones necesarias para manejarlo mediante software.&amp;lt;br&amp;gt;&lt;br /&gt;
Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''2.1 USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|Fig.2.1.1: USB4all Baseboard 2.0]]&lt;br /&gt;
Es una placa de entrada/salida(E/S) configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de esta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''2.2 USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''2.3 USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== 3. Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
El protocolo está formado por un stack de protocolos que permiten abstraer al usuario de los detalles subyacentes de la arquitectura. &lt;br /&gt;
El objetivo final del protocolo de comunicación, es direccionar los mensajes provenientes desde la aplicación que se ejecuta en el computador, al ''usermodule'' correspondiente ejecutado en la placa USB4all.&lt;br /&gt;
Estos mensajes son solicitudes de ciertos servicios que los módulos exponen, por ejemplo en el caso de un dispositivo sonoro (buzzer) utilizado para una alarma, va a ser de interés poder emitir sonido (Prender el Buzzer) detener la emisón de sonido (Apagar el Buzzer), hacer sonidos cortos pasando por parámetro la cantidad de milisegundos que se desea esté prendido, etc.&lt;br /&gt;
Estos mensajes se tienen que codificar de alguna manera, el protocolo especifica que primero se debe indicar el comando que se desea se ejecute y luego en caso que sea necesario (como en el de los sonidos cortos) enviar los parámetros. En algunos casos va a ser necesario obtener respuestas, las cuales se codifican de forma análoga usando el mismo protocolo, enviando en lugar de un parámetro un valor de retorno.&lt;br /&gt;
Este protocolo es el que se llama ''user protocol'' y esta enfocado al usuario final, pero para que el sistema funcioné correctamente es necesario contar con otros protocolos los cuales transportan el protocolo ''user protocol''. Tal es el caso del handler manager protocol que se encarga de manejar el ruteo de los mensajes al ''user module'' correspondiente. Esto se debe a que en un momento determinado puede haber varios ''user modules'' ejecutando en la placa y el sistema debe permitir notificar al módulo del nuevo mensaje. La tarea fundamental de este protocolo es brindar los mecanismos para comunicar una aplicación con un ''user module''. Otro protocolo involucrado es el ''admin protocol'' el cual se encarga de gestionar el ciclo de vida de los ''user modules'', permitiendo poner a ejecutar un ''user module'', cerrarlo y también algunas funcionalidades como el listar los módulos presentes en la placa, cerrar todos los modulos abiertos o llevar al estado de reset al microcontrolador. Tanto el ''handler protocol'' como el ''admin protocol'' son implementados por las bibliotecas que se utilicen en el computador. Existiendo varias opciones, Java, Python o Lua. Actualmente la opción que se está manteniendo es la de Lua la cual puede estudiarse en profundidad en la sección bobot.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:protocolo.png|700px|Fig. 3.2 Protocolo USB4all]]&lt;br /&gt;
&lt;br /&gt;
Finalmente los paquetes USB4all se trasmiten por el protocolo de comunicación que disponga el ''baseboard'', para el caso típico del ''baseboard usb4all'' se trasmite mediante USB, pero puede ser trasmitido mediante otras tecnologías utilizadas para comunicarse con un computador, como ser serial o bluetooth (entre otros).&lt;br /&gt;
&lt;br /&gt;
== 4. Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux.&lt;br /&gt;
Microchip disrtibuye un bootloader para la familia de microcontroladores 18F. Un bootloader es unprograma que se utiliza para grabar otro. En nuestro caso, va a permitr grabar el firmware del proyecto USB4all sin la necesidad de disponer de un programador por hardware, para realizar esto es necesario dejar prescionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset. Esto funciona siempre y cuando el microcontrolador tenga grabado el bootloader.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
Dado que Microchip no distribuye microcontroladores con el bootlader previamente grabado, es necesario utilizar un programador por hardware para grabar el bootloader.&lt;br /&gt;
USB4all acutalmente utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de prescionar los botones, útil a la hora de realizar actualizaciones remotas, pero responde a los mismos comandos que el bootloader de Microchip, lo cual permite reutilizar el software ya desarrollado para interactuar con el bootloader.&lt;br /&gt;
Los fuentes del bootloader pueden encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una vez compilado su grabación se realiza mediante un programador por hardware como picdem o pickit. &lt;br /&gt;
Una vez grabado el bootloader ya '''no es necesario utilizar programadores por hardware''' y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe de estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== 5 Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Fig. 5.1:Entorno de desarrollor con Piklab en GNU/Linux]][[Archivo:mplab.png|thumb|Fig. 5.2: Entorno de desarrollor con MPLab en GNU/Linux]]&lt;br /&gt;
El proyecto USB4all está desarrollado para el compilador C18 de Microchip, hoy día se dispone de un buen soporte del mismo para GNU/Linux puediendose descargar de [http://ww1.microchip.com/downloads/MPLAB/X_Beta/installer.html] también se dispone de un entorno de desarrollo llamado MPLab el cual también se encuentra disponible para GNU/Linux en la misma dirección.&lt;br /&gt;
Hace un tiempo atrás no existía compatibilidad para GNU/Linux de estas herramientas clásicas para los ambientes Windows en GNU/Linux. Debiendose recurrir a alternativas para trabajar en un ambiente GNU/Linux, una opción era Piklab. Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC similar a lo que es MPLab. Era muy común utilizar la versión de C18 de windows emulada mediante wine en GNU/Linux debiendose configurar en las opciones de toolchain de PIKLab correspondientes a C18 para que apunten correctamente a los directorios donde se encuentra el compilador C18. En el repositorio puede encontrarse un proyecto piklab configurado de esta manera. Más información sobre la configuración de c18 con piklab en linux (deprecated) ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
&amp;lt;br&amp;gt;Luego de compilar, cargar el binario generado (.hex) en la placa mediante el uso del bootloader que se incluye en el firmware. Esto puede realizarse utilizando la herramienta fsusb como se describe en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== 6. Escribiendo un ''usermodule'' ==&lt;br /&gt;
Un ''usermodule'' es el bloque sobre el cual se representa una realidad y se modela utilizando la arquitectura ''USB4all'', en esta sección se presentan sus características, estructura necesaria para especificar los servicios que brinda y de que forma se anexa al ''firmwarebase''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:user_module.png|thumb|Fig. 6.1: Tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
'''6.1 Estructura de un ''usermodule:'' '''&amp;lt;br&amp;gt;&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que el módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es una estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre. En la sección detalles de implementación en el firmware se puede comocer más sobre el significado de la instrucción #pragma romdata user, podemos por el momento asumir que sirve para almacenar la estructura uTab en un lugar conocido de memoria.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización. A continuación puede verse como ejemplo la inicialización de un módulo de usuario para controlar un buzzer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es una estructura tipo ''case'' en el que se espera por los diferentes comandos que pueden enviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt; COMANDO [argumento1] [argumento2]...[argumentoN] &amp;gt;. La respuesta debe ser del tipo &amp;lt; COMANDO [resultado1] [resultado2]..[resultadoN] &amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devuelven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''6.2 Entrada/Salida en user modules:'''&amp;lt;br&amp;gt;&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren sus rutinas de atención para ser invocadas cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Dentro de éste módulo además se pueden brindar operaciónes con mayor nivel de abstracción relacionadas con el componente a modelar. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el ''usermodule'' a la placa de entrada/salida ''usb4all baseboard'' se debe agregar al proyecto el módulo (utilizando el IDE preferido) y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== 7. Servicios de Timers - T0Service ==&lt;br /&gt;
&lt;br /&gt;
T0service es un módulo encargado de brindar primitivas a los ''user modules'' para ser notificados de eventos del timmer.&lt;br /&gt;
La API expuesta es la siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
	Registers a new event callback, to be called t time units in the future.&lt;br /&gt;
	This function must not be called from a callback handler.&lt;br /&gt;
*/&lt;br /&gt;
BOOL registerT0event(unsigned int t, void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Registers a new event callback, to be called t time units in the future.&lt;br /&gt;
	This function only can be called from a callback handler.&lt;br /&gt;
*/&lt;br /&gt;
BOOL registerT0eventInEvent(unsigned int t, void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Unregister a event callback. No pending event(s) will invoke it.&lt;br /&gt;
*/&lt;br /&gt;
BOOL unregisterT0event(void (*callback)(void));&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
	Initialize the service&lt;br /&gt;
*/&lt;br /&gt;
void initT0Service(void);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 8. Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes áreas que se mapean en secciones definidas dentro de la memoria ROM correspondiente a la memoria de programa del microcontrolador, para implementar esto se necesita especificar en un archivo llamado linker script dónde están alojadas físicamente (en memoria) estas secciones.&lt;br /&gt;
La forma de realizar este mapeo es editando el archivo lrk asociado al proyecto.&lt;br /&gt;
Existe la directiva CODEPAGE que es utilizada para trabajar con las secciones de programa, permite inicializar datos, constantes, y realizar referencias a las mismas. Tiene el siguiente formato&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
donde:&lt;br /&gt;
memName es un string ASCII utilizado para identificar una CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
También existe la directiva DATABANK que permite realizar un manejo similar pero sobre la memoria de datos.&lt;br /&gt;
&lt;br /&gt;
La directiva #pragma &lt;br /&gt;
El estándar ANSI C provee a cada implementación de un método para definir constructores únicos, según sea requerido por la arquitectura del procesador a utilizar. Esto es hecho utilizando la directiva #pragma. La directiva #pragma más común en el compilador utilizado (MPLAB C18) identifica la sección de memoria para ser utilizada en el PIC18XXXX. Por ejemplo #pragma code le indica al compilador MPLAB 18 que compile el código C en la sección de programa de la memoria de programa. La sección de código está definida en el linker script asociado para cada dispositivo PIC18XXXX, especificando en que áreas de la memoria de programa pueden ser ejecutadas instrucciones. &lt;br /&gt;
Esta directiva puede ser insertada directamente o puede ser seguida de la dirección en el área de código del procesador destino, permitiendo tener un control total del a memoria de código. &lt;br /&gt;
En el contexto del USB4all esto es muy utilizado, debido a que se separan varias áreas de memoria, las más importantes son la del bootloader, y la correspondiente a los módulos de usuario, tanto para la parte de programa (module_sec) como para la información del módulo que se almacena para gestionarlo (user_sec).&lt;br /&gt;
Otra directiva #pragma común que se utiliza es #pragma udata, la cual se utiliza cuando se aloja memoria para variables, las variables no inicianlizadas definidas después de esta declaración van a utilizar los registros de proposito general para almacenamiento. La arquitectura del PIC18XXXX, se basa en una arquitectura harvard la que a diferencia de la von neumann almacena las variables y las instrucciones en diferentes espacios de memoria. Por tanto las áreas de memoria deben ser explicitamente identificadas.&lt;br /&gt;
&lt;br /&gt;
Por más información, consultar con el manual del compilador C18 (http://www.kevin.org/frc/C18_3.0_getting_started.pdf) en la sección #pragma DIRECTIVE o SECTIONS.&lt;br /&gt;
&lt;br /&gt;
De la forma que se definieron las secciones en el archivo lkr del proyecto (18f4550.lkr) se debe colocar un #pragma code module al comenzar la declaración de los procedimientos del módulo, de esa forma se almacenan en memoria de programa (code section) dentro de la sección module. Si consultamos el linker script podemos ver que está definida la sección module como un alias del área en ROM llamada module_sec&lt;br /&gt;
&lt;br /&gt;
    SECTION	   NAME=module				ROM=module_sec&lt;br /&gt;
&lt;br /&gt;
a su vez module_sec es definida como:&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE   NAME=module_sec   START=0x40AB       END=0xFFFF PROTECTED&lt;br /&gt;
&lt;br /&gt;
Lo mismo se debe hacer cuando se definen las funciones que utiliza el módulo para atender eventos y su nombre (estructura uTab):&lt;br /&gt;
&lt;br /&gt;
   #pragma romdata user&lt;br /&gt;
   uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
Como vimos en el ejemplo presentado en la sección escribiendo un ''user module''.&lt;br /&gt;
Hay que tener cuidado de no olvidarse de los #pragmas correspondientes ya que de de lo contrario puede no dar el espacio para compilar el proyecto o no funcionar el mecanismo de callbacks.&lt;br /&gt;
Los archivos lkr también especifican otros conceptos, como ser tamaño de memoria de datos y registros que utiliza, como también tamaño del stack&lt;br /&gt;
&lt;br /&gt;
== 9. Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|Fig. 9.1 bobot logo]][[Archivo:componentes.png|thumb|Fig. 9.2 Arquitectura del bobot]][[Archivo:web_bobot.png|thumb|Fig. 9.3 Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010.&amp;lt;br&amp;gt; &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'', de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, primero se debe desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
&lt;br /&gt;
El driver se escribe en Lua, debe seguir un formato preestablecido y es implementado mediante el recurso de tablas que brinda Lua. Una característica de Lua es que las funciones son miembros de primer orden, esto permite (entre otras cosas) que una función pueda ser un tipo de datos válido, pasar funciones como argumento de funciones o como retorno de las mismas y almacenarla en una tabla. &lt;br /&gt;
Esta capacidad permite que dentro de la tabla que representa un driver se puedan almacenar funciones asociadas para cada servicio expuesto por un módulo. Estas funciones son invocadas al solicitarse servicios desde la aplicación que utiliza la biblioteca.&lt;br /&gt;
&lt;br /&gt;
Asociado a cada función se almacenan metadatos que describen los parámetros que la función recibe, su tipo, valor de retorno y valores aceptados.&lt;br /&gt;
Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, como se muestra en la figura 9.3. Este sitio describe al módulo de usuario y se puede usar como documentación y mecanismo de prueba del mismo. &lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''. En este driver podemos ver que se exportan los siguientes servicios:&lt;br /&gt;
* read_version&lt;br /&gt;
* prender&lt;br /&gt;
* apagar&lt;br /&gt;
* buzzer_corto&lt;br /&gt;
* buzzer_triple&lt;br /&gt;
&lt;br /&gt;
El siguiente código corresponde con la implementación de estos servicios en un driver bobot:&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol'' y responde al formato de &amp;lt; COMANDO [argumento1] [argumento2]...[argumentoN] &amp;gt; para el pedido y mensajes del tipo &amp;lt; COMANDO [resultado1] [resultado2]..[resultadoN] &amp;gt; para la respuesta. &lt;br /&gt;
&lt;br /&gt;
Entre las características del bobot se encuentra la capacidad de abstraer al usuario del tipo de hardware de placa de E/S está conectada pudiendo ser placas que utilizan comunicación serial rs232c o USB u otra tecnología como también la cantidad de las mismas. En la figura 8.2 puede verse un caso posible, donde se encuentran diferentes ''usermodules'' cargados en una ''baseboard'' y ciertos drivers cargados en el bobot que van a permitir consumir los servicios expuestos por los ''usermodules''.&lt;br /&gt;
&lt;br /&gt;
Como se mencionó al comienzo de la sección, bobot expone un protocolo que puede utilizarse mediante conexiones TCP/IP, este protocolo se describe de esta forma:&lt;br /&gt;
&lt;br /&gt;
    LIST&lt;br /&gt;
    DESCRIBE moduleName&lt;br /&gt;
    CALL moduleName operation param1, param2, ...,paramN&lt;br /&gt;
    OPEN moduleName&lt;br /&gt;
    CLOSEALL&lt;br /&gt;
&lt;br /&gt;
Donde el comando:&lt;br /&gt;
* LIST despliega la lista de módulos disponibles en la placa por su nombre.&lt;br /&gt;
* DESCRIBE muestra la información de que servicios expone el módulo de nombre moduleName e información sobre los parámetros.&lt;br /&gt;
* CALL es utilizado para invocar los servicios expuestos por un módulo.&lt;br /&gt;
* OPEN se utiliza para abirir un módulo, a partir de ese momento el baseboard le asigna tiempo de CPU y recursos al ''usermodule'', actualmente esta deprecado su uso ya que bobot se encarga de abrirlos de forma automática ante la primer invocación.&lt;br /&gt;
* CLOSEALL cierra todos los módulos abiertos en la placa, llevandola a un estado conocido.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
== ANEXO 1 ==&lt;br /&gt;
&lt;br /&gt;
En el enlace [http://sourceforge.net/p/usb4all/code/ci/6ecc2581f50519fe427f7a3947136c2a03108841/tree/firmware/u4a2/user/usr_buzzer.c] y [http://sourceforge.net/p/usb4all/code/ci/6ecc2581f50519fe427f7a3947136c2a03108841/tree/firmware/u4a2/user/usr_buzzer.h] puede descargarse el código completo del ejemplo presentado como caso de estudio. El mismo puede usarse como esqueleto para desarrollar otros ''user modules''&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1073</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1073"/>
				<updated>2011-10-05T19:08:16Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* Bobot */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== Arquitectura ==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo concerniente al hardware como las abstracciones necesarias para manejarlo mediante software. Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|USB4all Baseboard]]&lt;br /&gt;
Es una placa de entrada/salida configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de ésta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
==Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux&lt;br /&gt;
Microchip disrtibuye un bootloader para ésta familia de microcontroladores, el cual permite grabar el firmware sin la necesidad de disponer de un programador, para realizar esto es necesario dejar prescionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
La versión 2.0 de la placa USB4all utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de prescionar los botones.&lt;br /&gt;
La misma puede encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una ves compilado su grabación se realiza mediante un programador por hardware como picdem o pickit.&lt;br /&gt;
Una vez grabado el bootloader ya no es necesario utilizar programadores por hardware y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe de estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Entorno de desarrollor con piklab]]&lt;br /&gt;
Una de las opciones posibles para trabajar en un ambiente GNU/Linux es instalar el Piklab, Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC, el proyecto USB4all utiliza el compilador C18 de Microchip el cual solo está disponible para Windows, para hacerlo funcionar se utiliza wine y se debe configurar el toolchain C18 en piklab para que apunte correctamente a los directorios donde se encuentra el compilador C18. &lt;br /&gt;
Una limitante que posee este compilador es que no permite rutas de archivos que sean muy largas, lo cual es fácilmente alcanzado utilizando wine, por lo tanto se recomienda que el proyecto este lo más cercano a la raíz posible.&lt;br /&gt;
Más información sobre la configuración de c18 con piklab en linux ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
Otra opción es utilizar MPlab que actualmente trae soporte para GNU/Linux [http://microchip.wikidot.com/mplab:_start]&lt;br /&gt;
En el repositorio USB4all puede descargarse un proyecto ya armado para trabajar con piklab, compilando contra c18 mediante wine. Luego de compilar, cargar el binario en la placa mediante el uso del bootloader que se incluye en el firmware, utilizando la utilidad fsusb como fue descripto en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== Escribiendo un ''usermodule'' ==&lt;br /&gt;
[[Archivo:user_module.png|thumb|tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que el módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es una estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es un case en el que se espera por los diferentes comandos que pueden enviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt;comando&amp;gt;&amp;lt;argumento1&amp;gt;...&amp;lt;argumentoN&amp;gt;. La respuesta debe ser del tipo &amp;lt;comando&amp;gt;&amp;lt;resultado1&amp;gt;...&amp;lt;resultadoN&amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devuelven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''Entrada/Salida en user modules:'''&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren para ser notificados cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el usermodule a la placa de entrada salida usb4all ''baseboard'' se debe agregar al proyecto en piklab el módulo y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes área que se mapean en secciones definidas dentro de la memoria ROM correspondiente a la memoria de programa del microcontrolador, para implementar esto se necesita especificar en un archivo llamado linker script dónde están alojadas físicamente(en memoria) estas secciones.&lt;br /&gt;
La forma de realizar este mapeo es editando el archivo lrk asociado al proyecto.&lt;br /&gt;
Existe la directiva CODEPAGE que es utilizada para trabajar con las secciones de programa, permite inicializar datos, constantes, y referencias externas. Tiene el siguiente formato&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
donde:&lt;br /&gt;
memName es un string ASCII utilizado para identificar una CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
== Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|bobot logo]][[Archivo:web_bobot.png|thumb|Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010. &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'' de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, se debe primero desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
El driver está escrito en Lua y esta implementado como una tabla aprovechando la característica de de este lenguaje en el que las funciones son miembros de primer orden, esto permite que una función pueda ser un tipo de datos válido, pasar funciones como argumento de funciones o como retorno de las mismas almacenarla en una tabla, entre otras cosas. Por este motivo dentro de la tabla se pueden almacenar funciones donde en la misma se especifican las operaciones que el driver expone, y los tipos de parámetros que recibe. Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, la cual describe un módulo de usuario otra como el método de la función es utilizada para resolver de forma genérica las invocaciones a los servicios expuestos por el driver.&lt;br /&gt;
&lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot-server desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1072</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1072"/>
				<updated>2011-10-05T18:13:12Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* Detalles de implementación en el firmware */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== Arquitectura ==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo concerniente al hardware como las abstracciones necesarias para manejarlo mediante software. Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|USB4all Baseboard]]&lt;br /&gt;
Es una placa de entrada/salida configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de ésta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
==Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux&lt;br /&gt;
Microchip disrtibuye un bootloader para ésta familia de microcontroladores, el cual permite grabar el firmware sin la necesidad de disponer de un programador, para realizar esto es necesario dejar prescionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
La versión 2.0 de la placa USB4all utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de prescionar los botones.&lt;br /&gt;
La misma puede encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una ves compilado su grabación se realiza mediante un programador por hardware como picdem o pickit.&lt;br /&gt;
Una vez grabado el bootloader ya no es necesario utilizar programadores por hardware y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe de estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Entorno de desarrollor con piklab]]&lt;br /&gt;
Una de las opciones posibles para trabajar en un ambiente GNU/Linux es instalar el Piklab, Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC, el proyecto USB4all utiliza el compilador C18 de Microchip el cual solo está disponible para Windows, para hacerlo funcionar se utiliza wine y se debe configurar el toolchain C18 en piklab para que apunte correctamente a los directorios donde se encuentra el compilador C18. &lt;br /&gt;
Una limitante que posee este compilador es que no permite rutas de archivos que sean muy largas, lo cual es fácilmente alcanzado utilizando wine, por lo tanto se recomienda que el proyecto este lo más cercano a la raíz posible.&lt;br /&gt;
Más información sobre la configuración de c18 con piklab en linux ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
Otra opción es utilizar MPlab que actualmente trae soporte para GNU/Linux [http://microchip.wikidot.com/mplab:_start]&lt;br /&gt;
En el repositorio USB4all puede descargarse un proyecto ya armado para trabajar con piklab, compilando contra c18 mediante wine. Luego de compilar, cargar el binario en la placa mediante el uso del bootloader que se incluye en el firmware, utilizando la utilidad fsusb como fue descripto en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== Escribiendo un ''usermodule'' ==&lt;br /&gt;
[[Archivo:user_module.png|thumb|tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que el módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es una estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es un case en el que se espera por los diferentes comandos que pueden enviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt;comando&amp;gt;&amp;lt;argumento1&amp;gt;...&amp;lt;argumentoN&amp;gt;. La respuesta debe ser del tipo &amp;lt;comando&amp;gt;&amp;lt;resultado1&amp;gt;...&amp;lt;resultadoN&amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devuelven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''Entrada/Salida en user modules:'''&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren para ser notificados cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el usermodule a la placa de entrada salida usb4all ''baseboard'' se debe agregar al proyecto en piklab el módulo y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes área que se mapean en secciones definidas dentro de la memoria ROM correspondiente a la memoria de programa del microcontrolador, para implementar esto se necesita especificar en un archivo llamado linker script dónde están alojadas físicamente(en memoria) estas secciones.&lt;br /&gt;
La forma de realizar este mapeo es editando el archivo lrk asociado al proyecto.&lt;br /&gt;
Existe la directiva CODEPAGE que es utilizada para trabajar con las secciones de programa, permite inicializar datos, constantes, y referencias externas. Tiene el siguiente formato&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
donde:&lt;br /&gt;
memName es un string ASCII utilizado para identificar una CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
== Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|bobot logo]][[Archivo:web_bobot.png|thumb|Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010. &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'' de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, se debe primero desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
El driver está escrito en Lua y esta implementado como una tabla aprovechando la característica de de este lenguaje en el que las funciones son miembros de primer orden, esto permite que una función pueda ser un tipo de datos válido, pasar funciones como arguemnto de funciones o como retorno de las mismas almcenarla en una tabla, entre otras cosas. Por este motivo dentro de la tabla se pueden almacenar funciones donde en la misma se especifican las operaciones que el driver expone, los tipos de parametros que recibe y de que tipo son los mismos. Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, la cual describe un módulo de usuario otra como el método de la función es utilizada para resolver de forma genérica las invocaciones a los servicios expuestos por el driver.&lt;br /&gt;
&lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot-server desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1071</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1071"/>
				<updated>2011-10-05T15:05:48Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* Escribiendo un usermodule */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== Arquitectura ==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo concerniente al hardware como las abstracciones necesarias para manejarlo mediante software. Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|USB4all Baseboard]]&lt;br /&gt;
Es una placa de entrada/salida configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de ésta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
==Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux&lt;br /&gt;
Microchip disrtibuye un bootloader para ésta familia de microcontroladores, el cual permite grabar el firmware sin la necesidad de disponer de un programador, para realizar esto es necesario dejar prescionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
La versión 2.0 de la placa USB4all utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de prescionar los botones.&lt;br /&gt;
La misma puede encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una ves compilado su grabación se realiza mediante un programador por hardware como picdem o pickit.&lt;br /&gt;
Una vez grabado el bootloader ya no es necesario utilizar programadores por hardware y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe de estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Entorno de desarrollor con piklab]]&lt;br /&gt;
Una de las opciones posibles para trabajar en un ambiente GNU/Linux es instalar el Piklab, Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC, el proyecto USB4all utiliza el compilador C18 de Microchip el cual solo está disponible para Windows, para hacerlo funcionar se utiliza wine y se debe configurar el toolchain C18 en piklab para que apunte correctamente a los directorios donde se encuentra el compilador C18. &lt;br /&gt;
Una limitante que posee este compilador es que no permite rutas de archivos que sean muy largas, lo cual es fácilmente alcanzado utilizando wine, por lo tanto se recomienda que el proyecto este lo más cercano a la raíz posible.&lt;br /&gt;
Más información sobre la configuración de c18 con piklab en linux ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
Otra opción es utilizar MPlab que actualmente trae soporte para GNU/Linux [http://microchip.wikidot.com/mplab:_start]&lt;br /&gt;
En el repositorio USB4all puede descargarse un proyecto ya armado para trabajar con piklab, compilando contra c18 mediante wine. Luego de compilar, cargar el binario en la placa mediante el uso del bootloader que se incluye en el firmware, utilizando la utilidad fsusb como fue descripto en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== Escribiendo un ''usermodule'' ==&lt;br /&gt;
[[Archivo:user_module.png|thumb|tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que el módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es una estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es un case en el que se espera por los diferentes comandos que pueden enviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt;comando&amp;gt;&amp;lt;argumento1&amp;gt;...&amp;lt;argumentoN&amp;gt;. La respuesta debe ser del tipo &amp;lt;comando&amp;gt;&amp;lt;resultado1&amp;gt;...&amp;lt;resultadoN&amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devuelven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''Entrada/Salida en user modules:'''&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren para ser notificados cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el usermodule a la placa de entrada salida usb4all ''baseboard'' se debe agregar al proyecto en piklab el módulo y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes área que se mapean en secciones definidos dentro de la memoria ROM correspondiente a la memoria del programa del microcontrolador, para implementar esto se necesita especificar en un archivo llamado linker script donde físicamente estan alojadas estas secciones.&lt;br /&gt;
La forma de realizar este mapeo es editando en el archivo lrk asociado al proyecto.&lt;br /&gt;
Existe la directiva CODEPAGE que es utilizada para trabajar con las secciones de programa, permite inicializar datos, constantes, y referencias externas. Tiene el siguiente formato&lt;br /&gt;
&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
donde:&lt;br /&gt;
memName es un string ASCII utilizado para identificar una CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
== Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|bobot logo]][[Archivo:web_bobot.png|thumb|Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010. &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'' de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, se debe primero desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
El driver está escrito en Lua y esta implementado como una tabla aprovechando la característica de de este lenguaje en el que las funciones son miembros de primer orden, esto permite que una función pueda ser un tipo de datos válido, pasar funciones como arguemnto de funciones o como retorno de las mismas almcenarla en una tabla, entre otras cosas. Por este motivo dentro de la tabla se pueden almacenar funciones donde en la misma se especifican las operaciones que el driver expone, los tipos de parametros que recibe y de que tipo son los mismos. Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, la cual describe un módulo de usuario otra como el método de la función es utilizada para resolver de forma genérica las invocaciones a los servicios expuestos por el driver.&lt;br /&gt;
&lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot-server desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1069</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1069"/>
				<updated>2011-10-05T15:02:10Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* Entorno de desarrollo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== Arquitectura ==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo concerniente al hardware como las abstracciones necesarias para manejarlo mediante software. Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|USB4all Baseboard]]&lt;br /&gt;
Es una placa de entrada/salida configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de ésta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
==Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux&lt;br /&gt;
Microchip disrtibuye un bootloader para ésta familia de microcontroladores, el cual permite grabar el firmware sin la necesidad de disponer de un programador, para realizar esto es necesario dejar prescionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
La versión 2.0 de la placa USB4all utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de prescionar los botones.&lt;br /&gt;
La misma puede encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una ves compilado su grabación se realiza mediante un programador por hardware como picdem o pickit.&lt;br /&gt;
Una vez grabado el bootloader ya no es necesario utilizar programadores por hardware y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe de estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Entorno de desarrollor con piklab]]&lt;br /&gt;
Una de las opciones posibles para trabajar en un ambiente GNU/Linux es instalar el Piklab, Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC, el proyecto USB4all utiliza el compilador C18 de Microchip el cual solo está disponible para Windows, para hacerlo funcionar se utiliza wine y se debe configurar el toolchain C18 en piklab para que apunte correctamente a los directorios donde se encuentra el compilador C18. &lt;br /&gt;
Una limitante que posee este compilador es que no permite rutas de archivos que sean muy largas, lo cual es fácilmente alcanzado utilizando wine, por lo tanto se recomienda que el proyecto este lo más cercano a la raíz posible.&lt;br /&gt;
Más información sobre la configuración de c18 con piklab en linux ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
Otra opción es utilizar MPlab que actualmente trae soporte para GNU/Linux [http://microchip.wikidot.com/mplab:_start]&lt;br /&gt;
En el repositorio USB4all puede descargarse un proyecto ya armado para trabajar con piklab, compilando contra c18 mediante wine. Luego de compilar, cargar el binario en la placa mediante el uso del bootloader que se incluye en el firmware, utilizando la utilidad fsusb como fue descripto en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== Escribiendo un ''usermodule'' ==&lt;br /&gt;
[[Archivo:user_module.png|thumb|tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que él módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es un estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es un case en el que se espera por los diferentes comandos que pueden eviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt;comando&amp;gt;&amp;lt;argumento1&amp;gt;...&amp;lt;argumentoN&amp;gt;. La respuesta debe ser del tipo &amp;lt;comando&amp;gt;&amp;lt;resultado1&amp;gt;...&amp;lt;resultadoN&amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devueleven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''Entrada/Salida en user modules:'''&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren para ser notificados cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el usermodule a la placa de entrada salida usb4all ''baseboard'' se debe agregar al proyecto en piklab el módulo y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes área que se mapean en secciones definidos dentro de la memoria ROM correspondiente a la memoria del programa del microcontrolador, para implementar esto se encesita especificar en un archivo llamado linker script donde físicamente estan alojadas estas secciones.&lt;br /&gt;
&lt;br /&gt;
//TODO completar esto &lt;br /&gt;
&lt;br /&gt;
Linker script files are the command files of the linker. They specify:&lt;br /&gt;
• Program and data memory regions for the target part&lt;br /&gt;
• Stack size and location (for MPLAB C18)&lt;br /&gt;
• A mapping of logical sections in source code into program and data regions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The CODEPAGE directive is used for program code, initialized data values, constant data values and external memory. It has the following format:&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
where:&lt;br /&gt;
memName is any ASCII string used to identify a CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
== Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|bobot logo]][[Archivo:web_bobot.png|thumb|Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010. &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'' de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, se debe primero desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
El driver está escrito en Lua y esta implementado como una tabla aprovechando la característica de de este lenguaje en el que las funciones son miembros de primer orden, esto permite que una función pueda ser un tipo de datos válido, pasar funciones como arguemnto de funciones o como retorno de las mismas almcenarla en una tabla, entre otras cosas. Por este motivo dentro de la tabla se pueden almacenar funciones donde en la misma se especifican las operaciones que el driver expone, los tipos de parametros que recibe y de que tipo son los mismos. Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, la cual describe un módulo de usuario otra como el método de la función es utilizada para resolver de forma genérica las invocaciones a los servicios expuestos por el driver.&lt;br /&gt;
&lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot-server desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1068</id>
		<title>Usb4all</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Usb4all&amp;diff=1068"/>
				<updated>2011-10-05T14:59:08Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* Arquitectura */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Motivación ==&lt;br /&gt;
&lt;br /&gt;
La motivación de este proyecto se centra en lograr de una manera sencilla, la comunicación entre un sistema computador y un conjunto de dispositivos electrónicos no necesariamente pensados para interactuar con una computadora.&lt;br /&gt;
Durante muchos años la única forma de interactuar con dispositivos externos desde a un computador personal (Personal Computer) (PC) fueron los puertos seriales y paralelos, esto llevo a que se utilizaran ampliamente en multiplicidad de dispositivos. Sus principales carácteristicas son su simplicidad de manejo vía software y facilidad de inclusión en distintos dispositivos. En la última década han aparecido nuevos medios o canales de comunicación, tales como Bluetooth, Fidelidad Inalámbrica (Wireless Fidelity) (WiFi), FireWire, Bus Universal en Serie (Universal Serial Bus) (USB), etc. Estos permitieron mejorar las velocidades de comunicación y calidad de datos y lentamente tornaron a los puertos paralelos y seriales en obsoletos, hasta llegar al día de hoy en que se obtienen sólo de manera opcional en los nuevos PC.&lt;br /&gt;
Dentro de todas estas nuevas tecnologías que aparecieron la que tuvo mayor aceptación y difusión entre los usuarios fue el USB, debido a su facilidad y versatilidad de escenarios de uso. Esta simplicidad desde el punto de vista del usuario de los dispositivos USB tiene como contrapartida una mayor complejidad para los desarrolladores de software y hardware, lo cual es un gran problema al momento de interactuar con dispositivos electrónicos.&lt;br /&gt;
Frente a estas adversidades que presenta el entorno actual aparece la necesidad de buscar una forma de reducir el grado de complejidad y conocimientos necesarios para poder desarrollar&lt;br /&gt;
software que utilice la tecnología USB. Al mismo tiempo, se requiere una plataforma base que incorpore componentes de hardware reutilizables y que en conjunto formen una solución genérica&lt;br /&gt;
para la comunicación con dispositivos electrónicos diversos.&lt;br /&gt;
En el contexto de lo antedicho aparecen un conjunto de desafíos como son el desarrollo de controladores (drivers) y construcción de piezas de hardware que brinde una solución genérica&lt;br /&gt;
reutilizable, desplazando el manejo de los casos particulares a componentes específicos. Esto proporciona el beneficio de evitar que cada vez que se necesite conectar un nuevo dispositivo,&lt;br /&gt;
se comience desde cero. A su vez permite recuperar y potenciar la característica de facilidad de manejo que poseían los puertos seriales y paralelos, explotando todas las capacidades brindadas&lt;br /&gt;
por USB.&lt;br /&gt;
&lt;br /&gt;
== Arquitectura ==&lt;br /&gt;
 &lt;br /&gt;
La arquitectura esta compuesta por diferentes componentes, los cuales van a permitir el funcionamiento del sistema desde lo concerniente al hardware como las abstracciones necesarias para manejarlo mediante software. Los componentes principales son:&lt;br /&gt;
&lt;br /&gt;
'''USB4all ''Baseboard'''''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:usb4all2.png|thumb|USB4all Baseboard]]&lt;br /&gt;
Es una placa de entrada/salida configurable que se conecta por USB con un sistema computador. El proyecto USB4all es mucho más que una placa de E/S, en sí es una forma de modelar sistemas embebidos, siendo la placa de E/S  un componente que fue necesario construir para desarrollar la solución completa. Para la construcción de ésta placa se utilizó un microcontrolador PIC18F4550 de Microchip. Entre las características más destacadas en lo que concierne al proyecto se encuentra el soporte completo del estándar USB, pudiéndose utilizar varias de sus características, como ser diferentes tipos de transferencias y varios canales de comunicación (endpoints).&lt;br /&gt;
  &lt;br /&gt;
'''USB4all ''base firmware'''''&lt;br /&gt;
&lt;br /&gt;
Es el firmware más estático, brinda servicios a los usermodules para que puedan utilizar los recursos presentes en la baseboard (timmers, puerto USB, conversores A/D, etc) además de brindar las primitivas para el intercambio de mensajes entre el computador y el usermodule y realiza la gestión de los ''usermodules''. Establece las bases para que los usermodules sean independientes del protocolo de comunicación computador/placa y de los detalles de hardware del microcontrolador utilizado. A su vez oferce un entorno de ejecución concurrente que permite instanciar de forma dinámica varios ''usermodules''. &lt;br /&gt;
&lt;br /&gt;
'''USB4all ''usermodule'''''&lt;br /&gt;
Son los componentes intercambiables del sistema que permiten encapsular la lógica de un dispositivo especifico y su protocolo de comunicación con las aplicaciones de usuario. Permite al usuario dar rápidamente soporte a un nuevo dispositivo de forma genérica, expandiendo de ésta manera las funcionalidades del USB4all ''basefirmware''. Los ''user modules'' son los bloques principales sobre los que se construye la arquitectura USB4all. Exponen una API uniforme que es utilizada a modo de callbacks por el ''base firmware'' y también exponen los servicios que brindan los dispositivos. Es recomendable modelar cada uno de los dispositivos electrónicos conectados a la ''baseboard'' como un ''usermodule'' donde los servicios a exponer se mapean con las características del mismo, como ejemplo en el caso de un motor, sería esperable que expusiera servicios para moverse, cambiar la velocidad y el sentido. &lt;br /&gt;
&lt;br /&gt;
Del lado del sistema computador se dispone de diferentes formas de interacción: Todas ellas implementan el protocolo USB4all, su objetivo es abstraer al usuario del mismo brindando una forma sencilla de utilizar el sistema, existiendo soporte para diferentes lenguajes de programación. El objetivo principal de las bibliotecas utilizadas en el computador son las de permitir utilizar los servicios de los ''usermodules''. Esta forma de trabajo permite desarrollar la lógica de interacción entre los diferentes dispositivos electrónicos dentro del sistema computador, con lenguajes de mayor abstracción, mejores herramientas de desarrollo, permitiendo generar un código con un nivel de mantenibilidad y abstracción mayor al que se lograría si todo estuviera embebido en el microcontrolador.&lt;br /&gt;
&lt;br /&gt;
Uno de los componentes más usados actualmente es el bobot que persigue un enfoque genérico al igual que el proyecto USB4all y permite acompañar la extensibilidad de la placa USB4all mediante el uso de ciertos componentes propios de la arquitectura llamados drivers.&lt;br /&gt;
&lt;br /&gt;
== Protocolo de Comunicación ==&lt;br /&gt;
&lt;br /&gt;
==Grabando el Firmware ==&lt;br /&gt;
&lt;br /&gt;
Para grabar el firmware se necesita disponer de un programador, como el picdem o el pickit, este último tiene buen soporte dentro de GNU/Linux&lt;br /&gt;
Microchip disrtibuye un bootloader para ésta familia de microcontroladores, el cual permite grabar el firmware sin la necesidad de disponer de un programador, para realizar esto es necesario dejar prescionado el botón de programación (botón más cercano al led) mientras se resetea la placa con el botón de reset.&lt;br /&gt;
Una vez que el dispositivo se encuentra en modo programación su identificador de producto cambia de 000c a 000b, esto puede verificarse utilizando el comando ''lsusb'' cuya salida se adjunta para los dos casos a continuación:&lt;br /&gt;
&lt;br /&gt;
Id dispositivo USB4all&lt;br /&gt;
    Bus 002 Device 002: ID 04d8:000c Microchip Technology, Inc. &lt;br /&gt;
&lt;br /&gt;
id dispositivo Bootloader&lt;br /&gt;
    Bus 002 Device 003: ID 04d8:000b Microchip Technology, Inc.&lt;br /&gt;
&lt;br /&gt;
La versión 2.0 de la placa USB4all utiliza un bootloader modificado que permite actualizar el firmware programáticamente sin necesidad de prescionar los botones.&lt;br /&gt;
La misma puede encontrarse en el repositorio en el directorio bootloader del firmware, es un proyecto separado y una ves compilado su grabación se realiza mediante un programador por hardware como picdem o pickit.&lt;br /&gt;
Una vez grabado el bootloader ya no es necesario utilizar programadores por hardware y puede realizarse la grabación del firmware mediante varios programas que implementan el protocolo de grabación de firmware de microchip. Una de esas utilidades es el programa fsusb el cual puede encontrarse en [http://www.internetking.org/fsusb/] y es de código libre. Su uso se realiza de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
    ./fsusb --program usb4all2.hex&lt;br /&gt;
&lt;br /&gt;
Donde usb4all2.hex es el binario generado como resultado de compilar el proyecto. Recordar que el hardware debe de estar en modo bootloader para poder recibir el firmware.&lt;br /&gt;
&lt;br /&gt;
== Entorno de desarrollo ==&lt;br /&gt;
[[Archivo:piklab.png|thumb|Entorno de desarrollor con piklab]]&lt;br /&gt;
Una de las opciones posibles para trabajar en un ambiente GNU/Linux es instalar el Piklab, Piklab es un entorno de desarrollo para trabajar con microcontroladores PIC, el proyecto USB4all utiliza el compilador C18 de Microchip el cual solo está disponible para Windows, para hacerlo funcionar se utiliza wine y se debe configurar el toolchain C18 en piklab para que apunte correctamente a los directorios donde se encuentra el compilador C18. &lt;br /&gt;
Una limitante que posee este compilador es que no permite rutas de archivos que sean muy largas, lo cual es fácilmente alcansado utilizando wine, por lo tanto se recomienda que el proyecto este lo más cercano a la raiz posible.&lt;br /&gt;
Más información sobre la configuración de c18 con piklab en linux ver: [http://cantareus.com/2009/08/18f4550-and-18f2550-with-piklab-and-ubuntu/]&lt;br /&gt;
Otra opción es utilizar MPlab que actualmente trae soporte para GNU/Linux [http://microchip.wikidot.com/mplab:_start]&lt;br /&gt;
En el repositorio USB4all puede descargarse un proyecto ya armado para trabajar con piklab, compilando contra c18 mediante wine. Luego de compilar el carga el binario en la placa mediante el uso del bootloader que se incluye en el firmware utilizando la utilidad fsusb como fue descripto en la sección Grabando el Firmware.&lt;br /&gt;
&lt;br /&gt;
== Escribiendo un ''usermodule'' ==&lt;br /&gt;
[[Archivo:user_module.png|thumb|tabla de referencias a ''user modules'']]&lt;br /&gt;
&lt;br /&gt;
Un ''usermodule'' debe cumplir con una API determinada, de esta manera es posible agregar las funcionalidades que él módulo expone, dentro del ''basefirmware''.&lt;br /&gt;
Las operaciones principales que se deben implementar son las encargadas de atender los eventos de:&lt;br /&gt;
* inicialización&lt;br /&gt;
* liberación de recursos&lt;br /&gt;
* configuración &lt;br /&gt;
&lt;br /&gt;
Estas operaciones se ejecutan en determinados momentos del ciclo de vida de una aplicación USB4all, siendo la operación registrada al evento de inicialización invocada al abrir desde la aplicación el ''usermodule'' y la de liberación de recursos al cerrarlo, esto permite utilizar los recursos del microcontrolador solo cuando es necesario. La operación de configuración puede invocarse en cualquier momento para cambiar en caliente algún aspecto de configuración del hardware.&lt;br /&gt;
A comenzar un ''usermodule'' se debe declarar cuales van a ser las funciones que van a atender estos eventos y el nombre del módulo para ser identificado desde el computador al listar los módulos presentes en la placa.&lt;br /&gt;
&lt;br /&gt;
    #pragma romdata user&lt;br /&gt;
    uTab userBuzzerModuleTable = {&amp;amp;UserBuzzerInit,&amp;amp;UserBuzzerRelease,&amp;amp;UserBuzzerConfigure,&amp;quot;buzzer&amp;quot;};&lt;br /&gt;
    #pragma code&lt;br /&gt;
&lt;br /&gt;
Donde user es el nombre de la sección y uTab es un estructura para almacenar las posiciones de memoria de las operaciones que exporta el módulo y su nombre.&lt;br /&gt;
&lt;br /&gt;
Como argumento a la operación init se recibe el número de handler asignado al módulo, este número es utilizado como argumento en otras operaciones como ser ''setHandlerReceiveFunction'' la cual recibe por parámetro el handler y un puntero a la función encargada de manejar la recepción de datos. Otra operación similar es ''getSharedBuffer'' que recibe por parámetro el ''handlerID'' del módulo y retorna un buffer por el cual el módulo puede enviar datos a la aplicación que ejecuta en el computador.    &lt;br /&gt;
Un buen lugar para obtener éste buffer y registrar la función de recepción de datos es la operación encargada del evento de inicialización&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerInit(byte i) {&lt;br /&gt;
    usrBuzzerHandler = i;&lt;br /&gt;
    // add my receive function to the handler module, to be called automatically when the pc sends data to the user module&lt;br /&gt;
    setHandlerReceiveFunction(usrBuzzerHandler,&amp;amp;UserBuzzerReceived);&lt;br /&gt;
    // initialize the send buffer, used to send data to the PC&lt;br /&gt;
    sendBufferUsrBuzzer = getSharedBuffer(usrBuzzerHandler);&lt;br /&gt;
}//end UserBuzzerInit &amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La función de recepción de datos es la encargada de implementar el protocolo de comunicación entre el ''usermodule'' y la aplicación, típicamente es un case en el que se espera por los diferentes comandos que pueden eviarse. La forma de codificar el pedido de servicios es mediante mensajes del tipo &amp;lt;comando&amp;gt;&amp;lt;argumento1&amp;gt;...&amp;lt;argumentoN&amp;gt;. La respuesta debe ser del tipo &amp;lt;comando&amp;gt;&amp;lt;resultado1&amp;gt;...&amp;lt;resultadoN&amp;gt;. El buffer para enviar datos al computador es obtenido como argumento de la función y el buffer para enviar datos fue obtenido previamente en la función de inicialización.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt; void UserBuzzerReceived(byte* recBuffPtr, byte len){&lt;br /&gt;
      byte index;&lt;br /&gt;
      byte j;  &lt;br /&gt;
      byte userBuzzerCounter = 0;&lt;br /&gt;
      byte tiempo;&lt;br /&gt;
&lt;br /&gt;
      switch(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;CMD){&lt;br /&gt;
        case READ_VERSION:&lt;br /&gt;
              //dataPacket._byte[1] is len&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[2] = BUZZER_MINOR_VERSION;&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[3] = BUZZER_MAJOR_VERSION;&lt;br /&gt;
              userBuzzerCounter = 0x04;&lt;br /&gt;
              break;  &lt;br /&gt;
              &lt;br /&gt;
        case PRENDER:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_on();&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
        &lt;br /&gt;
        case APAGAR:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              buzzer_off(); &lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;  &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_TRIPLE:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks1 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]);&lt;br /&gt;
              cantTicks2 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[2]);  &lt;br /&gt;
              cantTicks3 = (byte)(((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[3]);&lt;br /&gt;
              boubleBeep(cantTicks1, cantTicks2, cantTicks3);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;        &lt;br /&gt;
&lt;br /&gt;
        case BUZZER_CORTO:&lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[0] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[0]; &lt;br /&gt;
              ((BUZZER_DATA_PACKET*)sendBufferUsrBuzzer)-&amp;gt;_byte[1] = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1]; &lt;br /&gt;
              cantTicks3 = ((BUZZER_DATA_PACKET*)recBuffPtr)-&amp;gt;_byte[1];&lt;br /&gt;
              timeOutTicksBuzz = 1; // lo seteo timmer para que venza inmediantamente&lt;br /&gt;
              buzzerState = DELAY;  &lt;br /&gt;
              registerT0event(0, &amp;amp;buzzEvent);&lt;br /&gt;
              userBuzzerCounter = 0x02;&lt;br /&gt;
              break;    &lt;br /&gt;
&lt;br /&gt;
        case RESET:&lt;br /&gt;
              Reset();&lt;br /&gt;
              break;&lt;br /&gt;
     &lt;br /&gt;
         default:&lt;br /&gt;
              break;&lt;br /&gt;
      }//end switch(s)&lt;br /&gt;
      if(userBuzzerCounter != 0){&lt;br /&gt;
            j = 255;&lt;br /&gt;
            while(mUSBGenTxIsBusy() &amp;amp;&amp;amp; j--&amp;gt;0); // pruebo un máximo de 255 veces&lt;br /&gt;
                if(!mUSBGenTxIsBusy())&lt;br /&gt;
                    USBGenWrite2(usrBuzzerHandler, userBuzzerCounter);&lt;br /&gt;
      }//end if            &lt;br /&gt;
}//end UserBuzzerReceived&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este ejemplo se puede apreciar como se reciben los pedidos de comandos desde la aplicación que ejecuta en el computador y como se obtienen los parámetros necesarios para implementar los comandos y se devueleven los datos (en caso de ser requeridos) a la aplicación.&lt;br /&gt;
&lt;br /&gt;
'''Entrada/Salida en user modules:'''&lt;br /&gt;
Una de las tareas más importantes de los ''usermodules'' es la de realizar entrada/salida con diferentes periféricos electrónicos. Para realizar ésta tarea existen dos paradigmas:&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
* Polling&lt;br /&gt;
* Interrupciones&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Dentro de la arquitectura USB4all existen formas de que los módulos implementen entrada/salida utilizando estos paradigmas, para el caso de pooling existe un servicio que permite registrar una función para ser ejecutada cuando el procesador este disponible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addPollingFunction(&amp;amp;UserBuzzerProcessIO);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Existe soporte para interrupciones mediante el módulo ''DynamicISR'' el cual permite que otros módulos se registren para ser notificados cuando ocurren interrupciones. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
addISRFunction(&amp;amp;timmerISRFunction);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Una forma que mantiene alta la cohesión del sistema es registrar módulos que se encarguen de esperar un evento en particular y brinde una interfaz para que los ''usermodules'' se registren para ser notificados de eventos generados por el componente de hardware que esta siendo modelado. Hoy día se dispone del módulo T0service que se encarga de brindar servicio de timmers a los ''usermodules''. Al igual que el resto de los componentes funciona registrando funciones que son invocadas por el ''basefirmware'' &lt;br /&gt;
&lt;br /&gt;
También existen funciones para desregistrar los ''usermodules'' de las notificaciones, es conveniente realizar la desregistración en la función que implementa el evento de liberación de recursos del módulo.&lt;br /&gt;
&lt;br /&gt;
Por ahora el único componente de hardware del microcontrolador modelado de esta forma es el timmer, pero puede escalarse a otros que requieran ser compartidos por más de un módulo.&lt;br /&gt;
Hay que recordar que la concurrencia implementada es puramente colaborativa entre ''usermodules'' por lo cual se debe tener especial cuidado al programar las funciones que atienden estos eventos ya que si se queda &amp;quot;colgada&amp;quot; va a degradar la disponibilidad de todo el sistema.&lt;br /&gt;
&lt;br /&gt;
Para agregar el usermodule a la placa de entrada salida usb4all ''baseboard'' se debe agregar al proyecto en piklab el módulo y realizar la compilación del proyecto&lt;br /&gt;
&lt;br /&gt;
== Detalles de implementación en el firmware ==&lt;br /&gt;
&lt;br /&gt;
El firmware está organizado en diferentes área que se mapean en secciones definidos dentro de la memoria ROM correspondiente a la memoria del programa del microcontrolador, para implementar esto se encesita especificar en un archivo llamado linker script donde físicamente estan alojadas estas secciones.&lt;br /&gt;
&lt;br /&gt;
//TODO completar esto &lt;br /&gt;
&lt;br /&gt;
Linker script files are the command files of the linker. They specify:&lt;br /&gt;
• Program and data memory regions for the target part&lt;br /&gt;
• Stack size and location (for MPLAB C18)&lt;br /&gt;
• A mapping of logical sections in source code into program and data regions&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The CODEPAGE directive is used for program code, initialized data values, constant data values and external memory. It has the following format:&lt;br /&gt;
    CODEPAGE NAME=memName START=addr END=addr [PROTECTED] [FILL=fillvalue]&lt;br /&gt;
&lt;br /&gt;
where:&lt;br /&gt;
memName is any ASCII string used to identify a CODEPAGE.&lt;br /&gt;
&lt;br /&gt;
== Bobot ==&lt;br /&gt;
[[Archivo:bobot.png|thumb|bobot logo]][[Archivo:web_bobot.png|thumb|Interacción con dispositivo USB4all de forma web]]&lt;br /&gt;
bobot-server (version 2) es un servicio que permite acceder a aplicaciones y usuarios interactuar con dispositivos USB4all.&lt;br /&gt;
Consiste en un agente altamente portable y liviano, que exporta la funcionalidad de los dispositivos USB4all presentes de una forma fácil de usar. Ofrece dos métodos de acceso,&lt;br /&gt;
uno optimizado para aplicaciones, basado en un socket y un protocolo fácilmente parseable, y otro optimizado para ser usado por humanos, mediante un sitio web&lt;br /&gt;
hosteado en el propio agente, el cual atiende en el puerto 2010. &lt;br /&gt;
Bobot introduce el concepto de driver, en el cual se codifica el protocolo que utilizan los ''usermodules'' de esta forma se exponen al usuario del sistema bobot los servicios que implementan los ''usermodules'' ocultando los detalles relacionados con el protocolo de intercambio de mensajes.&lt;br /&gt;
Para desarrollar compatibilidad con un nuevo dispositivo electronico en la plataforma USB4all utilizando bobot para su control, se debe primero desarrollar el ''usermodule'' necesario como fue descripto en la sección: Escribiendo un ''usermodule'' luego se debe escribir el driver correspondiente a ese ''usermodule''. &lt;br /&gt;
El driver está escrito en Lua y esta implementado como una tabla aprovechando la característica de de este lenguaje en el que las funciones son miembros de primer orden, esto permite que una función pueda ser un tipo de datos válido, pasar funciones como arguemnto de funciones o como retorno de las mismas almcenarla en una tabla, entre otras cosas. Por este motivo dentro de la tabla se pueden almacenar funciones donde en la misma se especifican las operaciones que el driver expone, los tipos de parametros que recibe y de que tipo son los mismos. Mucha de ésta información es utilizada por el bobot para generar el sitio web mencionado anteriormente, la cual describe un módulo de usuario otra como el método de la función es utilizada para resolver de forma genérica las invocaciones a los servicios expuestos por el driver.&lt;br /&gt;
&lt;br /&gt;
A continuación se muestra un ejemplo de driver para el módulo de usuario presentado en la sección: Escribiendo un ''usermodule''&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; &lt;br /&gt;
local device = _G&lt;br /&gt;
local RD_VERSION = string.char(0x00)&lt;br /&gt;
local PRENDER = string.char(0x01)&lt;br /&gt;
local APAGAR = string.char(0x02)&lt;br /&gt;
local BUZZER_CORTO = string.char(0x03)&lt;br /&gt;
local BUZZER_TRIPLE = string.char(0x04)&lt;br /&gt;
&lt;br /&gt;
api={}&lt;br /&gt;
api.read_version = {}&lt;br /&gt;
api.read_version.parameters = {} --no parameters&lt;br /&gt;
api.read_version.returns = {[1]={rname=&amp;quot;version&amp;quot;, rtype=&amp;quot;number&amp;quot;}} --one return&lt;br /&gt;
api.read_version.call = function ()&lt;br /&gt;
        local get_read_version = RD_VERSION &lt;br /&gt;
        device:send(get_read_version)&lt;br /&gt;
        local version_response = device:read(2) &lt;br /&gt;
        local raw_val = string.byte(version_response, 2) &lt;br /&gt;
        --print(&amp;quot;rawval, deg_temp: &amp;quot;, raw_val, deg_temp)&lt;br /&gt;
        return raw_val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.prender = {}&lt;br /&gt;
api.prender.parameters = {} --no parameters&lt;br /&gt;
api.prender.returns = {} --no return&lt;br /&gt;
api.prender.call = function ()&lt;br /&gt;
    local write_res, err = device:send(PRENDER)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.apagar = {}&lt;br /&gt;
api.apagar.parameters = {} --no parameters&lt;br /&gt;
api.apagar.returns = {} --no return&lt;br /&gt;
api.apagar.call = function ()&lt;br /&gt;
    local write_res, err = device:send(APAGAR)&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_corto = {}&lt;br /&gt;
api.buzzer_corto.parameters = {[1]={rname=&amp;quot;num&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_corto.returns = {} --no return&lt;br /&gt;
api.buzzer_corto.call = function (num)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_CORTO .. string.char(num))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
api.buzzer_triple = {}&lt;br /&gt;
api.buzzer_triple.parameters = {[1]={rname=&amp;quot;tiempo1&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [2]={rname=&amp;quot;tiempo2&amp;quot;, rtype=&amp;quot;number&amp;quot;}, [3]={rname=&amp;quot;tiempo3&amp;quot;, rtype=&amp;quot;number&amp;quot;}} &lt;br /&gt;
api.buzzer_triple.returns = {} --no return&lt;br /&gt;
api.buzzer_triple.call = function (tiempo1, tiempo2, tiempo3)&lt;br /&gt;
    local write_res, err = device:send(BUZZER_TRIPLE .. string.char(tiempo1) .. string.char(tiempo2) .. string.char(tiempo3))&lt;br /&gt;
    if write_res then return true else return false end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En el ejemplo puede notarse al comparar con el ''usermodule'' presentado de ejemplo, como se realiza el pasaje de parámetros entre el driver y el ''usermodule'', esto corresponde con el protocolo definido por el usuario para codificar los comandos del ''usermodule'' y el orden de los parámetros, este protocolo es llamado en la arquitectura USB4all como ''user protocol''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Puede descargarse bobot-server desde el git del proyecto butiá en sourceforge.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
El proyecto USB4all se encuentra disponible bajo licencia GNU/GPL v2 en el [http://sourceforge.net/projects/usb4all/ repositorio sorceforge] &amp;lt;br&amp;gt;&lt;br /&gt;
Este proyecto surge originalmente como un trabajo de [http://www.fing.edu.uy/inco/grupos/mina/pGrado/pgusb tesis de grado] en Ingeniería en Computación de Aguirre, Fernandez y Grossy.&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Wiki_Buti%C3%A1&amp;diff=167</id>
		<title>Wiki Butiá</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?title=Wiki_Buti%C3%A1&amp;diff=167"/>
				<updated>2011-06-08T13:14:43Z</updated>
		
		<summary type="html">&lt;p&gt;Edgardo: /* Proyecto Butiá */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Proyecto Butiá ==&lt;br /&gt;
Este proyecto plantea como objetivo crear una plataforma simple, la cual ponga al alcance de estudiantes escolares o liceales las herramientas necesarias para permitirles interiorizarse en la programación del comportamiento de robots.&lt;br /&gt;
Actualmente la implmentación 1.0 del proyecto está siendo utilizado en formato de kit, distribuido a 28 liceos públicos del Uruguay, con un set de sensores y piezas que permiten cambiar la ubicación de los sensores en la plataforma móvil donde se coloca la computadora XO del proyecto OLPC.&amp;lt;br&amp;gt;&lt;br /&gt;
De todas formas el proyecto butiá fue desarrollado de manera que sea muy sencillo agregar nuevos sensores o actuadores, lo cual abre la posibilidad a que usuarios a los cuales les interese aspectos más relacionados con el hardware puedan implementar sus propios sensores y actudores de forma sencilla. Incluso el diseño industrial del robot es abierto lo cual permite realizarlo con materiales reciclados o de bajo costo.&lt;br /&gt;
&lt;br /&gt;
== TortugArte Butiá ==&lt;br /&gt;
&lt;br /&gt;
Tortugarte es una actividad Sugar la cual pone al alcance de niños conceptos de programación, mediante una interfaz icónica, donde cada instrucción se mapea como un bloque.&lt;br /&gt;
El proyecto butiá realizó un plugin para TortugArte que permite controlar el Robot Butiá y tomar valores de sus sensores muy fácilmente.&amp;lt;br&amp;gt;&lt;br /&gt;
Dado que el robot Butiá tiene soporte plug and play para los sensores/actuadores que se conectan al mismo son detectados permitiendo cambiar el color de los bloques correspondientes a los elementos de sensado/actuación según lo que se haya conectado al robot.&amp;lt;br&amp;gt;&lt;br /&gt;
Puede descargarse una versión autoinstalable de TortugArte Butia desde el [http://activities.sugarlabs.org/es-ES/sugar/addon/4434 Repositorio de actividades Sugar]&lt;br /&gt;
&lt;br /&gt;
*[[Ejemplos_TortugArteButiá|Ejemplos de comportaminetos que pueden realizarse en tortugarte con el plugin Butiá]]&lt;br /&gt;
&lt;br /&gt;
== Curso módulo taller Butiá ==&lt;br /&gt;
&lt;br /&gt;
* [[proyectos_mtbutia_2011|Proyectos módulo taller butiá 2011]]&lt;br /&gt;
&lt;br /&gt;
* [[proyectos_mtbutia_2010|Proyectos módulo taller butiá 2010]]&lt;br /&gt;
&lt;br /&gt;
== Extensión Universitaria ==&lt;br /&gt;
&lt;br /&gt;
* [[talleres_y_charlas|Talleres y charlas]]&lt;br /&gt;
&lt;br /&gt;
* [[entrega_de_Butiá_V1.0|Entrega de 28 robots Butiá en el evento Sumo.uy 2010]]&lt;br /&gt;
&lt;br /&gt;
== Charlas Butiá ==&lt;br /&gt;
&lt;br /&gt;
* [http://www.fing.edu.uy/inco/proyectos/butia/mediawiki/public/pres_seMINArios_2011_handouts.pdf Charla del robot Butiá el los seMINArios del Instituto de Computación, UdelaR, Montevideo, Uruguay, 2011]&lt;br /&gt;
&lt;br /&gt;
* [http://www.fing.edu.uy/inco/proyectos/butia/mediawiki/public/presCASE2011HandsOut.pdf Charla del robot Butiá en el congreso argentino de sistemas embebidos, Buenos Aires, 2011]&lt;br /&gt;
&lt;br /&gt;
* [http://www.fing.edu.uy/inco/proyectos/butia/mediawiki/public/butia-jornadasANTel-FIng2011.pdf Charla del robot Butiá en las jornadas de telecomunicaciones realizadas, Rocha, Uruguay, 2011]&lt;br /&gt;
&lt;br /&gt;
* [http://www.fing.edu.uy/inco/proyectos/butia/mediawiki/public/presCPBRASIL.pdf Charla del robot Butiá en el campus party, San Pablo, Brasil, 2011]&lt;br /&gt;
&lt;br /&gt;
== Construcción ==&lt;br /&gt;
&lt;br /&gt;
* [[construcción_Butiá_V1.0|Construyendo un Robot Butiáv1.0 paso a paso]]&lt;br /&gt;
&lt;br /&gt;
== Desarrollo ==&lt;br /&gt;
&lt;br /&gt;
La plataforma Butiá fue liberada como software libre a la comunidad y puedes contribuir con el proyecto como desarrollador uniendote en [https://sourceforge.net/projects/butia/ proyecto butiá en sourceforge]&lt;br /&gt;
&lt;br /&gt;
== Empezando ==&lt;br /&gt;
&lt;br /&gt;
Consulta la [http://meta.wikimedia.org/wiki/Ayuda:Contenido Guía de usuario] para obtener información sobre el uso del software wiki.&lt;br /&gt;
* [http://www.mediawiki.org/wiki/Manual:Configuration_settings Lista de ajustes de configuración]&lt;br /&gt;
* [http://www.mediawiki.org/wiki/Manual:FAQ/es FAQ de MediaWiki]&lt;br /&gt;
* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de correo de anuncios de distribución de MediaWiki]&lt;/div&gt;</summary>
		<author><name>Edgardo</name></author>	</entry>

	</feed>