<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>TuxDroid</title>
  <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/taxonomy/term/1113"/>
  <link rel="self" type="application/atom+xml" href="http://artisan.karma-lab.net/taxonomy/term/1113/atom/feed"/>
  <id>http://artisan.karma-lab.net/taxonomy/term/1113/atom/feed</id>
  <updated>2008-10-01T02:31:53+02:00</updated>
  <entry>
    <title>Spécification Tuxdroid Gadget API</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1567" />
    <id>http://artisan.karma-lab.net/node/1567</id>
    <published>2008-05-01T17:32:07+02:00</published>
    <updated>2008-09-01T02:48:51+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="TuxDroid" />
    <category term="Aucun" />
    <category term="OK" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p>
  Ce document a pour objectif de définir le fonctionnement des Gadgets TuxDroid et du conteneur associé. Il a valeur de loi, et nul n'est sensé ignorer la loi <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>
</p>


	<a name='chapter_1'></a>
  
	<a name='chapter_2'></a>
  <h2>Licence</h2>
	
	
<p>
 L'ensemble des développements est sous Licence GPL v2. Chaque fichier source dispose d'un en-tête décrivant sommairement la licence, le nom de l'auteur et les droits à la société Kysoh. 
</p>    ]]></summary>
    <content type="html"><![CDATA[<p>
  Ce document a pour objectif de définir le fonctionnement des Gadgets TuxDroid et du conteneur associé. Il a valeur de loi, et nul n'est sensé ignorer la loi <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>
</p>


	<a name='chapter_3'></a>
  <h2>Licence</h2>
	
<p>
 L'ensemble des développements est sous Licence GPL v2. Chaque fichier source dispose d'un en-tête décrivant sommairement la licence, le nom de l'auteur et les droits à la société Kysoh. 
</p>


	<a name='chapter_4'></a>
  <h2>Conteneur de Gadgets</h2>
	
<h3>Organisation générale</h3>
<p>
  Le système proposé suit le schéma d'un <u>framework</u>. C'est à dire que les gadgets sont insérés dans le flot de traitement d'un ensemble plus large qui en fixe les règles de gestion, contrairement à une API ou une librairie qui s'insère dans le flot de traitement de l'appelant.  
</p>

<h3>Aspect conteneur</h3>
<p>
  L'architecture du Tuxdroid Gadget Framework est centré autour d'un <u>conteneur</u>. Cette philosophie est <u>emprunté</u> aux serveurs d'application, de même que le système de déploiement/retrait des gadgets du système. L'idée en est que le framework maintient en permanence la liste des gadgets qu'il connait, de leur état, de leurs propriétés, etc. Le conteneur est le médiateur obligatoire entre l'application tiers et les gadgets. C'est lui qui les instancie, les exécute, les arrête, les détruit, etc.
</p>

<h3>Auto déploiement</h3>
<p>
   Le conteneur de gadget observe en permanence un dossier spécial dit <u>dossier d'auto déploiement</u>. Lorsqu'il y détecte l'arrivée d'une nouvelle archive, il la décompresse dans un autre dossier dit <u>dossier de travail</U>. Cette phase est appelée <u>déploiement</u>. 
</p>

<p>
   A chaque lancement du conteneur, les gadgets sont redéployés. Si un gadget est détruit, le dossier correspondant l'est lui aussi. Enfin, si au démarrage un dossier n'a pas d'archive associée, il est automatiquement retiré.
</p>

<h3>Listeners</h3>
<p>
  Le conteneur est un objet Java produisant un certain nombre de notifications à ceux qui s'y abonnent 
  <ul>
  <li>void gadgetContainerError(Throwable throwable), si une erreur a été détecté par exemple en phase de déploiement.</li>
  <li>void gadgetLoaded(Gadget gadget), si un gadget a été chargé (voir le cycle de vie d'un gadget).</li>
  <lI>void gadgetUnloaded(Gadget gadget), si le gadget a été déchargé, par exemple s'il a été supprimé.</li>
  <li>void deployementTerminated(), si le déploiement d'un gadget vient juste d'être terminé.</li>
  </ul>
</p>

<h3>Mise en oeuvre</h3>
<p>
   La mise en oeuvre du conteneur est très simple
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; &nbsp; &nbsp; <span class="co1">// Création du conteneur</span><br />
&nbsp; &nbsp; &nbsp; GadgetContainer container <span class="sy0">=</span> <span class="kw1">new</span> GadgetContainer<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span class="co1">// Ajout du listener sur le conteneur &nbsp; &nbsp; &nbsp; &nbsp;</span><br />
&nbsp; &nbsp; &nbsp; container.<span class="me1">addListener</span><span class="br0">&#40;</span><span class="kw1">new</span> GadgetsContainerListener<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
<br />
&nbsp; &nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">void</span> gadgetUnloaded<span class="br0">&#40;</span>Gadget gadget<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Appelé lorsqu'un gadget a été retiré du conteneur</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">void</span> gadgetLoaded<span class="br0">&#40;</span>Gadget gadget<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Appelé lorsqu'un gadget a été ajouté (déployé) au conteneur</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">void</span> gadgetContainerError<span class="br0">&#40;</span><a target="blank" href="http://www.google.com/search?hl=en&amp;q=allinurl%3AThrowable+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">Throwable</span></a> throwable<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; Appelé lorsqu<span class="st0">'un exception c'</span>est produite lors du processus de déploiement ou d<span class="st0">'enregistrement <br />
<br />
&nbsp; &nbsp; &nbsp; }<br />
<br />
&nbsp; &nbsp; &nbsp; @Override<br />
&nbsp; &nbsp; &nbsp; public void deployementTerminated() {<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Appelé quant le déploiement initial est terminé. <br />
&nbsp; &nbsp; &nbsp; }<br />
&nbsp; &nbsp; });<br />
<br />
&nbsp; &nbsp; &nbsp; // Ajout d'</span>un organe de déploiement<br />
&nbsp; &nbsp; &nbsp; container.<span class="me1">addAutoDeployer</span><span class="br0">&#40;</span><span class="st0">&quot;/dossier_de_travail&quot;</span>, <span class="st0">&quot;/dossier_de_gadgets&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>


	<a name='chapter_5'></a>
  <h2>Définition du gadget</h2>
	
<h3>Vue générale</h3>
<p>
  Un gadget est programme écrit dans <u>n'importe quel langage</u> qui lors de son exécution communique avec le conteneur à l'aide d'un protocole normalisé. Comme nous l'avons vu plus haut, une fois le gadget déployé dans le conteneur, il est soit utilisable à travers une instance de la class <kbd>Gadget</kbd>. Cette instance peut soit être récupérée de manière assynchrone via le listener du conteneur, soit comme suit :
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">for</span> <span class="br0">&#40;</span>Gadget gadget<span class="sy0">:</span>container.<span class="me1">getGadgets</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; ... <br />
<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>

<h3>Format du gadget</h3>
<p>
   Un Gadget est une archive au format ZIP portant l'extension .tgf. Son contenu est totalement libre. Le langage utilisé pour rédiger un gadget est lui aussi absolument libre (C, en Python, en Java, en Bash, etc.).
</p>
<p>
 A la racine de l'archive se trouve fichier XML, nommé <u>gadgets.xml</u> donnant :
 <ul>
 <li>La description du gadget</li>
 <li>Son mode d'exécution</li>
 <li>Ses données</li>
 <li>Ses commandes</li>
 <li>Ses notifications</li>
 </ul>
 </p>
 <p>
   Voici un exemple pour un tel fichier :
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  &nbsp; &nbsp;<span class="sc3"><span class="re1">&lt;gadgets<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;gadget<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;interpreter</span><br />
&nbsp; &nbsp; &nbsp; <span class="re0">kind</span>=<span class="st0">&quot;java&quot;</span><span class="re2">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;executable<span class="re2">&gt;</span></span></span>net.karmaLab.tuxDroid.gadgets.WeatherGadget<span class="sc3"><span class="re1">&lt;/executable<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/interpreter<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;description<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;name<span class="re2">&gt;</span></span></span>Weather Gadget<span class="sc3"><span class="re1">&lt;/name<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;description<span class="re2">&gt;</span></span></span>Google Weather Gadget<span class="sc3"><span class="re1">&lt;/description<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;author<span class="re2">&gt;</span></span></span>Y. Brault (C) http://artisan.karma-lab.net 2008<span class="sc3"><span class="re1">&lt;/author<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;version<span class="re2">&gt;</span></span></span>1.0<span class="sc3"><span class="re1">&lt;/version<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;iconFile<span class="re2">&gt;</span></span></span>resources/WeatherGadget.png<span class="sc3"><span class="re1">&lt;/iconFile<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;uuid<span class="re2">&gt;</span></span></span>f63af23e-7ae0-4389-b89b-bc5a8185b0b8<span class="sc3"><span class="re1">&lt;/uuid<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/description<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;parameters<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;parameter</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">name</span>=<span class="st0">&quot;location&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">description</span>=<span class="st0">&quot;Weather location&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">type</span>=<span class="st0">&quot;string&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">defaultValue</span>=<span class="st0">&quot;paris&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;parameter</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">name</span>=<span class="st0">&quot;unit&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">description</span>=<span class="st0">&quot;Temperature unit (celcius, fareneight)&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">type</span>=<span class="st0">&quot;enum(celcius,fareneight)&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">defaultValue</span>=<span class="st0">&quot;celcius&quot;</span> <span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;parameter</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">name</span>=<span class="st0">&quot;tomorrow&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">description</span>=<span class="st0">&quot;Give tomorrow weather too&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">type</span>=<span class="st0">&quot;boolean&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">defaultValue</span>=<span class="st0">&quot;false&quot;</span> <span class="re2">/&gt;</span></span> &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/parameters<span class="re2">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;commands<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;command</span> <span class="re0">name</span>=<span class="st0">&quot;play&quot;</span> <span class="re0">description</span>=<span class="st0">&quot;play&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;command</span> <span class="re0">name</span>=<span class="st0">&quot;stop&quot;</span> <span class="re0">description</span>=<span class="st0">&quot;stop&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/commands<span class="re2">&gt;</span></span></span><br />
<br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;notifications<span class="re2">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;command</span> <span class="re0">name</span>=<span class="st0">&quot;test&quot;</span> <span class="re0">description</span>=<span class="st0">&quot;Test notification&quot;</span><span class="re2">/&gt;</span></span><br />
&nbsp; &nbsp; <span class="sc3"><span class="re1">&lt;/commands<span class="re2">&gt;</span></span></span><br />
&nbsp; <span class="sc3"><span class="re1">&lt;/gadget<span class="re2">&gt;</span></span></span><br />
<span class="sc3"><span class="re1">&lt;/gadgets<span class="re2">&gt;</span></span></span>
  </div>
  
  </div>
 </p>
 <p>
 Comme vous le voyez, ce fichier peut définir plusieurs gadgets contenus dans la même archive.
 </p>
 <p>
    La description d'un gadget n'est JAMAIS à lire à travers le fichier XML. En fait toute application utilisant un gadget doit passer impérativement par son instance de la classe <kbd>Gadget</kbd>.
 </p>
 
 <h3>Interpreteur</h3>
 <p>
 La section <kbd>interpreter</kbd> définit  : 
