Eclipse


Arduino et après?

Ce titre est un peu raccoleur, surtout que je vais continuer à parler d'Arduino... Le sujet exact ici est plutôt "AVR et après?".

En effet, l'ampleur ou les besoins de certains projets nécessitent d'aborder une solution plus complète que les plateformes Arduino classiques, utilisant des microcontrôleurs AVR 8 bits.

Voici donc comment prendre en main l'Arduino Due, et surtout son microprocesseur ARM 32 bits (ATSAM3X8E), utilisé par exemple dans les smartphones.

Plus de mémoire!

Le point le plus marquant et intéressant de la plateforme est sans doute la quantité de mémoire disponible : 512Ko de Flash (pour le programme) et 96Ko de RAM (pour l'execution et les données).

De plus la vitesse d'exécution de 84Mhz peut apporter un sacré coup de pouce aux projets qui le nécessitent (temps réel...). Enfin, l'utilisation de données sur 32 bits offre une puissance de calcul importante.

Pour une présentation détaillée, je vous laisse lire l'article suivant : [Test] Arduino Due & IDE arduino 1.5.x

Appréhender le nouveau coeur

Un processeur ARM est bien plus complexe que les traditionnels AVR : bus de données, contrôleur avancé d'interruptions, optimisation du code exécuté, timers (watchdog)... Je ne vais pas m'attarder ici sur ce sujet complexe, je vous laisse vous lancer par vous-même en lisant par exemple cette présetation, l'excellent ouvrage "Processeurs arm - architecture et langage d'assemblage" de Jacques Jorda ou le livre "The Definitive Guide to the ARM Cortex-M3, Second Edition" de Joseph Yiu.

Outils de développement

Qui dit nouvelle architecture, dit nouveaux outils... Pour commencer, le compilateur : place à la toolchain ARM-GCC. Maintenue par les développeurs de AVR-GCC, elle permet de faire du bare-metal (oh-yeah!), comprenez du code indépendant de la plateforme. Pour la culture, voici une exlication du nom du compilateur "arm-none-eabi" :

Basically, "arm-none-eabi" means:

- 'arm' we are building for the ARM architecture (ARM, Thumb, Thumb-2, etc).
- 'none' means we are not building for a specific operating system. or 'bare-metal' (...)
- 'eabi' says we're going to use the ARM standard EABI, which describes how binary files (libraries, etc) are stored (the actual file formats), and calling conventions, register usage, etc. This makes libraries from different parties compatible with each other and your code. ABI's and EABI's standardize our compiled code.. (...)

source : http://kunen.org/uC/gnu_tool.html

Qu'en est-il du code lui-même? Là où les plateformes AVR supportent très bien le C++, les processeurs ARM préfèrent nettement le C car ils sont bien plus optimisés pour gérer ce langage. Qui plus est, la plupart des améliorations apportées par le C++ (orienté objet...) ne sont que très peu utilisées dans cet environnement et ne justifient donc pas (pour le moment) son utilisation.

Des librairies et frameworks permettent également de faciliter la prise en main du code : CMSIS, une couche d'abstration de moyen niveau fournie par ARM (donc "vendor-independant"), ou bien Atmel Software Framework, cette fois-ci proposé par le fabricant Atmel dans son environnement de développement, qui apporte notamment une tonne d'exemples et de bonnes pratiques.

Débugger un ARM

La nouvelle gestion de la mémoire du processeur ainsi que les nouvelles possibilités d'observation du code exécuté requièrent forcément de nouveaux outils pour débugger votre programme. Adieu donc notre bel AVR-Dragon vu précédemment. Même s'il est heureusement toujours possible d'utiliser une interface JTAG, il vous faudra investir dans par exemple ce J-Link de Segger :

Pourquoi celui-ci en particulier? En effet, il existe également le SAM-ICE de Atmel. Mais je pense que lorsque vous aurez jeté un oeil aux prix pratiqués, la version Education du JLink fera pencher la balance! Surtout qu'au final les fonctionnalités sont quasi-identiques, l'un n'étant qu'une déclinaison de l'autre...

Pour la commande, je me permets de vous conseiller le site Mouser, très pro et très rapide pour la livraison. Dernier point important, même si l'Arduino Due dispose bien d'une interface JTAG 2x5 broches, elle est de taille réduite! Et les debuggers quant à eux utilisent des interfaces 2x10 broches. Il faudra vous procurer l'adaptateur correspondant : 10-PIN TO 20-PIN JTAG ADAPTER.

Vous voilà bien armés pour démarrer... La suite au prochain épisode! Have fun!

Sources :


Fichier(s) joint(s) :



Logstash et MongoDB en 10 minutes

Lorsqu'il s'agit de mettre en place des outils de gestion de logs applicatifs, Logstash est souvent mis en avant.

Il est souvent proposé en combinaison avec d'autres utilitaires comme ElasticSearch et Kibana, qui, bien que remarquables, posent deux soucis :

  1. l'effet "usine à gaz" : en effet, 3 outils à prendre en main d'un coup et à déployer, cela peut paraître intimidant.
  2. "Quels sont mes besoins ?" : ces outils sont essentiellement destinés à la création/analyse de statistiques extraites des informations loggées.

Dans l'exemple que j'ai choisi ici, la structure des fichiers de logs ne permet pas ce genre d'utilisation : en effet, une ligne de log en elle-même ne comporte que peu d'information (entrée dans un service, appel d'une procédure stockée...). Mais c'est plutôt en ensemble de lignes qui permet de reconstituer un scénario dans l'application : ce que l'utilisateur a fait, par où est passé le code, etc. En somme une analyse contextuelle (verticale) des logs plutôt que du contenu (horizontale).

Nous allons donc voir comment il est tout de même possible d'utiliser Logstash et MongoDB pour créer une application facilitant l'analyse de fichiers de logs volumineux.

Tout d'abord, pourquoi ces outils?

Logstash : il est prévu pour traiter des volumes de données importants, de manière efficace, même pour des fichiers au contenu spécifique grâce à son moteur d'expressions régulières Grok. Sa configuration est également très simple car il embarque des composants tout prêts, comme l'accès aux bases MongoDB.

MongoDB : NoSQL pour une mise en place rapide (schemaless orientée document), sans configuration, gérant également des grands volumes de données (au format JSON, utile pour les applis web).

C'est parti, mise en place!

Logstash

Il se présente sous la forme d'un Jar autonome exécutable et ne nécessite qu'un fichier de configuration. En voici un exemple, l'explication par la suite :

input {
  file {
    type => "serveur"
    path => "C:/log/serveur_*.log"
  }

  file {
    type => "client"
    path => "C:/log/client_*.log"
  }
}

filter {
  grok {
    match => [ "message", "%{DATESTAMP:date} %{LOGLEVEL:level} ?(<context>[a-Z0-9_]*) %{GREEDYDATA:message}" ]
  }
}

output {
  mongodb {
    collection => "collec-%{type}"
    database   => "local"
    uri        => "mongodb://localhost"
  }
}

En détails :

  • Les entrées (input) de type "fichier" :
    • type : une étiquette qui permet de différencier nos sources de fichiers (logs serveur d'un côté et client de l'autre)
    • path : le chemin d'accès, utilisant des wildcards
  • filter : la traitement a effectuer sur les entrées, ici un découpage via une expression régulière Grok
    • %{DATESTAMP:date} : on crée un champ nommé "date" constitué d'un timestamp, quel que soit le format (trop fort!)
    • %{LOGLEVEL:method} : un champ nommé "level" contenant les constantes classique de niveau de log : INFO, ERROR...
    • ?(<context>[a-Z0-9_]*) : un champ nommé "context" basé sur une expression régulière personnalisée
    • %{GREEDYDATA:message} : un champ nommé "message" contenat... tout et n'importe quoi!
  • Les sorties (output) de type "mongodb", avec les infos de connexion basiques. Petite astuce : il est possible de rendre dynamiques les éléments de configuration pour chaque ligne de log traitée.

Il est possible de se faciliter l'écriture de l'expression Grok avec Grok Debugger. Comme vous le voyez, très efficace!

Ces quelques lignes placées dans un fichier "ma-config.conf", Logstash se lance simplement avec :

java -jar logstash-1.3.2-flatjar.jar agent -f ma-config.conf

MongoDB

Là, rien de plus simple (la doc ici) :

  1. Lancer "mongod.exe" pour démarrer la base
  2. Optionnel : lancer "mongo.exe" pour ouvrir la console d'administration
  3. Dans notre exemple, pas besoin de créer une base de données, "local" est déjà créée par défaut.

Et voilà! Vous pouvez d'ores-et-déjà déposer des fichiers dans les répertoires indiqués, Logstash va lancer nos traitements pour fournir les documents correspondant dans notre base...

Comme je vous sens coupé dans votre élan, allons plus loin.

API Java

Bien évidemment, MongoDB vient avec une API Java très simple d'utilisation. Quelques lignes de code déployées par exemple sur un serveur Glassfish exposant des webservices REST via Jersey et vous avez une application web pour consulter et requêter dans vos fichiers de logs!

Petits exemples, avec JQuery datatables et un tableau de bord avec gridster :

Plus loin...

Ils vous est également possible de pousser un peu plus loin ce système en utilisant cette extension de log4j, log4mongo, afin d'écrire vos logs en temps réel dans la base MongoDB depuis votre application!


Fichier(s) joint(s) :



Introduction au NoSQL avec Apache CouchDB

Je vais vous montrer comment prendre en main facilement une base de données NoSQL, grâce à un exemple simple.

Nous allons créer une petite application utilisant Ektorp, une API de mapping par annotations et CouchApp, un utilitaire pour déployer des applications HTML5.

Création des données

Pour commencer, il suffit de créer un simple POJO représentant un objet métier. Comme illustré dans la documentation Ektorp ici, il n'est même pas nécessaire de mapper les attributs à enregistrer. C'est même le contraire, Ektorp part du principe que tous les attributs seront sauvegardés sauf ceux explicitement annotés comme ignorés! Un bon gain de temps...

Ensuite, quelques lignes suffisent pour implémenter les fonctionnalités primaires de CRUD :

Here's how a SofaRepository implemented with the generic repository looks like

public class SofaRepository extends CouchDbRepositorySupport {

    public SofaRepository(CouchDbConnector db) {
        super(Sofa.class, db);
    }

}

This repository will have the following methods "out of the box":

SofaRepository repo = new SofaRepository(db);

repo.add(Sofa s);
repo.contains("doc_id");
Sofa sofa = repo.get("doc_id");
repo.update(Sofa s);
repo.remove(Sofa s);
List repo.getAll();

A ce stade, nous avons déjà de quoi mettre en place une moulinette pour insérer des données. Une fois ceci fait, il est possible de consulter le contenu de la base avec Futon, une interface web fournie par CouchDB, à l'adresse http://localhost:5984/_utils/ :

Initier l'application web

CouchDB propose une interface REST très pratique. Ce qui signifie que n'importe quel outil effectuant des requêtes HTTP peut interroger directement la base, y compris un navigateur et... Ajax!

Seulement, comme certains yeux affûtés l'auront remarqué, CouchDB démarre par défaut sur le port 5984, ce qui rend impossible les accès directs via Ajax, par raison de sécurité. Si vous n'avez pas la main sur le serveur hébergeant la base afin de configurer le mécanisme HTTP "CORS", comme indiqué sur cette page, il vous faudra passer par CouchApp afin de déployer votre application sur le serveur interne de CouchDB (comme c'est le cas de Futon).

Un tutoriel très concis explique comment générer et déployer une application basique :

En réalité, tous le fichiers composant cette application sont des documents au sens NoSQL que CouchDB gère comme tels. Tous les fichiers "statiques" (images, css, js...) sont des "_attachments".

Lister les documents

Imaginons que nos documents possèdent un attribut "date", par lequel nous voulons les filtrer, entre une date de début et une de fin.

Nous allons commencer par créer une vue, qui va nous retourner la liste des documents identifiés par une clé issue de notre champ "date".

Ceci se fait par l'intermédiaire des fonctions view, fonctions Javascript pures appelées pour chaque document, pouvant servir de filtre (le cas échéant). Créons par exemple un fichier "by_date.js" dans le répertoire "/views/by_date/" de notre application. Voici donc un exemple de ce que nous cherchons :

function(doc) {
        if(doc.date) {
                emit(doc.date,doc);
        }
} 

Le résultat de notre fonction est accessible à l'adresse (objets JSON) : GET /[db]/_design/[appName]/_view/by_date/

{
  "total_rows": 2,
  "offset": 0,
  "rows": [
    {
      "key": "2014/01/15 15:52:20",
      "value": {...}
    },

    {
      "key": "2014/01/30 18:04:11",
      "value": {...}
    }

  ]
}

Utiliser JQuery

Maintenant nous pouvons compléter le fichier "index.html" (situé dans "_attachments") afin d'ajouter des fonctionnalités. Mais il faut savoir que CouchDB dispose d'un plugin JQuery pour faciliter les interactions. Par exemple, pour interroger notre vue :

$.couch.db("[db]").view("[appName]/by_date", {
    success: function(data) {
        console.log(data);
    },
    error: function(status) {
        console.log(status);
    }
});

Enfin, pour ajouter simplement des filtres sur les dates, il suffit d'intégrer les mots clés : "[appName]/by_date?startkey=[date1]&endkey=[date2]"

Ainsi, avec REST et HTML5/Javascript, vous voilà équipé pour jouer avec CouchDB! :) Enjoy!

Sources :


Fichier(s) joint(s) :



Arduino : XBee Ethernet data logger

Après plusieurs semaines de galère, j'ai décidé de rassembler ici tous les éléments qui m'ont permis, tant bien que mal, de mettre en place l'installation suivante :

D'un côté, un module XBee transmettant les informations d'un capteur de température (LM35). De l'autre, un second XBee relié à un Seeduino ATMega 2560 (similaire à un Arduino) qui enregistre toutes les mesures reçues sur une carte SD et expose le fichier créé via une connexion Ethernet. Voici le schéma du montage :

Avant d'aller plus loin, il est indispensable de faire un point sur la notion de SPI afin de comprendre le fonctionnement de notre montage.

SPI est un bus de communication basé sur les principes de Maitre et Esclave. Il est composé de 4 canaux. Pour ne pas plagier un très bon cours existant sur le site rocketnumbernine, voici en quelques mots son fonctionnement :

Each end of a SPI connection is acting in one of two roles - Master or Slave. The master is responsible for initiating and controlling the communication.

SPI Master/Slave Connections

The basic mode of operation is very simple: When the master wishes to initiate transfer of data:
  1. It sets the SS (Slave Select - often called CS - chip select) pin low to tell the slave that communication is about to start
  2. The master writes a bit of information onto the MOSI (Master Out Slave In) wire (sets it to 0 or 1) and the slave does the same on the MISO wire (either of these can be omitted if the data transfer is one way)
  3. As the master ticks the clock line SCLK it will read the value of MISO (Master In Slave Out) wire (which the Slave has written) and the slave will read the value of the MOSI wire (whether the data is sampled as the clock rises or falls depends on which mode is in operation)
  4. The process is repeated from (b), transferring a bit of data on each pulse of the clock until all data is transferred

Ce bus SPI est accessible via les broches ICSP (Arduino UNO et Mega 2560) ET les broches 11,12,13 (pour le UNO) ou 50,51,52 (pour le Mega 2560).

Un élément important est le Chip Select : il s'agit de la broche qui permet de choisir le périphérique cible de l'échange. Pour désactiver un périphérique, il faut passer la broche en niveau haut et pour l'activer, en niveau bas. Un seul périphérique ne peut être activé à la fois car les trois broches de communication MOSI, MISO et SCK sont partagées.

Sur l'Arduino UNO (Revision 3), le Mega 2560 (Rev 3) et sur le shield Ethernet (Rev 3), on trouve le CS :

  • sur la broche A4 pour la carte SD
  • sur la broche A10 pour l'Ethernet

C'est grâce à cette correspondance des broches qu'il est possible de simplement empiler les cartes sans avoir à faire de connexions supplémentaires. Il est tout de même possible, si vous ne souhaitez pas empiler les cartes, de relier les broches comme indiqué sur le schéma. Attention cependant, ceci est impossible sur le shield Ethernet car seules les broches CS sont utilisées et reliées directement à l'ICSP. Toutes les autres broches ne servent qu'à transférer les connexions à une éventuelle autre carte supperposée.

Revenons donc à notre projet. La carte Ethernet est apposée sur l'ATMega 2560, le module XBee principal (coordinateur) relié directement au Serial1 : broches RX1 et TX1 (croisées avec les RX/TX du XBee).

Côté logiciel maintenant : l'application doit, au démarrage, aller lire un fichier de configuration sur la carte SD et initialiser une connexion Ethernet. Pour bien démarrer, voici le code de la fonction setup() :

void setup() {
 pinMode(10, OUTPUT);
 pinMode(4, OUTPUT);
 // 
 pinMode(53, OUTPUT);
 digitalWrite(53, HIGH);
 /* disable all slaves */
 // disable Ethernet
 digitalWrite(10, HIGH);
 delay(5);
 // disable SD
 digitalWrite(4, HIGH);
 delay(5);

 /* read config file */
 // init SD
 boolean sd = SD.begin(4);
 delay(5);
 // ... read file ...
 // disable SD
 digitalWrite(4, HIGH);
 delay(5);
}

A noter qu'il est très important de désactiver à la main l'Ethernet après son initialisation car la librairie ne le fait pas! Sur un ATMega 2560, il faut également obligatoirement définir la broche de Hardware SS (53) en sortie.

Ensuite, afin que le programme puisse à la fois recevoir en continu des paquets de données XBee à écrire sur la carte SD et assurer son rôle de serveur web, voici, sous forme algorithmique, le déroulement du code à mettre en place :

void loop() {
 - Vérifier la présence d'un packet XBee
  - si un paquet a été reçu :
   - traiter les informations du paquet 
   - désactiver l'Ethernet : digitalWrite(10, HIGH)
   - activer la carte SD : digitalWrite(4, LOW)
   - écrire sur la carte SD
   - désactiver la carte SD : digitalWrite(4, HIGH)
 - Vérifier la réception d'une requete Ethernet :
  - si une requete a été reçue :
   - désactiver la carte SD : digitalWrite(4, HIGH)
   - activer l'Ethernet : digitalWrite(10, LOW)
   - générer la réponse HTTP
   - fermer la connexion client
   - désactiver l'Ethernet : digitalWrite(10, HIGH)
}

Normalement, la gestion de l'activation/désactivation de chaque périphérique SD ou Ethernet est gérée en interne par les librairies correspondantes, mais je vous conseille de ne pas hésiter à le faire également manuellement afin de renforcer votre programme (on n'est jamais mieux servi que par soi-même!).

Un conseil supplémentaire : il est préférable d'ajouter quelques délais après chaque dés/activation de périphérique (via la méthode delay()), au moins pendant la phase de développement, afin d'éviter tout conflit de communication sur le bus SPI (par les broches partagées) qui pourrait engendrer, par exemple, la destruction de la carte SD (qui arrive plus vite qu'on ne le croit!).

Ci-dessous sont décrites les erreurs les plus communes qui peuvent être rencontrées :

  • Impossible de démarrer la carte SD :
    Si SD.begin() renvoie false, il faut dans un premier temps vérifier les connexions SPI (MOSI, MISO) dans le cas où elles auraient été réalisées autrement que par les broches ICSP et dans un second temps s'assurer que seule sa broche CS est active.
  • Impossible de PING la carte Ethernet :
    Les requêtes ping répondent "Impossible de joindre l'hôte" ("Host unreachable") et la LED TX de la carte ne s'allume jamais : vérifier également que seule la broche CS de la carte Ethernet est active et qu'aucun autre périphérique ne tente d'accéder au bus SPI.

Vous voilà prêts! J'ai essayé de regrouper ici les connaissances de base dont j'ai eu besoin et pour lesquelles j'ai du écumer nombre de blogs et forums. J'espère que tout cela vous sera utile!


Fichier(s) joint(s) :



Analyser une interface Swing

Intervenir sur une application Swing peut vite s'avérer très complexe si celle-ci est basée sur une importante imbrication de composants et layouts personnalisés.

Afin de se faciliter la tâche, il existe Swing Explorer. Disponible sous forme de plugin (Eclipse, Netbeans...) ou autonome, il permet d'explorer l'arbre des composants graphiques au moment de l'exécution de l'application :

Comme vous pouvez le voir, la partie gauche contient les arbres de tous les objets Swing instanciés. Il est alors possible de double-cliquer dessus pour en afficher un aperçu dans la partie droite.

Il est alors possible de sélectionner à la souris chaque composant pour entrer dans leur détail.

C'est donc l'outil idéal pour retrouver n'importe quel composant graphique instancié dans une application, sans avoir à utiliser de point d'arrêt ou modification pas-à-pas.

Il dispose même d'un Player qui permet de rejouer la création et la mise en place des objets telles qu'exécutées par Swing :

Sur ce, bon debug! :)


Fichier(s) joint(s) :