<dl>
   <dt>L'interpréteur</dt>
   <dd>sh, perl, java, python, etc..</dd>

   <dt>L'URI de la ressource</dt>
   <dd>./mon_gadhet.sh</dd>
</dl>
</p>
<div class='inline-box note'>
Notez que certains interpréteurs font plus de choses que d'autre. Par exemple en mode <kbd>java</kbd>, le dossier <kbd>./librairies</kbd> est automatiquement inclus dans le classpath.
</div>


	<a name='chapter_6'></a>
  <h2>Identification</h2>
	
<p>
   Le gadget fournit aussi des données fondamentales :
<ul>
<li>Son nom</li>
<li>Sa description</li>
<li>Son auteur</li>
<li>Sa version</li>
<li>Son UUID, qui représente un ID unique pour ce gadget</li>
</ul>
</p>

<div class='inline-box attention'>
  Chaque commande exécuté doit rendre la main le plus rapidement possible.   
</div>
<p>
   Pour accéder à la description d'un gadget, il faut passer par son objet <kbd>Gadget</kbd>, par exemple :
    
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// récupération de la description du gadget</span><br />
gadget.<span class="me1">getDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">getDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<div class='inline-box note'>
   La description et le fichier d'aide (gadget.getHelpFile()) sont automatiquement traduits par le framework. 
</div>

<a name="Internationalisation"></a>
<h3>Internationalisation</h3>
<p>
	Les gadgets utilisent le système <kbd>gettext</kbd> standard dans le monde de l'openSource (utilisé par Drupal, Linux, Gnome, etc.). 
</p>

<p>En fait le concept est ultra simple. L'idée est que toutes les chaînes à traduire sont passées par une fonction unique qui maintient les traductions en mémoire.</p>
<p>
 Pour du code Java ça donne quelque chose comme cela :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// Chargement du moteur de traduction</span><br />
I18n i18n<span class="sy0">=</span> <span class="kw1">new</span> I18n<span class="br0">&#40;</span><span class="st0">&quot;./resources&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1">// Traduction d'un message</span><br />
<a target="blank" href="http://www.google.com/search?hl=en&amp;q=allinurl%3ASystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">System</span></a>.<span class="me1">out</span>.<span class="me1">println</span> <span class="br0">&#40;</span>i18n.<span class="me1">tr</span><span class="br0">&#40;</span><span class="st0">&quot;This is a message with one parameter : %d&quot;</span>, <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
La fonction <kbD>i18n.tr(....)</kbD> va chercher dans son dictionnaire la traduction de <kbD>This is a message with one parameter : %d</kbd>. S'il la trouve, il renvoie sa valeur, sinon il renvoie la chaîne d'origine.
</p>
<p>
 Il est donc possible de voir ce qui n'est pas encore traduit en basculant par exemple en français et en localisant toutes les chaînes encore en anglais. L'avantage c'est que si la traduction n'a pas encore été faite, les chaînes restent lisibles pour l'utilisateur ET dans le code. 
</p>
<p>
Les dictionnaires sont de simples fichiers textes que l'objet I18n va chercher dans le dossier qui est passé en paramètre de son constructeur (<kbD>./resources</kbd>). Pour ce faire, il se base sur la fonction java <kbd>Locale.getDefault().getLanguage()</kbd> qui renvoie la langue courante du système.</p>
<p>
 Pour un système français cela renvoie "fr". L'objet i18n va donc chercher un fichier appelé <kbd>./resources/fr.po</kbd>. 
</p>
<p>
Ce fichier <kbd>fr.po</kbd> contient une série de traductions sous la forme :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  msgid &quot;﻿This is a message with one parameter : %d&quot;<br />
msgstr ﻿&quot;Ceci est un message avec paramètre %d&quot;<br />
<br />
msgid &quot;﻿Another message&quot;<br />
msgstr ﻿&quot;Un autre message&quot;
  </div>
  
  </div>
</p>
<p>
Ce sont ces traductions que l'objet <kbd>I18n</kbd> va charger en mémoire et que la fonction <kbd>i18n.tr</kbd> va utiliser. 
</p>

<p>
Pour les fichiers XML, il n'y a évidement pas de fonction <kbd>i18n.tr</kbd> directement dans le fichier. C'est le framework qui avant de renvoyer une chaîne provenant du fichier gadgets.xml, par exemple au ControlCenter, va la faire passer dans <kbd>i18n.tr</kbd>. 
</p>

<p>
  De la même manière le framework va passer à la fonction <kbd>i18n.tr</kbd> toutes les notifications de gadget de type <kbd>message</kbd>. Du coup, le code gadget suivant sera automatiquement traduit :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  throwMessage<span class="br0">&#40;</span><span class="st0">&quot;This is a message with one parameter : %d&quot;</span>, <span class="nu0">1</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
  Le Control Center recevra cette notification déjà traduite donc, sauf si bien sur cette chaîne n'est pas dans le fichier .po de la langue courante ou que la langue courante n'a pas encore de fichier .po.
</p>
<p>
Le format des fichiers .po est très évolué, il permet de chercher des chaînes simples, des chaînes "floues", des chaînes avec pluriels, etc. Pour l'instant, la lecture des fichiers .po se fait dans karmalab-commons (la librairie d'utilitaires utilisé par le framework) avec une version très simple et très rapide d'un parser de .po. 
</p>
<p>
Si les besoins évoluent vers plus de complexité, on fera évolué cet objet pareillement. 
</p>
<p>
En somme, les avantages l'approche .po par rapport aux classique Bundles de ressources Java sont :
<ul>
  <li>Le code reste lisible de manière naturelle.</li>
  <li>Même si des chaînes ne sont pas traduite, la lecture de l'interface reste possible.</li>
  <li>Les fichiers .po ne sont pas inclus dans les .jar, mais sont des fichiers que chacun peut lire, modifier, étendre. Cela facilite les contributions par <b>de purs non-informaticiens</b>.</li>
  <li>Il existe de nombreux outils permettant d'éditer des .po : http://drupal.org/node/11131</li>
</ul>
</p>
<p>
 Pour l'aspect développeur, La génération de .po est elle aussi assez simple, y compris à partir du code Java. 
</p>
<p>
La première étape consiste à générer un fichier .pot (Portable Object Template) qui n'est rien d'autre qu'un .po dont tous les "msgstr" sont vides. Cela se fait par la commande suivante

  <div class='code-block code-block-fragment'>
  <div class='container'>
  xgettext -k_ -o po<span class="sy0">/</span>messages.pot src<span class="sy0">/</span>Translatable.java
  </div>
  
  </div>
<p>
Ensuite on duplique le .pot en, par exemple, fr.po pour rédiger une traduction ou envoyer les fichiers à un traducteur. 
</p>
<p>
  Ensuite pour la mise à jour, quant le code source évolue et donc que de nouveaux messages apparaissent, ou que d'anciens messages disparaissent, il suffit de régénérer le .pot et d'appliquer cette nouvelle mouture aux fichiers .po existants :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  msgmerge -U po<span class="sy0">/</span>fr.po po<span class="sy0">/</span>messages.pot
  </div>
  
  </div>
<p>
<p>
   Concernant le fichier d'aide du gadget, il est lui aussi traductible mais de manière un peu différente. L'idée est que par défaut le gadget doit avoir un fichier <kbd>./resources/help.html</kbd> et optionellement plusieurs fichiers <kbd>./resources/help_xx.html</kbd>. De la même manière lorsque l'hote demande la référence au fichier d'aide du gadget, celui-ci lui renvoie la version traduite automatiquement si elle existe, la version anglaise le cas échéant ou <kbd>null</kbd> si aucun fichier n'est présente. 
</p>

<div class='inline-box note'>
  La variable <kb>tgp_language</kb>, fournit au gadget le langage courant à utiliser lors des traductions (voir paramètres du gadget plus bas). 
</div>

<h3>Notifications et commandes</h3>
<p>
  A travers les sections <kbd>commands</kbd> et <kbd>notifications</kbd>, le gadget indique au conteneur les <u>commandes</u> qu'il prend en charge et les <u>notifications</u> qui peut générer. Le lancement de ces commandes et la prise en charge des notifications est à la charge du Control Center. 
</p>
<p>
   Dans les deux cas, chaque commande/notification est caractérisée par 
   <ul>
   <li>Un ID</li>
   <li>Une description</li>
   </ul>
</p>
<p>
   Pour accéder à ces données, il faut passer par son objet <kbd>Gadget</kbd>. Dans les deux cas l'objet retourné est de classe <kbd>GadgetToken</kbd>, par exemple :
    
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// récupération de l'id de la première commande</span><br />
gadget.<span class="me1">getCommands</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>.<span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<br />
<span class="co1">// récupération de l'id de la première notification</span><br />
gadget.<span class="me1">getNotification</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">get</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span>.<span class="me1">getId</span><span class="br0">&#40;</span><span class="br0">&#41;</span>
  </div>
  
  </div>
</p>
<div class='inline-box note'>
   La description est automatiquement traduite par le framework. 
</div>

<h3>Données du Gadget</h3>
<p>
   Dans la section <kbd>parameters</kbd>, le Gadget fournit l'ensemble des données dont il a besoin pour fonctionner. Cela correspond à une liste où chaque élément est composé comme suit : 
  <ul>
  <li>Nom, le nom de la donnée.</li>
  <li>Description, la description (en anglais !!) de la donnée.</li>
  <li>Type, le type de la donnée pouvant être : string, integer, double, boolean, enum(litem1,item2...,itemn)</li>
  <li>defaultValue, la valeur par défaut de la donnée.</li>
  </ul>
</p>
<div class='inline-box note'>
   La description et la valeur par défait sont automatiquement traduites par le framework. 
</div>
<div class='inline-box note'>
  La modification et la sauvegarde des données est à la charge du Control Center. La création d'un jeu de donnée pour un Gadget va nous permettre d'instancier le Gadget. 
</div>
<p>
   Pour accéder à ces données, il faut passer par son objet <kbd>Gadget</kbd> et récupérer l'objet <kbd>GadgetParameter</kbd> correspondant, par exemple :
    
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="kw1">for</span> <span class="br0">&#40;</span>GadgetParameter parameter gadget.<span class="me1">getParameters</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp;parameter.<span class="me1">getKind</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp;parameter.<span class="me1">getDescription</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp;...<br />
&nbsp;<span class="br0">&#125;</span>
  </div>
  
  </div>
</p>

<h3>Gagdet et Instance de Gadget</h3>
<p>
   Un gadget dans l'état une fois connu du conteneur est dans un état "chargé" et n'est pas instancié en mémoire (cad exécuté). Seule sa description (cf gadgets.xml) est connue du conteneur et des applications tiers. 
 </p>
 <p>
   Pour exécuter une commande du Gadget, il convient donc de transforme le Gadget en <kbd>Instance de Gadget</kbd> que le Control Center va ensuite pouvoir exécuter et même stopper en cours d'exécution si besoin était. 
 </p>
 <p>
   A ce titre on comprend qu'une instance est composée :
   <ul>
   <li>D'une référence au gadget "chargé".</li>
   <li>D'un jeu de valeurs correspondant à ses paramétres d'exécution.</li>
   <li>Du nom de la commande à exécuter.</li>
</ul>
</p>
<p>
  La conséquence de cette approche est qu'il n'est pas besoin de faire des gadgets à la configuration complexes mais d'utiliser les instances pour réduire cette complexité. Prenons l'exemple d'un Gadget lisant les flux RSS. Il a pour données <kbd>l'URL à lire</kbd> et comme commande <kbd>checkRSS</kbd>. Pour effectuer le traitement, il va falloir créer une<kbd> instance du Gadget RSS</kbd>, prenant en paramètre la commande à exécuter ET les valeurs des paramètres de l'instance. On en déduit que si l'on désire lire plusieurs flux RSS, il suffira de crée plusieurs instances associées chacune à un jeu de données unique. 
</p>
<p>
   Pour créer une instance de gadget à travers le framework, la syntaxe est la suivante
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  GadgetInstance instance <span class="sy0">=</span> gadget.<span class="me1">create</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
   Ensuite une commande est invokable de la manière suivante :
   
  <div class='code-block code-block-fragment'>
  <div class='container'>
  instance.<span class="me1">start</span><span class="br0">&#40;</span>command, parameters<span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>   
</p>
<p>
   Si command est à <kbd>null</kbd>, c'est la commande par défaut du gadget qui est utilisée, sinon il s'agit d'un objet GadgetToken que l'on récupère par <kbd>gadget.getCommands().get(XXX)</kbd>. Les paramétres sont une liste de <kbd>GadgetParameter</kbd> contenant les valeurs des paramétres pour cette exécution de commande. 
</p>

<h3>Protocole de communication</h3>
<p>
  La communication entre le gadget et l'hôte, doit être suffisamment simple pour permettre la rédaction dans tous les langages. L'idée de base est que les commandes sont passées en argument, les données dans les variables d'environnement, et les notifications sont renvoyés sur le canal StdOut.
</p>
<p>
  Les données dans les variables d'environnement sont préfixées avec la chaîne de caractère <kbd>tgp_</kbd>. Si le gadget déclare une données <kbd>message</kbd>, il recevra donc sa valeur dans la variable <kbd>$tgp_message</kbd>.
</p>
<div class='inline-box note'>
  La variable <kb>tgp_version</kb>, fournit au gadget la version du protocole. ex. <kbd>1.0</kbd>. Charge au gadget de correctement prendre en charge la version du protocole.
</div>
<p>
   Lorsqu'un gadget est exécuté sans paramètres, il revoies sa description sous la forme d'un flux XML. Ensuite exécuté avec en paramètre un ID de commande, il exécute la commande correspondante.
</p>
<p>
   Les notifications sont émises sur le canal stdOut sous la forme :<br/>
   <kbd>ID "PARAM1" "PARAM2" ... "PARAM2"</kbd>
</p>
<p>
  Les paramètres sont des chaînes qui sont échappées sur le caractère <kbd>"</kbd>.
</p>
<p>
   Il existe un certain nombre de d'ID de notification standard que le gadget n'a pas besoin de déclarer pour les utiliser :
   <ul>
   <li><kbd>message chaîne param1 param2 ... paramN</kbd>, indique à l'hôte que ce qui suit est un message en anglais, de la forme <kbd>message {0} suite {1}</kbd>. Les paramètres sont neutres du point de vue de la langue ce qui fait que le message peut être traduit sans risque. Le fait de transformer ce message en parole par le Tux est à la charge du Control Center.</li>
   <li><kbd>trace chaîne param1 param2 ... paramN</kbd>, fonctionne comme message mais fournit une trace d'exécution.</li>
   <li><kbd>error chaîne param1 param2 ... paramN</kbd>, fonctionne comme message mais fournit une erreur d'exécution.</li>
   </ul>
</p>


	<a name='chapter_7'></a>
  <h2>Questions/réponses</h2>
	

<h3>Comment afficher plus d'information lors d'une erreur sur un gadget</h3>
<p>
  Si une erreur se produit, le message de l'exception est remonté par le framework sous la forme d'une notification "error". En activant le mode "traces" du gadget (propriété traces à true), c'est la trace complète qui est remontée avec numéros de lignes & co. Pour l'activer, la solution est peu simple pour l'instant, il faut passer la valeur à true à la ligne
</p>

<h3>Pourquoi ne pas faire parler et utiliser la télécommande du TUX directement dans un gadget ?</h3>

<p>
   Comme base à ce framework, il y a deux constats induits par les précédentes générations :
<ol>
<li>70% des actions physiques sur le Tux faites par les gadgets est de le faire parler.</li> 
<li>Les 20% restant correspondant à prendre en charge la télécommande,
les boutons du Tux et les capteurs pour effectuer des actions sur les
tuxlets.</li>
</ol>
</p> 
 
<p>
   Du coup pour simplifier le développement des gadgets, il semble pertinent de remonter ces deux aspects sous la forme de services offerts aux gadgets évitant ainsi un code redondant :
<ul>
<li>
   Sous la forme d'une fonction qui fait parler le Tux (throwMessage) qui utiliserait toujours la même voix, le même timbre et la même langue. </li>
<li>
   En mettant en place dans le manager un système permettant
d'associer UN évènement (de type "Bouton X de la télécommande", "Niveau
Y de la lumière", etc) à UNE commande pour UNE instance d'UN gadget. 
</li>
</ul>
</p>
<p>
  Ainsi le Gadget fournit des commandes,
qui sont associées, PAR le Control Center, à UN évènement. L'utilisateur
peut donc décider de relier par exemple le fait de taper sur la tête du
Tux pour lire ses eMails sans que moi, développeur du gadget, n'ai eu
une seule ligne de code à écrire pour que cela soit rendu possible. Tout
est à la charge du Control Center. </p>
<p>
En somme, rien n'empêche le gadget de contrôler lui-même le Tux, mais en faisant cela de manière systémauqye, on s'expose 1/ à un code
plus complexe 2/ à des conflits entre les différents gadgets sur une
ressource physique donnée (ex. deux gadgets utilisent le même bouton XX
de la télécommande)
</p>
<p>
D'un point de vue ergonomique, l'idée est en trois/quatre
click d'associer une commande à un évènement qui peut être :
<ul>
<li> Une alarme temporelle (ex. tout les N minutes, à 10h chaque jour,
etc) en utilisant la librairie Quartz</li>
<li>Un bouton du Tux (ex. tête, aile, etc..)</li>
<li>Un bouton de la télécommande</li>
<li>Un seuil de capteur lumineux</li>
<li>Un seuil de capteur sonore</li>
<li>Une notification venant d'un autre gadget</li>
<li>...</li>
</ul>

<p>Avec un tel système il est possible grâce au control center, et
sans qu'un code soit inclus dans le gadget lui-même, d'opérer par exemple une lecture des
mails lorsque la lumière du jour a suffisamment baissé. Il s'agit juste d'un exemple, mais cela permet de comprendre la, je pense,
puissance de l'approche "par évènement" à contrario de l'approche "par
code gadget".</p>
<p>
 Un exemple plus crédible du même ordre serait un gadget
qui allume les yeux du Tux que l'utilisateur peut décider d'associer à
l'arrivée de la nuit et un gadget qui fait simplement dire un message au
tux qui lui fait faire "Cocorico" le matin <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>
</p>
<p>
En somme l'approche par évènements simplifie les gadgets et les rends
beaucoup plus souple, et le fait de laisser le control center faire
parler le tux par le biais de notification permet de centraliser
proprement le paramétrage des voix sans avoir à envoyer à chaque instance de gadget un
paramétrage de voix juste pour qu'il sache correctement parler. De même le gadget n'a pas à gérer de configuration complexes de boutons, horloge, etc, car tout est factorisé dans le Control Center. 
</p>


<h3>Pourquoi les librairies du Control Center/Gadget Tester ne sont pas héritées par le Gadget ?</h3>
<p>
Dans le cas des gadgets écrits en Java, il faut bien comprendre une chose sur le mode de lancement des
gadgets. Il sont exécutés dans <b>un processus différent de l'application
hôte</b> (Control Center ou Gadget Tester). Cela implique dans le cas d'un gadget en Java qu'il ne partage pas
la même machine virtuelle que le contrôle Center. L'avantage est que si
le gadget plante, cela n'affecte en rien le Control Center. La
contrepartie est que le gadget démarrant sur une machine virtuelle
vierge, n'hérite pas des dépendances qu'utilise le Control Center. Cela
implique aussi qu'un Gadget peut utiliser des librairies de version
différente du CC. 
</p>
<p>
Ainsi, un gadget écrit en BASH qui dit "Hello World" ressemblera
seulement à cela :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co0">#! /bin/sh </span><br />
<span class="kw3">echo</span> message Hello World <span class="sy0">!!</span> : <span class="re1">$tgp_message</span>
  </div>
  
  </div>
</p>

<p>
Ce que l'on comprend du coup, c'est qu'un gadget n'a, a priori, besoin
de rien d'autre qu'un langage capable de lire les variables
d'environnement (paramètres du gadget) et d'écrire dans la sortie
standard (les notifications). 
</p>
<p>
Dans le cas des gadgets en Java, j'ai écrit une classe appelée
SimpleGadget qui va simplifier la fabrication, en java, de gadget en
fournissant des fonctions qui vont un peu cacher ce fonctionnement de
base variables/écriture dans la sortie standard. Du coup la fonction
"throwMessage" n'est rien d'autre qu'un simple :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <a target="blank" href="http://www.google.com/search?hl=en&amp;q=allinurl%3ASystem+java.sun.com&amp;btnI=I%27m%20Feeling%20Lucky"><span class="kw3">System</span></a>.<span class="me1">out</span>.<span class="me1">println</span><span class="br0">&#40;</span>message<span class="br0">&#41;</span>
  </div>
  
  </div>
</p>

<p>
Là ou un malentendu est apparu est que cette classe
SimpleGadget est dans le .Jar du framework. C'est pour cela qu'il faut
inclure le framework dans les gadgets pour qu'ils puissent fonctionner.
Mais le gadget n'utilise RIEN D'AUTRE dans ce .Jar QUE la classe
SimpleGadget. Au fond, il serait peut-être moins déroutant de mettre
cette classe toute seule dans un .jar du genre "SimpleGadget.Jar". Cela
générerait moins de confusion. 
</p>

<h3>Pourquoi le packaging via ANT plante sous Windows ?</h3>
<p>
Maintenant pour ce qui est de du packaging via ANT, j'ai déjà donné deux
fois il me semble la résolution de ce problème lié à Windows. C'est même
à la suite de cela que j'ai ajout le truc sur mon site à la fin de <a class='external' target='_blank' href='http://artisan.karma-lab.net/node/1156' >cette page</a>
</p>

<h3>Pourquoi utiliser UTF-8 sous Windows plutôt qu'ISO-8859-15 ?</h3>
<p>
Déjà l'utilisation d'UTF8 est un pré requis effectivement pour la librairie des PO. Je vous
conseille d'ailleurs vivement de ne pas laisser eclipse dans son mode
standard sous windows consistant à utiliser ISO-8859-15. Car dés que
vous allez avoir à utiliser des langues exotiques, vous allez être dans
le "caca".</p>
<p>
 UTF-8 est aujourd'hui une norme absolue et universellement
utilisée. Même Windows n'utilise plus que cela en interne. Le fait
qu'éclipse utilise ISO par défaut est juste un effet de bord malheureux
du à ce que Java par défaut sous Windows utilise ISO.
</p>
<p>
 Une fois que vous
avez défini UTF-8 comme étant l'encodage par défaut dans éclipse
(préférences du Workspace), il faut aussi que vous traduisiez tous vos
sources avec un utilitaire comme uconv. Je sais, c'est un peu casse
pied, mais obligatoire sur un gros projet. Sinon, je vous prédit de gros
soucis lorsque vous devrez intégrer des contributions de la communauté. 
</p>

<p>
Il faut donc impérativement basculer les sources en UTF8 car sinon on aura des gros
problèmes lors de l'intégration de contributions. Pour cela changer la
propriété "Text file encoding" dans
eclipse/windows/preferences/general/workspace ) UTF-8 et utiliser un
utilitaire comme "iconv" pour ré-encoder les sources dans un format
lisible par tous
</p>

<h3>Pourquoi n'y a t-il pas de en.po ? </h3>
<p>
   Les ID des chaînes sont pas norme en anglais, le en.po est donc innutile car si l'on ne trouve pas de traduction, c'est les ID qui sont utilisés. En revanche, il est de bon ton de mettre dans le dossier ./resources un gadgets.pot (PO Template) permettant de créer facilement une traduction.</p>

<h3>Pourquoi ne pas coller les .Jar des sous-projets TUX dans les dépendances d'un gadget ?</h3>
<p>
L'idée de base est de ne pas ajouter d'autres librairies dans le projet eclipse que celles
dont on ne dispose pas des sources (ex. javamail). Les librairies dont
les sources sont disponibles via tuxisalive ou karma-lab.net doivent
être checkouté à partir des dépots et liés dans l'onglet "projects".
</p>

	<a name='chapter_8'></a>
  <h2>Changements sur le framework</h2>
	
<h3>Gadget-Java-Kit</h3>
<p>
Pour éviter les confusions, une nouvelle librairie a été créée :
Tuxdroid-Gadget-JavaKit. Elle permet de construire plus rapidement des
gadgets en java et ne dépend d'AUCUNE AUTRE librairie. Ainsi les gadgets
en java ne dépendent plus de Gadget Framework.
</p>
<p>
  Je JavaKit est maintenant totalement standalone et ne dépend d'aucune librairies. Du coup, un gadget minimal ne fait plus que 40ko. Autre améliorations :
<ul>
<li>plus besoin de getter/setter dans les configuration, un champ, même privé, suffit</li>
<li>Une fonction readState et writeState permettant d'écrire l'état d'un objet dans le bon dossier de configuration.</li>
</ul>
</p>

<h3>Gadgets.xml</h3>
<p>
gadgets.xml est maintenant localisé dans le dossier ./ressources d'un
gadget. C'est plus cohérent ainsi. 
</p>

<h3>Editeur de propriétés</h3>
<p>
Les paramètres d'un gadgets ont maintenant une propriété "visible"
permettant de masquer certains paramètres comme "traces". Par défaut
cette propriété est à "true". C'est à usage interne mais il est possible
de spécifier un &lt;visible&gt;false&lt;/visible&gt; dans un gadgets.xml.
</p>

<h3>Locuteur & co</h3>
<p>
Tant que l'implémentation de throwMessage n'est pas finalisée dans le
Control Center (pile de textes), on garde locuteur, coutry & co dans le
conteneur. Cependant, dans la mesure où tous les gadgets ont le même
paramétrage, les données ont été déplacées de l'interpréteur au
GadgetsContainer (méthode setLocale). Cet appel ne change pas
dynamiquement la langue des gadgets déjà chargés mais celle de ceux qui
suivent l'appel.</p>
<p>

Les propriétés languages, locutor, country et pitch ont été normalisés
en tant que paramètre invisible du gadget. Dans un gadget, pour lire la langue par exemple, il suffit de faire un <kbd>configuration().getLanguage()</kbd>. 
</p>

<h3>Gadget Tester</h3>
<p>
  Ce dernier a beaucoup changé. Tout d'abord il supporte maintenant le changement de langues effectif pour la gadgets suivant. On peut décharger un gadget et, via le menu, demander le rechargement. 
</p>
<p>
   En revanche, le mode test dit "stand alone" a été viré. Maintenant pour tester dynamiquement un gadget, il faut passer par l'application Gadget Tester en mode "gadget" avec une commande du genre :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  java \<br />
&nbsp; &nbsp;-jar Gadget-Tester.jar \<br />
&nbsp; &nbsp;--<span class="re2">mode=</span>gadget \<br />
&nbsp; &nbsp;--<span class="re2">path=</span>..<span class="sy0">/</span>tuxdroid-gadget-clock \ &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp;--<span class="re2">classpath=</span>..<span class="sy0">/</span>targets<span class="sy0">/</span>eclipse:\<br />
&nbsp; &nbsp; &nbsp;..<span class="sy0">/</span>tuxdroid-gadget-java-kit<span class="sy0">/</span>targets<span class="sy0">/</span>eclipse
  </div>
  
  </div>
</p>
<p>Dans cet exemple, les dossiers ./targets/eclipse
et ../tuxdroid-gadget-java-kit/targets/eclipse, relatifs
à ../tuxdroid-gadget-clock sont insérés en tête du classpath,
surchargeant ainsi d'éventuelles librairies.
</p>

<h3>Traductions</h3>
<p>
  Vu les problèmes de Java pour formater les chaînes contendant des %, l'option a été prise de remplacer les %s par le formalisme Java/MessageFormat en utilisant des {0}, {1}, etc. Dans le même esprit, les chaînes contenant des doubles quotes echapées et des simples quotes sont maintenant utilisables sans problèmes. 
</p>

<h3>ThrowMessage synchrone</h3>
<p>
  Pour éviter les catapultage de message dans la pile TTS, une file de notifications synchrones a été ajoutée au Conteneur de Gadgets. L'idée est que les notifications de type "message" continue d'être postées par les gadgets en assynchrone, mais que le conteneur les place dans une file qu'il dépile dans un thread en le notifiant le suivant que si le précédent a été traîté par l'application hôte. 
</p>


</p>
</p>
    ]]></content>
  </entry>
  <entry>
    <title>TuxDroid Java API - Nouveautés de la 0.5</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1266" />
    <id>http://artisan.karma-lab.net/node/1266</id>
    <published>2007-11-01T02:44:45+01:00</published>
    <updated>2008-05-03T20:36:23+02:00</updated>
    <author>
      <name>Anonymous</name>
    </author>
    <category term="TuxDroid" />
    <category term="Aucun" />
    <category term="OK" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p>
Voilà, c'est fait, l'API passe à la version .5 au passage pour un support à 99% des fonctions du Tux. Le tout est embarqué dans un nouveau tuxlet manager, une application qui réside dans la boite de miniatures pour héberger des tuxlets, des micros applications qui ajoutent des fonctionnalités au pingouin.
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
Voilà, c'est fait, l'API passe à la version .5 au passage pour un support à 99% des fonctions du Tux. Le tout est embarqué dans un nouveau tuxlet manager, une application qui réside dans la boite de miniatures pour héberger des tuxlets, des micros applications qui ajoutent des fonctionnalités au pingouin.
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Change-Log</h2>
	
<ul>
<li>TuxletManager .2 with a brand news swing/GTK UI.
<li>Tuxlet API
<li>Feed Reader Tuxlet. It car read as many feed as you want using a specific voice.
<li>Clock Tuxlet
<li>Light seeker Tuxlet
<li>Weather Tuxlet
<li>Full binding of any thuxlet action to any remote button/Switch
<li>Binding of any tuxlet action to a new scheduler (at time, every time, each time events)
<li>Light graph tuxlet
</ul>

<p>
Donc finalement, une deuxième API se trouve embarquée dans cette histoire, celle des tuxlets. Rien de bien sorcier là dedans mais un moyen pour qui connaît java, de faire fonctionner le tux avec des fonctions très haut niveau et de bénéficier en même temps de l'API de base du robot. 
</p>
<p>
Pour décrire rapidement l'ensemble, le tuxlet manager est donc un conteneur de tuxlet qui sont basiquement des plugins (.jar) qui se pose dans le dossier ./tuxlets. Un plugin peut contenir autant de tuxlets que voulu. Le dépôt peut être fait à chaud, le manager les installera/désinstallera automatiquement (un peu comme une webapp). 
</p>
<p>
Une tuxlet par définition publie vers le tuxlet manager un ensemble d'actions haut niveau qui vont pouvoir être utilisées de divers manière (voir plus loin le configurateur et dbus). </p>
<p>
<image style="border:none"  id="1"/> Une fois que la tuxlet est installée, son icône se place dans la barre à tuxlets offrant un click-droit pour énumérer l'ensemble des actions que la tuxlet met à disposition. Le click gauche déclenche quant à lui l'action par défaut de la tuxlet.
</p>
<p>
Si la tuxlet n'a rien à afficher, la partie centrale de l'IHM sert de zone de message permettant d'avoir un retour visuel sur ce qu'à pu dire le Tux. Les messages peuvent être agrandis par un click. 
</p>
<p>
La configuration d'une tuxlet si elle existe, est disponible, comme toutes ses actions, via le menu click-droit. De même pour les informations de version.
</p>
<p>
<image style="border:none" id="2"/> Il y a pour l'heure les tuxlets :
<ul>
<li>"horloge" qui dit betement l'heure</li> 
<li>"météo" qui donne les conditions actuelles et les prévisions du lendemain</li>
<li>"lecteur de flux rss" qui va, via son panneau de configuration, vous permettre d'ajouter des flux RSS ou Atom, leur titre, le nombre de news à lire et s'il faut en lire le contenu ou seulement les titres. Il est aussi possible de changer la voix du tux spécifiquement pour cette tuxlet.</li>
<li>"chercheur de lumière", une simple tuxlet d'exemple qui fait tourner le tux sur lui même à la recherche de la plus forte source lumineuse.</li>
<li>"Configurateur", une grosse tuxlet qui permet de configurer la voix, les sons internes, d'afficher les informations de version, et le graphique di capteur lumineux.<br/>
Elle permet aussi de gérer le binding des touches de la télécommande OU d'un switch du Tux vers n'importe quelle action de n'importe quelle tuxlet (par exemple assigne la touche 0 à la météo). <br/>
Enfin, il y a maintenant un programmateur d'événement (genre de cron) qui peut être configuré ici aussi permettant de lancer n'importe quelle action de n'importe quelle tuxlet à une heure donnée, sur un intervalle de temps donnée, sur un temps donné (à 11h 12h 13h etc..).</li>
<li>"Mouvements", une tuxlet très simple qui permet de contrôler tous les mouvements du tux et qui exporte des actions du type "tourner à gauche", "tourner à droite", etc...</li>
</ul>
</p>
<p>
<image style="border:none"  id="3"/> Enfin, dernière chose ajoutée au tuxlet manager, le support de 
  <a target='_blank' href='http://fr.wikipedia.org/wiki/DBUS'>
  DBUS
  </a> lui donnant ainsi la capacité de pouvoir lancer des actions de l'extérieur (ex. un message parlé à l'arrivée d'un contact sous Gaim ou Kopete). Un script d'exemple est fournit dans le dossier ./bin</p>
<p>
Voilà pour cette version. Tout cela est bien évidement instable et à tester. Je ne pourrais être tenu responsable si le tux part en vrille <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>
</p>
<br style="clear:left"/>
    ]]></content>
  </entry>
  <entry>
    <title>TuxDroid - Le lever de soleil</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1237" />
    <id>http://artisan.karma-lab.net/node/1237</id>
    <published>2007-10-15T09:05:46+02:00</published>
    <updated>2008-02-12T11:40:37+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="TuxDroid" />
    <category term="Aucun" />
    <category term="javafr" />
    <category term="OK" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p>
Oui je sais, c'est "un peu" cul-cul la fraise, mais Dame, on s'amuse de peu ces temps-ci <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/smile.gif" title="Smiling" alt="Smiling" class="smiley-content"/> Voila donc un lever de soleil vu par le Tux. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>
Oui je sais, c'est "un peu" cul-cul la fraise, mais Dame, on s'amuse de peu ces temps-ci <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/smile.gif" title="Smiling" alt="Smiling" class="smiley-content"/> Voila donc un lever de soleil vu par le Tux. 
</p>
<!--break-->
<br/>
<p><image id="2"/>L'histoire ne dis pas si le Tux Electrique rêvent d'Androide ou s'il fait simplement là son Salut au Soleil. Quoi qu'il en soit, cela semble lui faire bien plaisir <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/></p>
<p>Le contre-jour ne permet pas de voir que tux a maintenant une petite éraflure sur le crâne. En effet la cohabitation entre Yogi-Tux et Vodka, notre chatte, n'a pas été des plus simple. Cette dernière sentant son territoire envahi par les battements d'ailes a décidé hier de... l'attaquer... </p>
<p style="clear:left"><image  style="border:none" id="1"/>C'est aussi l'occasion de montrer un peu la tête du Manager .2 pour saine critique. Chaque icône du haut est une "tuxlet", composé d'actions et de dialogues. Une action est par défaut lié à l'IHM par un menu déroulant sur click gauche mais peut aussi être associée à un événement horloge (à telle heure, tout les "tant", à chaque heure, demi-heure, etc..), à un événement "touche" (switch du Tux ou télécommande), ou encore, à un point du graph. 
</p>
<p>
Pour l'instant, outre les tuxlets de la version .1, nous avons une horloge fonctionnelle, un lecteur de flux RSS multi-canal avec ses propres settings de langage (la voix tuxifiée étant un peu incompréhensible appliquée à de l'actualité) et enfin la tuxlet "Weather" paramétrable. 
</p>    ]]></content>
  </entry>
  <entry>
    <title>L&#039;art de faire manger des fichiers WAV à TuxDroid </title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1233" />
    <id>http://artisan.karma-lab.net/node/1233</id>
    <published>2007-10-05T04:31:51+02:00</published>
    <updated>2008-02-12T11:36:15+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="TuxDroid" />
    <category term="Aucun" />
    <category term="javafr" />
    <category term="OK" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[<p>Grande bataille de gagnée ce soir... (euh... ce matin en fait, j'va être ben frai moi pour bosser  J'ai enfin réussi à enregistrer des sons dans cette maudite mémoire interne du TuxDroid. Oui je sais, j'occupe certaines de mes nuits étrangement... Mais une fois que je tiens un morceau, j'ai du mal à le lacher...</p>
    ]]></summary>
    <content type="html"><![CDATA[<p>Grande bataille de gagnée ce soir... (euh... ce matin en fait, j'va être ben frai moi pour bosser <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/smile.gif" title="Smiling" alt="Smiling" class="smiley-content"/> J'ai enfin réussi à enregistrer des sons dans cette maudite mémoire interne du TuxDroid. Oui je sais, j'occupe certaines de mes nuits étrangement... Mais une fois que je tiens un morceau, j'ai du mal à le lacher...</p>
<p>Car je ne veux pas critiquer les devs du pingouin mécanique, mais y'a du réellement vaudou là dessous... Je suis pas sur d'avoir bien compris... En fait pour stocker N sons dans le tux, il faut (attention, on s'accroche) :</p>
<ol>
<li>Lire le "sample rate" de chaque fichier audio. Information contenue dans le header du fichier wav (qui est constitué de 44 octets), sur 4 octets, en position 24.</li>
<li>Si le sample rate n'est pas très exactement de 8khz, il faut convertir le sample avec la commande sox source.wav -c 1 -r 8000 -b cible.wav.</li>
<li>Il faut ensuite regarder en position 40, la taille de la "charge utile" codé sur 4 octets. Chose étrange, le chiffre est inférieur à la réalité, c'est à dire tailleFichier-44.</li>
<li>Ensuite il faut merger tous les wav's en un seul. Pour cela, on récupère le header du premier wave, sauf la taille (40 octets donc, faut suivre <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>. On réserver 4 octets (pour la futur taille) et on ajoute à la queue leu-leu tes charges utiles (tout sauf les 44 premiers octets) de chacun des samples.</li>
<li>Et là commence le vaudou, le naïf aurait pu croire qu'il faille insérer la taille avec la somme de toutes les tailles... Oui mais non... En fait il faut insérer tailleDansHeader=sommeTailles+0.07*sommeTailles (au petits malin qui veulent factoriser, je rappelle que l'on est en arithmétique entière <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>. Pourquoi .07 ? aucune idée...</li>
<li>Bref, on insère la valeur ainsi trouvée et on se dit c'est fini. Ben non, car tant que la taille physique du fichier est inférieur à tailleDansHeader-44, on ajoute 12 espaces à la suite des données !!!</li>
<li>C'est pas fini, il faut ensuite réinitialiser la mémoire du tux, pour cela, on s'accroche, il faut d'abord envoyer la commande qui indique au Droid le nombre de sample qui vont arriver.</li>
<li>On attends 10 secondes !!!</li>
<li>On envoi à Tux un premier index en 0x400... Pourquoi, je sais pas, c'est comme si on définissant un premier sample "blanc"</li>
<li>Puis on envoi les N indexes suivant, en incrémentant à chaque fois avant de la taille (la vraie, celle du header d'origine) du sample en prenant bien soin de faire une pause de 100ms entre chaque envois...</li>
<li>Enfin, pour ceux qui se demandaient comment envoyer les données elles-même au Tux, ben c'est tout con, on envoi notre super WAV précédemment fusionné... dans la carte son USB avec un aplay -D hw:0,0 merged.wav...</li>
</ol>
<p>J'avoue que je ne m'attendait pas à un truc aussi délirant.. Je subodore que le coup de 0.07 et du padding avec des espaces à la fin permet au firmware de comprendre qu'il doit arrêter de stocker...<br />
Peu importe, aidé du code python de l'API d'origine et de celui de tuxgi, on y arrive. Mais serieux, c'est pas clair du tout à lire le Python... </p>
<p>En tout cas pour ceux qui veulent savoir comment la même chose peut maintenant être réalisée en Java :</p>
<div class='code-block code-block-fragment'>
<div class='container'>
  WaveFile<span class="br0">&#91;</span><span class="br0">&#93;</span> files <span class="sy0">=</span> <span class="kw1">new</span> WaveFile<span class="br0">&#91;</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
files<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw1">new</span> WaveFile<span class="br0">&#40;</span><span class="st0">&quot;./r2d2wst1.wav&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
files<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw1">new</span> WaveFile<span class="br0">&#40;</span><span class="st0">&quot;./saberon.wav&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
files<span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw1">new</span> WaveFile<span class="br0">&#40;</span><span class="st0">&quot;./hyperdrv.wav&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
files<span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span> <span class="sy0">=</span> <span class="kw1">new</span> WaveFile<span class="br0">&#40;</span><span class="st0">&quot;./beamup.wav&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
tux.<span class="me1">sound</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">store</span><span class="br0">&#40;</span>files<span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
</div>
<p>C'est sur, une fois que le gros est caché dans l'API, c'est plus simple <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/smile.gif" title="Smiling" alt="Smiling" class="smiley-content"/> A noter que l'objet WaveFile converti tout seul les samples au bon format. </p>
<p>Ban ben vala, je suis content, j'ai saoulé tout le monde, je vais me coucher <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/smile.gif" title="Smiling" alt="Smiling" class="smiley-content"/></p>
    ]]></content>
  </entry>
  <entry>
    <title>TuxDroid Java API - Nouveautés de la 0.4</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1267" />
    <id>http://artisan.karma-lab.net/node/1267</id>
    <published>2007-10-04T03:44:45+02:00</published>
    <updated>2008-05-03T20:42:18+02:00</updated>
    <author>
      <name>Anonymous</name>
    </author>
    <category term="TuxDroid" />
    <category term="Aucun" />
    <category term="OK" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p><image id="1"/>
It toke me some time but I hope it worth it. This release now supports all TuxDroid features, even those which are not implemented yet (Sleep, ping, etc). Apart from that, the API now comes with a new TuxManager, a widgets based graphical application. 
</p>
    ]]></summary>
    <content type="html"><![CDATA[<p><image id="1"/>
It toke me some time but I hope it worth it. This release now supports all TuxDroid features, even those which are not implemented yet (Sleep, ping, etc). Apart from that, the API now comes with a new TuxManager, a widgets based graphical application. 
</p>
<!--break-->

	<a name='chapter_1'></a>
  <h2>Core API</h2>
	
<p>This is mainly a reverse ingeneered version of the very clear Python API reworked to fit Java standards.</p>

<ul>
<li>All TuxDroid features (motors, captors, speech, sound, system, etc..) are supported.</li>
<li>Mostly all useful status are accessible by a getXXX() and by events (classical swing system, on event, multiple listeners). To follow the daemon philosophy, getting a status is giving you the value but also generate associated event to listeners.</li>
<li>I rewrote the protocol engine that should be fully thread-safe now, even with re-entrance (getting a status that generate an event that is getting the same status <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/></li>
<li>Lost Connection recognition and automatic reconnection.</li>
<li>Building process is using Maven. There is now a specific maven repository for all libraries so everything can be build from source very easily (just untar & maven compile)</li>
<li>JavaDoc is included with sources. It's covering about 80% of core API.</li>
</ul>


	<a name='chapter_2'></a>
  <h2>TuxManager</h2>
	
<p>A Swing application that can be seen as the merge of Python Gadget Manager and tuxgi</p>
<ul>
<li>Core UI simply contains a Tuxlet selector, a traces output and a status bar for all important states (AC, RF, TTS, Tuxd, etc..)</li>
<li>All other features are wrapped in a plugin (tuxlets) system.</li>
<li>Tuxlet framework is included in the API).</li>
</ul>

	<a name='chapter_3'></a>
  <h2>Tuxlets</h2>
	
<p>For testing purpose, 3 "tuxlets" (gadgets) are included.</p>
<ul>
<li>"Movement Tuxlet" : basically the same as tuxgi first pane.</li>
<li>"Configuration Tuxlet" : speech test and voice selection, sounds test and management, information pane juste showing all Tux components versions.</li>
<li>"Insight Tuxlet" : just a joke to demonstrate light sensor.</li>
</ul>
<p>
More tuxlets will come later. I already wrote RSS reader, Clock and Weather. They just need a proper configuration panel
</p>

<p>
That's it for now. Just to finish a big thank you to Sonny ( http://geekrc1.free.fr ) who kindly accepted to test the beast and found nice bugs <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>
</p>    ]]></content>
  </entry>
  <entry>
    <title>TuxDroid Java API - Documentation</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1225" />
    <id>http://artisan.karma-lab.net/node/1225</id>
    <published>2007-09-21T13:06:54+02:00</published>
    <updated>2007-12-04T02:45:39+01:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="TuxDroid" />
    <category term="Aucun" />
    <category term="javafr" />
    <category term="OK" />
    <category term="Tutoriel" />
    <summary type="html"><![CDATA[
	<a name='chapter_1'></a>
  
	<a name='chapter_1'></a>
  <h2>Object hierarchy</h2>
	
	
<p>
The all API is available through one simple object, <kbd>Tux</kbd>. 
</p>
<p>
First you need to create and connect your Tux object

  <div class='code-block code-block-fragment'>
  <div class='container'>
  Tux tux <span class="sy0">=</span> <span class="kw1">new</span> Tux<span class="br0">&#40;</span><span class="st0">'localhost'</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// if your daemon is on an other machine, change localhost to its name</span><br />
tux.<span class="me1">connect</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>    ]]></summary>
    <content type="html"><![CDATA[
	<a name='chapter_9'></a>
  <h2>Object hierarchy</h2>
	
<p>
The all API is available through one simple object, <kbd>Tux</kbd>. 
</p>
<p>
First you need to create and connect your Tux object

  <div class='code-block code-block-fragment'>
  <div class='container'>
  Tux tux <span class="sy0">=</span> <span class="kw1">new</span> Tux<span class="br0">&#40;</span><span class="st0">'localhost'</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// if your daemon is on an other machine, change localhost to its name</span><br />
tux.<span class="me1">connect</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
API allows you to control your TuxDroid from it's different body parts :
<ul>
  <li><kbd>tux</kbd>. You can control speaking, turning left and right.
<ul>
  <li>
    <kbd>tux.head()</kbd>. You can listen head button on this object.
    <ul>
      <li>
        <kbd>tux.head().eyes()</kbd>. This to control eyes opening/closing and IR emitting. You can also listen Eye movements and IR reception. No motor listening yet.
        <ul>
          <li><kbd>tux.head().eyes().left()</kbd>. This to controls Blue LED. No LED listening yet.</li>
          <li><kbd>tux.head().eyes().left()</kbd>. This to controls Blue LED. No LED listening yet</li>
       </ul>
      </li>
      <li>
        <kbd>tux.head().mouth()</kbd>. You can control mouth movement here, and also listen to mouth events. No motor listening yet.
      </li>
    </ul>
  </li>
  <li>
    <kbd>tux.wings()</kbd>. You can control wings movement here. No motor listening yet implemented.
    <ul>
      <li><kbd>tux.wings().left()</kbd>. Here to listen left wing switch.<.li>
      <li><kbd>tux.wings().right()</kbd>. Here to listen right wing switch.<.li>
    </ul>
  </li>
</ul>
</li>
</ul>
</p>


	<a name='chapter_10'></a>
  <h2>Threading model</h2>
	
<p>
  Every object can have commands and events. Commands allways return a Query object that you can use to block the call or not. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// Blocking call. Eyes will not be opened if wings are not</span><br />
Query query <span class="sy0">=</span> tux.<span class="me1">wings</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">open</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
query.<span class="me1">waitForResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
tux.<span class="me1">eyes</span>.<span class="me1">open</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
<span class="co1">// Non-Blocking call. Eyes and Wings will be open at (nearly) the same time. </span><br />
tux.<span class="me1">wings</span>.<span class="me1">open</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
tux.<span class="me1">eyes</span>.<span class="me1">open</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
  When the API trigger an event, the associated call to the listener methods (we'll see that latter), are in their own thread. So if you push the head button and quickly after the right wing. Both call will occur at the same time, in tow separate threads. 
</p>

	<a name='chapter_11'></a>
  <h2>Movements</h2>
	
<p>
  Basically, all parts that have motors, have methods <kbd>open</kbd>,<kbd>close</kbd>, <kbd>isOpen</kbd>, <kbd>toggle</kbd>. Parameters depends of hardware abilities. For example wings got speed and counter, eyes got counter but no speed. 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// I gonna fly !!</span><br />
tux.<span class="me1">head</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">eyes</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">open</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
tux.<span class="me1">wings</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">toggle</span><span class="br0">&#40;</span><span class="nu0">3</span>,Speed.<span class="me1">veryQuick</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<div class='inline-box note'>
All movements are blocking calls for now. This because you can't use Eyes and Mouth at the same time. This is basically because they both use the same motor. Latter I'll allows wings And (Eyes or Mouth). 
</div>
<div class='inline-box attention'>
Be careful when you close Tux Eyes. As IR receptor is located here, you'll not be able to control Tux with the remote once closed. Or you'll have to be very close to go through. 
</div>
<p>
When you want to move the all tux, you can use Tux object itself

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// let's dance !</span><br />
tux.<span class="me1">turnLeft</span><span class="br0">&#40;</span><span class="nu0">3</span>,Speed.<span class="me1">slow</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
tux.<span class="me1">turnRight</span><span class="br0">&#40;</span><span class="nu0">2</span>,Speed.<span class="me1">quick</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>

	<a name='chapter_12'></a>
  <h2>Lights</h2>
	
<p>
  Lights are only available on Eye object. Methods are simply <kbd>lightOn</kbd> and <kbd>lightOff</kbd>.

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// Lets be a cyclope</span><br />
tux.<span class="me1">eyes</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">left</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">lightOn</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
tux.<span class="me1">eyes</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">left</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">lightOff</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<div class='inline-box note'>
Calling those methods is non-blocking.
</div>
</p>


	<a name='chapter_13'></a>
  <h2>Listening to events</h2>
	
<p>
Listening is basically the same as Swing model with some little calling differences. You always have :
<ul>
<li>An XXXEventListener interface you can implements.</li>
<li>An helper class BasicXXXEventListener that is an empty implementation of the previous interface for quick inheritance. </li>
<li>A XXXEvent object given to every XXXEventListener methods.</li>
<li>A XXXEventListeners object hosted by target body part object, generaly called XXXListeners, to add/remove your listener.</li>
</li>
</p>
<p>
For now there is 3 listeners : ButtonEventListeners that you can add to head, left wing et right wing. ShutterEventListener for eye and mouth. And RemoteControlEventListener for eyes. 

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// I'll dance if you tap on my head</span><br />
tux.<span class="me1">head</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">buttonListeners</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">add</span><span class="br0">&#40;</span><span class="kw1">new</span> BasicButtonEventListener<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="br0">&#123;</span><br />
&nbsp; <span class="kw1">public</span> <span class="kw4">void</span> buttonPressed<span class="br0">&#40;</span>ButtonEvent event<span class="br0">&#41;</span> <span class="kw1">throws</span> TuxException<br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; tux.<span class="me1">wings</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">toggle</span><span class="br0">&#40;</span><span class="nu0">6</span>, Speed.<span class="me1">verySlow</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; tux.<span class="me1">wings</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">toggle</span><span class="br0">&#40;</span><span class="nu0">6</span>, Speed.<span class="me1">veryQuick</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; <span class="br0">&#125;</span><br />
<span class="br0">&#125;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>
<p>
Remote Control use the same concept :

  <div class='code-block code-block-fragment'>
  <div class='container'>
  <span class="co1">// I control my Tux</span><br />
&nbsp; tux.<span class="me1">head</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">eyes</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">remoteControlListeners</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">add</span><span class="br0">&#40;</span><span class="kw1">new</span> BasicRemoteControlEventListener<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="kw1">public</span> <span class="kw4">void</span> remoteButtonPressed<span class="br0">&#40;</span>RemoteControlEvent event<span class="br0">&#41;</span> <span class="kw1">throws</span> TuxException<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span>event.<span class="me1">key</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">case</span> left<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; tux.<span class="me1">turnLeft</span><span class="br0">&#40;</span><span class="nu0">1</span>, Speed.<span class="me1">quick</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">case</span> right<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; tux.<span class="me1">turnRight</span><span class="br0">&#40;</span><span class="nu0">1</span>, Speed.<span class="me1">quick</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; <span class="br0">&#125;</span>
  </div>
  
  </div>
</p>

<H2>Voice</H2>
<p>
  For now it's a basic but working voice implementation. There is no control on voice Yet but you can make Tux speak (with a tiny cute voice <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/> in a blocking or non-blocking way. 
  
  <div class='code-block code-block-fragment'>
  <div class='container'>
  tux.<span class="me1">head</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">mouth</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">open</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// We don't want to wait here </span><br />
tux.<span class="me1">speak</span> <span class="br0">&#40;</span><span class="st0">&quot;Hello world&quot;</span><span class="br0">&#41;</span>.<span class="me1">WaitForResponse</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// We wait tux finish speaking</span><br />
tux.<span class="me1">head</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">mouth</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
  </div>
  
  </div>
</p>


	<a name='chapter_14'></a>
  <h2>That's all folks !</h2>
	
<p>
That's it for now, more will come soon <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/smile.gif" title="Smiling" alt="Smiling" class="smiley-content"/>
</p>    ]]></content>
  </entry>
  <entry>
    <title>Notre TuxDroid est arrivé !</title>
    <link rel="alternate" type="text/html" href="http://artisan.karma-lab.net/node/1213" />
    <id>http://artisan.karma-lab.net/node/1213</id>
    <published>2007-09-15T11:57:31+02:00</published>
    <updated>2008-10-01T02:31:53+02:00</updated>
    <author>
      <name>Ulhume</name>
    </author>
    <category term="TuxDroid" />
    <category term="Aucun" />
    <category term="OK" />
    <category term="Article" />
    <summary type="html"><![CDATA[<p>
  Il y a quelques semaines, je tombais sur <a href='#' title='Avant de mourrir, ce lien pointait sur : http://www.verlindensteve.com/2007/08/24/connaissez-vous-tux-droid/' >la nouvelle d'un nouveau robot</a> concurrent du Nabastak. Ayant eu une expérience frustrante au possible avec le lapin enragé (espèce de machin fermé qui fonctionne via un site externe avec un WIFI non sécurisé, du moins à l'époque), moi et surtout ma moitié (je tiens à dire qu'elle a même insisté !), avons donc décidé d'adopter un <a class='external' target='_blank' href='http://www.kysoh.com/' >TuxDroid</a>. Je viens de le recevoir et le chat n'en revient toujours pas...
</p> 
    ]]></summary>
    <content type="html"><![CDATA[<p>
  Il y a quelques semaines, je tombais sur <a href='#' title='Avant de mourrir, ce lien pointait sur : http://www.verlindensteve.com/2007/08/24/connaissez-vous-tux-droid/' >la nouvelle d'un nouveau robot</a> concurrent du Nabastak. Ayant eu une expérience frustrante au possible avec le lapin enragé (espèce de machin fermé qui fonctionne via un site externe avec un WIFI non sécurisé, du moins à l'époque), moi et surtout ma moitié (je tiens à dire qu'elle a même insisté !), avons donc décidé d'adopter un <a class='external' target='_blank' href='http://www.kysoh.com/' >TuxDroid</a>. Je viens de le recevoir et le chat n'en revient toujours pas...
</p> 
<!--break-->

	<a name='chapter_4'></a>
  <h2>The Tux Anatomy</h2>
	
<image id="1"/>
<p>
  Le Tux est donc une peluche à poil raz, doté d'une bonne bouille bien reconnaissable de pingouin, assis sur son séant comme il se doit. Tux n'arrive pas seul, il est accompagné de Fux, qui est son opérateur Radio en quelque sorte. Un petit poisson qui se branche sur le port USB et se charge de causer par les ondes avec Tux. Voilà donc le décors posé, voyons maintenant ce que Tux sait faire :
</p> 
<style>
  li
  {
  list-style-position:inside;
  }
</style> 
  <ul>
  <li>Il a deux ailes articulées qu'il peut battre.</li>
  <li>Il a deux yeux bleus qui peuvent s'allumer ou s'éteindre assorti de deux paupières qui peuvent s'ouvrir et se fermer.</li>
  <li>Il sait tourner sur lui même dans toutes les direction.</li>
  <li>Il peut aussi claquer du bec et vous parlant, ou juste comme cela, pour le plaisir.</li>
  </ul>
<p>Déjà à ce stade, c'est bien plus que la potiche lapinesque qui ne sais rien faire d'autre que clignoter et bouger ses oreilles. Mais Tux va encore plus loin que cela :
</p>
<ul>
<LI>Il sait quand il faut jour ou quand il fait nuit.</LI>
<LI>Il peut émettre des rayons... infrarouges et en recevoir. Il peut donc allumer votre télé si ça vous chante...</LI>
<li>Bien évidemment, Tux parle, joue de la musique mais sait aussi écouter.</li>
</ul>

<p>
  Bref, une petite bestiole bien plus complète que son concurrent à tout point de vue. Son look ne plaira pas je pense aux amoureux de design épuré à la mode "âge de cristal" mais pour les autres, c'est un régal <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/smile.gif" title="Smiling" alt="Smiling" class="smiley-content"/>
</p>
<p>

	<a name='chapter_5'></a>
  <h2>Mise en route</h2>
	
<image id="2"/>
<p>
Moi qui m'attendait (faute à mon expérience précédente) à gallérer comme un malade pour lui faire faire ses premiers pas à la bestiole, j'ai été plutôt surpris. J'ai simplement branché Tux sur le secteur (pour recharger en même temps), allumé... et il a battu joyeusement des ailes en me disant bonjour.
</p>
<p>
  Ensuite je n'ai plus eu qu'à télécharger le logiciel, lancer le setup (pensez à installer <kbd>ipython</kbd> avant !), et le tout c'est installé (en tant que root) sans soucis, proprement en <kbd>/opt/tuxdroid</kbd>. N'oubliez pas avant de poursuivre, d'installer aussi le pack de langue qui vous correspond. 
</p>
<p>
  Phase suivante, lancement de la commande <kbd>tuxgi</kbd>. C'est la petite interface de contrôle. Elle n'est pas rigoureusement indispensable mais va me permettre de tester le Tux. Les deux démons nécessaires à la prise en charge de Tux (contrôle et voix) sont éteints ainsi que l'indicateur de liaison radio. Logique car Fux n'est pas encore connecté.
  </p>
  <p>
  Je fais donc manger (littéralement <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/> la prise USB au poisson qui d'un coup se met à clignoter, d'abord lentement, en recherche, puis fébrilement pour m'indiquer que Tux est connecté. Sur l'interface, le démon Speech (voix) se lance... mais pas le démon Tux ni radio... Vas, un petit bug. Je lance donc la fautif à la main dans une console <kbd>sudo tuxd -d</kbd>, et c'est bon, tous les indicateurs sont maintenant au vert. 
</p>
<p>
  L'interface de test permet de commander la plus grande partie des composants du Tux. Je peux lui faire cligner les yeux, faire clignoter un oeil, battre des ailes, claquer du bec, tout cela marche à merveille. 
</p>
<div class='inline-box attention'>
Pour des raisons de sécurité, le Tux ne tourne pas s'il est branché au secteur. 
</div>
<p>
Je passe dans l'onglet TTS (parole), je choisis la voix féminine, tape un petit "Bonjour je suis Tux" et presse le bouton <kbd>Play</kbd>. Le bec s'ouvre, et la voix est très distincte. La jeune femme ne sait juste pas bien dire "Tux" mais à part cela, c'est très impressionnant. En revanche, la qualité sonore du haut parleur est un peu moyenne, cela crache un chouilla.</kbd>
</p>
<p>
Pour un premier tour de piste, tout cela marche vraiment très bien. Le seul défaut que je trouve au Tux pour l'instant est que sa mécanique est un tantinet bruyante. Mis à part cela, il répond au doigt et à l'oeil et la synthèse vocale est très bonne. En cours d'adoption donc, reste maintenant à laisser de côté l'interface de contrôle pour regarder les logiciels prêts à l'emploi. 
</p>

	<a name='chapter_6'></a>
  <h2>Les Gadgets</h2>
	
<p>
Les Gadgets sont de petites applications sous la forme d'extensions qui permettent à Tux de prendre vie. Pour les utiliser, il faut lancer l'application <kbd>Tux Gadget Manager</kbd> par la commande <kbd>tuxgdg</kbd>. L'interface est très simple, une icône dans la boite à miniatures pour redémarrer les démons ou quitter le manager, et une fenêtre principale présentant les gadgets installés par défaut : Météo, Horloge et EMail. 
</p>
<p>
Tout peut être contrôlé à la souris mais c'est en réalité là que la télécommande fournit intervient. Il suffit de la pointer sur Tux et d'utiliser les flèches pour passer d'un gadget à l'autre. Tux donnes à voix haute le nom du gadget sélectionné. Un coup sur OK pour exécuter le gadget et Tux vous donne ainsi la Météo (de Bruxel, par défaut <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>, l'heure (de manière étonnamment compréhensible), ou encore vérifie vous emails et vous annonce que vous en avez de nouveau. 
</p>
<div class='inline-box attention'>
Au début j'ai pensé que la télécommande ne fonctionnait pas. En fait, le récepteur infrarouge est logé dans les yeux de Tux. Donc lorsque les paupières sont fermées, ça marche moins bien <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>
</div>
</p>

<p>
  Mais ça c'est pour commencer, il y aura d'autres Gadgets à télécharger sur le <a class='external' target='_blank' href='http://www.tuxisalive.com/downloads' >site de la communauté</a> avec notamment un forum de mordus qui semblent bien s'amuser avec la bestiole.
</p>
<p>
  Car c'est pour nous la grande force de Tux, tout y est ouvert et clairement orienté Linux (utilisateurs de Windows, passez votre chemin, vous n'y avez pas droit <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/winktongue.gif" title="Wink Tongue" alt="Wink Tongue" class="smiley-content"/> Il est ainsi possible de créer ses propres plugins, drivers, et même firmware si leur coeur vous en chante (personnellement, je verrais cela un peu plus tard <img src="http://artisan.karma-lab.net/sites/all/modules/contrib/smileys/packs/crystal/wink2.gif" title="Wink" alt="Wink" class="smiley-content"/>. 
</p>
<H2>La bonne idée de l'audio</H2>
<p>
Lorsque vous branchez Fux sur le port USB, ce n'est pas une mais trois périphériques qui apparaissent : Un émeteur-récepteur Radio, une périphérique HID pour envoyer des ordres et ... une périphérique audio. Ça c'est la bonne idée de base car une fois branché, votre système dispose ainsi d'une carte son supplémentaire. Il est alors possible, après paramétrage, d'utiliser Tux pour jouer à peu près tout et n'importe quoi et ce, avec n'importe quelle application.</p>
<p>
 Personnellement, n'ayant pas de sortie audio sur ma station, j'utilise justement Tux pour cela. </p>
<p>
  Dans le même esprit, l'enregistrement à partir du Tux est elle aussi possible. Rien ne vous empêche donc d'utiliser un logiciel de VOIP pour téléphoner avec Tux !!
</p>

<H2>Spécification technique</H2>
<p>En interne, Tux est animé par un Microcontroleur Atmel AVR RISC équipé de 4Mo de Flash pour recevoir, entre autre, les morceaux audio à jouer. Le microcontroleur est assorti d'un processeur Audio exploitant le haut-parleur interne, le micro intégré, et les deux jacks IN et OUT. Côté capteur nous avons l'infrarouge en réception et en émission, une cellule photoélectrique pour la détection jour/nuit, deux leds pour les yeux et trois interrupteurs poussoirs (ailes et crâne). Le tout alimenté par 4 batteries AAA NiCd de 750mAh intégré et rechargeable via un bloc d'alimentation en 7.5v fournit. 
</p>
<p>
Côté radio, il s'agit d'une puce RF exploitant la bande de fréquences 2.4Ghz (comme le DECT), qui passe correctement à travers les murs et fonctionne selon mes tests, au moins jusqu'à 10m. 
</p>
<H2>Conclusion</H2>
<p>
  Tux est clairement Ludique mais loin d'être inutile car étonnamment bien pensé. Tout marche du premier coup, sans surprise ce qui fût loin d'être le cas du Nabaztag (j'avais eu une version 1). Autre différence de taille avec le Nabaztag, tout se passe entre le PC et le Tux. Rien ne transite par un obscure site web où l'on doit acheter des modules qui font dire Papa-Maman. 
</p> 
<p>
  Côté point améliorable, je diras que l'on préférerait une "vraie" peluche, avec une "vraie" fourrure plutôt que le poil velours. Le son demanderait à être amélioré en qualité et surtout, la mécanique en silence. C'est au fond le seul point que je trouve un peu limite. Mis à part cela, c'est que du bon. 
</p>  
<p>
  Alors si vous êtes un(e) "vrai(e)" Geek(ette) linuxien(ne) (pléonasme ?) qui ne limite pas sa convoitise à un aspirateur USB, le Tux, il vous le faut. Son prix est de 79€ ce qui est peu comparé au lapin neurasthénique, et par son ouverture, son excellente conception, la richesse de ses capteurs, n'aura de limite que votre imagination. 
</p>    ]]></content>
  </entry>
</feed>
