Développement embarqué sur GTA01 et GTA02

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
43
Mois de parution
août 2009
Domaines


Résumé

Avec la sortie du GTA01 et du Freerunner (GTA02) d'OpenMoko, les solutions libres pour embarqué, et particulièrement smartphones, ont franchi un pas de plus. Nous étudierons ici comment développer pour ces systèmes en prenant comme base la distribution SHR (Stable Hybrid Release), basée sur FSO (Freesmartphone.Org) en middleware et OpenEmbedded pour les « recettes » de génération de paquets. Afin d'être exhaustifs, nous étudierons également Hackable:1, basée sur Debian.


Body

1. Contexte

Nous voyons tous les jours, dans nos métiers et dans nos usages, se démocratiser l'utilisation du libre dans nos divers périphériques et logiciels, pour certains d'entre nous avec joie, pour d'autres avec récalcitrance, au vu de la maturité de certaines solutions. Il n'en reste pas moins qu'un fait est patent : au moment où nous voyons de plus en plus des solutions libres pérennes faire leur entrée chez de grands comptes, où des solutions libres font figure de standard de fait, technologiquement plus évoluées ou abouties que leurs concurrents, le milieu de l'embarqué reste encore un petit îlot paisible où il n'est pas aisé de déployer des logiciels libres.

Certes, il y a eu des expériences, par Nokia notamment, ou plus récemment Texas Instruments, mais ces exemples ne sont pas légion. La nécessité, ici, pour le développeur, l'utilisateur et le professionnel qui souhaitent une solution adaptée à son besoin, est de pouvoir avoir accès tant en termes de software que de hardware, au « cœur » de sa machine, afin d'être en mesure de pouvoir remplir son besoin au plus proche.

Cette tentative a partiellement été assurée par OpenMoko (modulo le chipset graphique, dit « Glamo », qui reste sous NDA), qui a donné les spécifications électroniques de son Freerunner, mais qui a également fondé des initiatives communautaires pour le développement d'une base logicielle permettant de profiter du concept de « libre » sur tout le système.

Nous considèrerons particulièrement dans cet article l'exemple de Freesmartphone.Org, qui, lorsque le projet a été lancé début 2008, faisait preuve d'un concept novateur et permet aujourd'hui l'exploitation de toutes les couches « de base » d'un périphérique embarqué. Depuis, de nouveaux challengers, tel qu'oFono, ont fait leur apparition, avec une cible quelque peu différente.

Afin de nous donner une base de réflexion plus simple à comprendre, nous considérerons également la distribution SHR (Stable Hybrid Release), dont un des auteurs de cet article a la joie d'être le « benevolent dictator ». Nous utiliserons donc les « aides » développées pour générer une image de cette distribution, tout en expliquant les commandes de base permettant de générer une image ou un paquet selon la méthode ancestrale.

En dernier lieu, nous considérerons également une alternative, Hackable:1. Elle est développée par Bearstech dans le cadre de son activité hackable:devices. L'objectif est de développer des services innovants dans le domaine de la mobilité tout en mettant à la disposition des développeurs une plate-forme de développement rapide, simple et respectant les standards existants. Elle est basée sur Debian et Gnome mobile. Elle est également pensée pour tourner sur d'autres matériels que le Freerunner. Il s'agit d'une distribution assez jeune, puisque son développement a démarré fin 2008.

Pour toutes les distributions, il est à noter qu'il existe une communauté francophone très active, dont le point de rencontre est sur http://www.openmoko-fr.org.

2. OpenEmbedded

OpenEmbedded est un système englobant un ensemble d'outils et de recettes de génération de paquets, permettant de construire dans un contexte « embarqué » des distributions et images complètes.

2.1 Commencer simplement : le Makefile SHR

Afin de pouvoir mettre en place un environnement complet de travail avec OE (OpenEmbedded), il est nécessaire de configurer un certain nombre d'éléments. Cette configuration est relativement aisée lorsqu'on est habitué à OE et sa logique, mais, pour un débutant, cela peut paraître très obscur : la barrière d'entrée est malheureusement assez haute.

En considérant ce problème, un certain nombre de solutions « packagées » fournissent un ensemble de primitives qui vous simplifieront la vie. Considérons donc ici le Makefile SHR, basé sur le MokoMakefile de Rod Whitby.

$ wget http://build.shr-project.org/Makefile

$ make setup

Cette dernière commande va vous permettre de remettre à jour le Makefile en fonction de la dernière version sur git [SHRGIT], ainsi que de télécharger et installer un arbre complet OpenEmbedded (basé sur la branche spécifique à SHR, shr/import, que vous pouvez trouver en ligne [OEGIT]), ainsi que l'outil bitbake et un ensemble de scripts facilitant l'utilisation de ce dernier. Deux principaux dossiers seront créés : shr-testing et shr-unstable, correspondant aux deux versions majeures actuelles de la distribution. Par la suite, dans cet article, nous considèrerons shr-unstable.

Il nous reste à adapter un peu cette structure de base en modifiant la configuration par défaut. Éditons donc le fichier local.conf se trouvant dans shr-unstable/conf/local.conf, et rajoutons les quelques paramètres suivants :

# Générer les locales française uniquement

GLIBC_GENERATE_LOCALES = "fr_FR.UTF-8"

# Si notre hôte est dual core ou multi processeur,

# cela permettra de compiler plus PARALLEL_MAKE = "-j 4"

rapidement les packages

# Idem

BB_NUMBER_THREADS = "4"

Si nous souhaitons simplement construire une image se basant sur les données et logiciels écrits par l'équipe SHR, nous nous contenterons alors de taper les commandes suivantes, à partir de là où nous avions téléchargé le Makefile :

$ cd shr-unstable

$ make image # Par défaut, image pour GTA02

Bien entendu, il vous faudra vous armer de patience et attendre que toutes les dépendances soient compilées pour une cible qui n'a pas la même architecture processeur que votre hôte, a priori (puisque ici, nous allons compiler pour ARM). À titre informatif, sur un PC « normal », en une nuit, on peut s'en sortir avec une image. Il est également important de considérer l'espace : avec les sources, et une certaine durée de vie, l'ensemble des fichiers de l'environnement de travail occupe 7,6 G sur l'ordinateur de l'auteur.

Éventuellement, pour les possesseurs de GTA01, il est possible de taper la commande suivante pour générer la configuration nécessaire pour une image sur ce dernier:

$ make setup-machine-om-gta01

Dès lors, afin de récupérer les changements commités sur le dépôt git SHR, et mettre à jour son ensemble de sources OE, il suffira de taper la commande suivante à la racine où nous avons téléchargé le Makefile :

$ make update

Dès lors, réitérer make image reconstruira une image à jour et correspondant à la dernière version des sources. Dépendant de votre architecture cible pour l'image, vous trouverez par défaut un fichier jffs2 et tgz, ainsi qu'un kernel, dans shr-unstable/tmp/deploy/glibc/images/. Il vous suffira dès lors de flasher ou installer l'image et le kernel selon la méthode traditionnelle (expliquée plus bas).

Accessoirement, si vous souhaitez compiler l'ensemble du « feed » SHR, c'est-à-dire l'ensemble des paquets compilés sur le serveur hébergeant SHR, vous pouvez également utiliser les commandes suivantes :

$ make distro # Compile la tâche task-shr-feed

$ make index # Remet à jour l'index des paquets

Une fois que l'index est mis à jour, vous pouvez exporter votre « feed », disponible dans tmp/deploy/glibc/ipk, et l'utiliser comme un dépôt de paquet pour votre périphérique. Le plus simple est de le rendre accessible par HTTP, et de le rajouter aux sources de packages d'opkg.

2.2 Bitbake

bitbake est un outil assez similaire à portage (de Gentoo) et permettant de construire des packages et images à partir de recettes .bb. Il dispose d'un certain nombre de commandes vous permettant de manipuler complètement les recettes OE. Le Makefile, décrit précédemment, englobe ces commandes, mais ne vous permet pas d'avoir autant de granularité que l'outil standard. Les auteurs vous enjoignent à regarder le Makefile afin de pouvoir constater l'ensemble des possibilités, et de comparer avec bitbake.

Prenons l'exemple précédent, et considérons que nous souhaitons à présent construire une image avec bitbake. Dès lors, nous taperons les commandes suivantes, de la racine du Makefile :

$ cd shr-unstable

$ . setup-env

$ bitbake shr-image # shr-image est le nom de la recette bb générant l'image

Ceci permet de charger l'environnement précédemment défini par le Makefile (les variables d'environnement permettant de situer où bitbake doit trouver ses recettes bb, mais aussi où se trouvent les dossiers avec les binaires compilés pour ARM, etc.), puis de générer une image en prenant en compte toutes les dépendances.

Supposons que nous souhaitions à présent compiler un paquet spécifique qui n'est pas disponible dans l'image, par exemple dictator. Dans ce cas, nous taperons la commande suivante :

$ bitbake dictator

Une fois cette commande terminée, vous trouverez le paquet dans tmp/deploy/glibc/ipk/ARCH/, où ARCH correspond à l'ARCH générique ou spécifique selon votre paquet. Dans le cas de dictator, nous trouverons donc cela dans tmp/deploy/glibc/ipk/armv4t, correspondant à l'architecture générique pour périphériques à processeur armv4t.

Attention, n'oubliez pas qu'il est nécessaire avant d'utiliser bitbake d'être sûr d'avoir au moins effectué une fois la commande. setup-env, afin de définir les chemins nécessaires.

Supposons maintenant que nous souhaitions éviter de « reparser » à chaque fois l'ensemble des recettes, voire que nous nous fichions des dépendances d'un paquet, sachant qu'elles sont déjà là. Dans ce cas, nous utiliserons le paramètre -b de bitbake, qui nous permet de cibler une recette spécifique.

$ bitbake -b openembedded/recipes/dictator/dictator_0.2.bb

Cette commande effectuera l'ensemble de la procédure permettant de construire le paquet, à la condition où celui-ci ne l'a pas déjà été, c'est-à-dire, si les stamps que l'on peut trouver dans tmp/stamps/ARCH n'existent pas pour le paquet donné. Dans le cas contraire, bitbake reprendra où il s'était arrêté.

De fait, on peut donc demander à forcer ces actions (-f) ou, par exemple, à exécuter une action particulière. Il existe un ensemble fini d'actions, mais on peut écrire des procédures spécifiques dans les recettes bb permettant des les étendre. Parmi ces actions, on citera fetch, unpack, patch, configure, « compile », install, qui revêtent pour nous un intérêt particulier dans l'utilisation de bitbake. Si donc, je souhaite forcer la réexécution de la procédure de configure de dictator, j'aurais à effectuer la commande suivante :

$ bitbake -b openembedded/recipes/dictator/dictator_0.2.bb -f -c configure

Enfin, comme de bien nombreux programmes, bitbake vous fournit des éléments de debug, lorsque vous concevez des recettes bb. Il apparaît nécessaire de préciser que les options -v (verbose), -D (debug) sont indispensables lorsque vous vous posez des questions métaphysiques sur la raison qui fait que votre recette ne veut pas se packager, mais également -e, qui affichera l'environnement complet d'exécution de bitbake, et donc tous les PATH, INCLUDE, et autres : on n'est jamais à l'abri d'une mauvaise configuration et régulièrement des erreurs apparaissent dans certaines recettes. Il n'est donc pas inutile de contrôler.

Il n'est pas inutile non plus de préciser que la commande -c devshell appliquée à une recette vous lancera un terminal avec toutes les variables d'environnement nécessaires à pouvoir faire vos changements directement dans le répertoire de travail de bitbake : vous pourrez donc éditer les sources, et taper make comme vous le feriez normalement.

2.3 Recettes « bb »

Afin de nous « sensibiliser » à la création d'une recette bitbake, nous allons ensemble essayer de créer une recette pour le paquet d'une application « Hello World », que nous appellerons helloworld-shr.

L'ensemble des sources développées pour cet exemple se trouve sur le site de SHR : http://build.shr-project.org/tutorial

2.3.1 En-tête d'une recette

Considérons d'abord la structure d'une recette bb. Comme dans toutes les distributions, nous avons, au départ, des informations de qualification de la recette :

#Description du paquet, telle qu'apparaissant

# dans les recherches avec opkg

DESCRIPTION = "Hello World from SHR"

SECTION = "utils" # La section du paquet

LICENSE = "GPL" # La licence du paquet

PR="r0" # La révision du paquet

Il existe d'autres variables, telles que PN (nom du paquet), PV (version du paquet), qui sont initialisées d'après le nom du fichier : si ma recette bb s'appelle helloworld-shr_0.1.bb, alors PN = helloworld-shr, et PV = 0.1. Au final, ces variables seront utilisées afin de qualifier si l'on doit ou non mettre à jour un paquet (si PV-PR est supérieur à l'ancien PV-PR).

Dans le cas de paquets récupérant des sources directement depuis un serveur de contrôle de version, il est nécessaire d'utiliser des conventions de nommage différentes. Par exemple, si, ici, helloworld-shr était directement téléchargé depuis git, la recette bb s'appellerait alors helloworld-shr_git.bb, et j'aurais à définir PV directement dans ma recette, comme suit :

PV = "0.1+gitr${SRCREV}"

Ici, ${SRCREV} est une variable qui permet de retourner la révision au sens contrôle de version : dans le cas de git, ce sera le hash du commit (précédé de son numéro afin de garder un ordre lexicographique permettant de mettre à jour).

Deux autres variables sont indispensables dans la description d'une recette bb : ses dépendances. Il en existe deux types, les dépendances à l'exécution, et à la compilation. Considérons un programme qui ait besoin de eet à la compilation, et de e-wm et ophonekitd à l'exécution, on écrira comme suit :

DEPENDS += « eet »

RDEPENDS += « e-wm ophonekitd »

Notez qu'on utilise la notation +=, car selon les dépendances rajoutées, on peut avoir des compléments de dépendances à la compilation issus des dépendances à l'exécution, et vice-versa. Les noms inscrits ici en dépendance sont des noms de paquets pour lesquels il existe des recettes bb.

Ensuite, logiquement, nous allons indiquer où récupérer les fichiers à compiler.

SRC_URI = « http://build.shr-project.org/tutorial/${PN}-${PV}.tar.gz »

Ici, nous utilisons ${PN} comme une partie du nom, c'est-à-dire helloworld-shr. Cette notation fait partie des recommandations sur OE. Dans le cas où nous considèrerons un gestionnaire de versions, cela pourrait ressembler à ceci :

SRC_URI = "git://git.shr-project.org/repo/ophonekitd.git;protocol=http;branch=master »

Ici, on indique le chemin d'un dépôt git, et on indique que l'on récupèrera le source de la branche master via le protocole HTTP. bitbake se chargera de lui-même d'initialiser le dépôt local, de prendre les sources, et de les compresser.

Il est également possible d'indiquer plusieurs sources, ce qui revêt une grande utilité dans le cadre de patchs. Si, dans le cadre de mon exemple précédent, je souhaite modifier les sources de mon « Hello world » afin de pouvoir, que sais-je, dire « Goodbye », je peux réaliser un patch sur les sources, le mettre à disposition dans mon arbre OE, et l'indiquer dans les sources :

SRC_URI = « http://build.shr-project.org/tutorial/${PN}-${PV}.tar.gz \

file://hello2goodbye.patch;patch=1»

Dès lors, cela signifie que le fichier hello2goodbye.patch doit se trouver dans un dossier correspondant au nom de la recette bb, au même niveau que celle-ci, c'est-à-dire l'arborescence suivante :

-rw-r--r-- 1 ainu wheel 206 juin 20 14:50 helloworld-shr_0.1.bb

helloworld-shr:

-rw-r--r-- 1 ainu wheel 0 juin 21 15:15 hello2goodbye.patch

Le fichier, indiqué dans les sources, sera utilisé en tant que patch (patch=1), avec un PNUM de 1 (le PNUM étant le paramètre donné à patch -pPNUM), et appliqué après la phase de copie des fichiers sources.

Il est à noter que nous pouvons également faire référence à des fichiers (sans préciser patch=1), et que ces fichiers seront copiés dans le dossier de travail. Cela peut-être utile dans certains cas, où les sources ne fournissent pas un fichier de configuration par défaut, par exemple.

Enfin, nous aurons également besoin de dire à bitbake où se trouve la racine de travail des sources téléchargés. Dans notre cas, c'est-à-dire depuis le fichier fourni en http, nous savons que celui-ci contient un dossier helloworld-shr-0.1 où se trouvent toutes les sources. Nous écrirons donc cela dans la recette :

S = ${WORKDIR}/${PN}-${PV}

Il est à noter que S change entre les différents gestionnaire de versions ou selon les sources téléchargés. Par exemple, dans le cas classique d'un paquet utilisant les autotools, S aura la forme précitée. Pour un paquet que l'on récupèrera depuis git, cela ressemblera plutôt à ce qui suit :

S = ${WORKDIR}/git/${PN}

2.3.2 Simulation d'une compilation manuelle

Nous avons à présent des en-têtes correspondant à ce que nous souhaitons empaqueter, que nous avons écrit dans une nouvelle recette dans openembedded/recipes/linuxmag/helloworld-shr_0.1.bb. Il nous reste donc à réaliser les opérations de compilation, d'installation et d'empaquetage.

Nous avons précédemment décrit les différentes « phases » d'une recette. Par convention, chaque phase possède une méthode do_ suivi du nom de la phase : do_compile, do_install...

Donc, en premier lieu, nous souhaitons compiler notre fichier source helloworld.c. À la main, nous effectuerons la commande suivante :

$ gcc helloworld.c -o helloworld

Sachant que bitbake nous fournit une variable ${CC} correspondant au compilateur de la cible pour laquelle nous compilons, nous écrirons donc la méthode suivante :

do_compile() {

${CC} helloworld.c -o helloworld

}

Constatons ici que le chemin dans lequel nous nous trouvons à l'exécution de la procédure correspond au chemin que nous avions indiqué dans le paramètre S. Rajoutons-donc cette méthode à la suite, dans notre recette, et essayons de compiler celle-ci, en tapant la commande suivante :

$ bitbake -b openembedded/recipes/linuxmag/helloworld-shr_0.1.bb

Nous constatons, si l'option OE_ALLOW_INSECURE_DOWNLOADS n'est pas activée dans votre configuration locale (celle-ci étant activée dans la configuration SHR par défaut, vous pourrez donc tester sans si vous le souhaitez ;-)), que la compilation échoue avec le message d'erreur suivant (au pouillème près) :

NOTE: Running task 1 of 19 (ID: 1, /home/ainu/shr/shr-unstable/openembedded/recipes/linuxmag/helloworld_0.1.bb, do_setscene)

NOTE: package helloworld-shr-0.1: started

NOTE: package helloworld-shr-0.1-r0: task do_setscene: started

NOTE: Checking if staging package installed

NOTE: No. Manually removing any installed files

NOTE: package helloworld-shr-0.1-r0: task do_setscene: completed

NOTE: package helloworld-shr-0.1: completed

NOTE: Running task 2 of 19 (ID: 2, /home/ainu/shr/shr-unstable/openembedded/recipes/linuxmag/helloworld_0.1.bb, do_fetch)

NOTE: package helloworld-shr-0.1: started

NOTE: package helloworld-shr-0.1-r0: task do_fetch: started

ERROR: helloworld-shr-0.1: http://build.shr-project.org/tutorial/helloworld-shr-0.1.tar.gz has no entry in conf/checksums.ini, not checking URI

En effet, il est nécessaire de certifier que les sources sont bien identiques à celles pour lesquelles le paquet a été créé. Suite à cette erreur, vous trouverez dans tmp/checksums.ini les lignes correspondant aux checksums des sources que bitbake vient de télécharger. Il vous suffit de les copier, de les insérer dans openembedded/conf/checksums.ini, afin de pouvoir fonctionner avec des téléchargements « sécurisés ».

Une fois cette étape faite, relançons notre commande, qui devrait se terminer correctement, et regardons ce que bitbake a généré comme paquets :

$ ls -al tmp/deploy/glibc/ipk/armv4t/helloworld-*

-rw-r--r-- 1 ainu wheel 684 juin 20 13:41 tmp/deploy/glibc/ipk/armv4t/helloworld-shr-dbg_0.1-r0_armv4t.ipk

-rw-r--r-- 1 ainu wheel 662 juin 20 13:41 tmp/deploy/glibc/ipk/armv4t/helloworld-shr-dev_0.1-r0_armv4t.ipk

Nous constatons qu'il n'y a que des paquets debug et développement. En effet, nous n'avons aucunement installé notre binaire, non plus que précisé qu'il faisait partie du paquet standard !

Tout d'abord, gérons donc l'installation, comme nous le ferions à la main :

do_install() {

install -d ${D}${bindir}

install -m 755 helloworld ${D}${bindir}

}

Nous créons ici le dossier cible où se trouvent les binaires, dans notre dossier d'installation temporaire. En effet, bitbake possède un dossier d'installation dit « bac à sable » où tout ce qui doit être installé doit se trouver avant la phase d'empaquetage, c'est notre ${D}. Dans ce dossier, nous créons le chemin vers le dossier des binaires (/usr/bin, par défaut, ici appelé ${bindir}). Ensuite, nous y installons le binaire que nous avons généré. Constatons ici que le chemin dans lequel nous nous trouvons à l'exécution de la procédure correspond au chemin que nous avions indiqué dans le paramètre S. Il existe également d'autres variables disponibles, pour les chemins, telles que ${sysconfdir} pour /etc, ${libdir} pour /usr/lib, et je vous ramène à la documentation de bitbake pour les moins indispensables !

Enfin, indiquons que ce binaire fait partie des fichiers délivrés par le paquet « standard ».

FILES_${PN} += " ${bindir}/helloworld"

Cette directive nous assure que dans les fichiers du paquet « standard », à différencier d'avec le paquet -dbg ou -dev, ce qui se trouve dans ${bindir}/helloworld est livré.

Nous venons de changer la définition de notre recette, afin de pouvoir la corriger. Étant donné que celle-ci a déjà été compilée, nous allons devoir soit la recompiler (-c rebuild), soit forcer une montée en version. Choisissons cette dernière solution, et montons la révision du paquet (ceci faisant encore une fois partie des bonnes pratiques OE) :

PR = « r1 »

Dès lors, nous obtenons la recette suivante :

DESCRIPTION = "Hello World from SHR"

SECTION = "utils"

LICENSE = "GPL"

PR="r1"

SRC_URI = "http://build.shr-project.org/tutorial/${PN}-${PV}.tar.gz"

S = ${WORKDIR}/${PN}-${PV}

FILES_${PN} += " ${bindir}/helloworld"

do_compile() {

${CC} helloworld.c -o helloworld

}

do_install() {

install -d ${D}${bindir}

install -m 755 helloworld ${D}${bindir}

}

Si nous tentons d'empaqueter helloworld-shr, nous obtiendrons dans tmp/deploy/glibc/ipk/armv4t un paquet correspondant, qui sera installable sur votre périphérique, et délivrera un exécutable helloworld, compilé pour ARM. Félicitations, vous venez de réaliser votre première recette bb !

2.3.3 Utilisation des autotools

Bien entendu, il serait fastidieux de réaliser systématiquement les compilations « à la main », ou selon la méthode ancestrale. Vous constaterez que les fichiers sources de helloworld-shr contiennent les éléments nécessaires pour pouvoir utiliser les autotools.

Utiliser ces derniers sous bitbake, il n'y a rien de plus simple : ce dernier permet d'hériter d'un système de « classes », dont une, spécifique, appelée « autotools ».

Il nous suffit donc d'écrire :

inherit autotools

Dès lors, les procédures de configuration, compilation et installation seront gérées par bitbake et les autotools. Notre recette (dans laquelle nous n'oublierons pas de changer PR), ressemblera dès lors à ceci :

DESCRIPTION = "Hello World from SHR"

SECTION = "utils"

LICENSE = "GPL"

PR="r2"

SRC_URI = "http://build.shr-project.org/tutorial/${PN}-${PV}.tar.gz"

S = ${WORKDIR}/${PN}-${PV}

inherit autotools

Beaucoup plus simple, non ? Notez qu'il n'est plus utile de préciser quels sont les fichiers délivrés, les autotools permettent de faire cette opération.

2.3.4 Staging des headers par les autotools

Dans le cadre de bibliothèques, par exemple, nous pouvons avoir envie de « stager » des headers permettant à des programmes incluant ces headers d'être compilés sur notre hôte (et donc de faire référence au dossier d'inclusion de notre hôte où se trouvent les headers). De fait, il serait fastidieux d'installer ces headers « à la main ».

De la même façon que pour les autotools standards, il existe une classe permettant donc d'effectuer ce « staging », c'est-à-dire la copie de ces headers dans l'environnement « simulé » pour l'hôte, et contenant le compilateur, les headers, etc.

Afin de mieux comprendre ce qu'est le « staging », considérez l'exemple suivant : je développe une bibliothèque, par exemple libframeworkd-phonegui, qui fournit des headers que des bibliothèques doivent implémenter afin d'être conforme à un standard défini. De fait, ces headers doivent être présents dans l'environnement de cross-compilation utilisé avec bitbake. Le fait de « stager » ces headers consiste à les rendre disponibles de cette manière. Il en va de même des bibliothèques, de la libc, etc.

Pour ce faire, il nous suffit de faire hériter notre recette de autotools_stage.

inherit autotools_stage

Attention : autotools_stage est une addition à autotools, il n'effectue que le staging. Afin de stager, et d'utiliser les autotools normalement, il faudra donc préciser les deux :

inherit autotools_stage autotools

2.4 Tâches et images

Il existe deux éléments spécifiques dans le cadre de la constitution d'une image générée par bitbake grâce aux recettes bb d'OE : les tâches et les images.

Les tâches permettent de constituer un ensemble cohérent de paquets, potentiellement dépendant de l'architecture cible, qui feront donc l'agrégation d'un certain nombre de logiciels, et dont l'installation permettra, en une seule fois, d'installer cet ensemble.

Par exemple, la tâche standard task-boot est une tâche qui permet d'installer tout ce qui est nécessaire à booter sur un périphérique, sysvinit par exemple.

Vous pouvez à cet effet regarder les tâches task-shr et task-shr-minimal qui se trouvent dans openembedded/recipes/tasks/.

Une tâche est constituée de la même façon qu'un paquet, à la différence près qu'elle ne fait que dépendre sur d'autres paquets, et n'a pas de directive spécifique de configuration ou compilation. Elle se trouve dans recipes/tasks et hérite de la classe task.

Dans le cadre de l'image, le principe est identique : il existe une classe image dont hérite la recette, et celle-ci se trouve dans recipes/images. Une phase importante est cependant rajoutée, c'est-à-dire la phase de constitution du rootfs. Durant cette phase, les paquets dont dépend l'image sont installés, et des opérations complémentaires peuvent être effectuées.

À cet effet, le principe reste le même que ce que vous avez pu observer dans la constitution d'un paquet bitbake standard, et observer certains exemples vous permettra de comprendre l'ensemble des tâches nécessaires à la constitution d'une image (dont on pourra néanmoins citer task-boot et task-base).

2.5 Versioning

Nous avons eu l'occasion de parler de paquets issus directement depuis des gestionnaires de contrôle de versions. Il va de soi que ces paquets nécessitent une attention particulière, puisqu'on ne voudra pas forcément récupérer la toute dernière version systématiquement. Pour ce faire, OE et bitbake proposent deux éléments à considérer, PREFERRED_VERSION et SRCREV.

En effet, admettons que je dispose de plusieurs versions d'un même paquet, et que, pour des raisons qui me sont propres, je souhaite utiliser une version spécifique, et non la dernière (qui sera utilisée par défaut). Dans ce cas, il me faut définir dans un fichier de configuration quelle version je souhaite utiliser.

Prenons pour exemple les fichiers inclus par SHR : dans openembedded/conf/distro/include/shr-autorev.inc, nous pouvons trouver les lignes suivantes :

PREFERRED_VERSION_shared-mime-info = "0.51"

PREFERRED_VERSION_navit = "0.1.0+svnrev${SRCREV}"

Ces deux lignes illustrent ce qu'il faut faire lorsque l'on souhaite choisir une version spécifique d'un paquet. La première nous permettra de choisir, selon la version du package (PV), la version 0.51 de shared-mime-info. A contrario, la deuxième nous permettra de choisir la version SVN de navit (en effet, lorsqu'on regarde la PV de navit, celle-ci correspond bien à ce que nous pouvons voir indiqué ici).

Attention : par défaut, les versions issues d'un gestionnaire de versions sont prioritaires ! Aussi, il faut les « désactiver » si on ne souhaite pas les utiliser par défaut, au moyen de la directive suivante dans leur recette bb :

DEFAULT_PREFERENCE= « -1 » 

Par la suite, afin de ne pas récupérer n'importe quelle version depuis le gestionnaire de versions, il nous faudra (impérativement) préciser quel commit utiliser. Voici quelques exemples que l'on peut trouver dans le fichier mentionné précédemment :

SRCREV_pn-navit = "2309"

SRCREV_pn-e-wm-config-illume-shr = "${AUTOREV}"

SRCREV_pn-libframeworkd-glib = "9765f6989d09d8f9b8676e1ef7e2501fe67fbdbc"

La première directive nous assure que pour navit, qui utilise Subversion, nous récupérerons les sources au commit 2309. La troisième directive est typique d'un git. Nous irons jusqu'au commit de hash 9765f6989d09d8f9b8676e1ef7e2501fe67fbdbc. La deuxième ligne, quant à elle, est spéciale, et permet de dire que nous utiliserons systématiquement la dernière version disponible.

Attention, il n'existe pas de SRCREV par défaut : si vous ne la définissez pas, vous obtiendrez des erreurs lors de la récupération des sources...

Dès lors, l'utilisation de ${SRCREV} dans la variable PV de vos recettes retournera un champ calculé permettant de pouvoir assurer que chaque « mise à jour » vous donnera un nom de paquet supérieur dans l'ordre lexicographique.

2.6 Providers

Il arrive que plusieurs paquets fournissent le même service. C'est le cas, par exemple, de openembedded/recipes/gpsd/gpsd_2.37.bb et openembedded/recipes/freesmartphone/fso-gpsd_git.bb. C'est d'ailleurs reconnaissable dans ce dernier à la ligne :

RPROVIDES_${PN} = "gpsd"

Cette ligne signifie que le paquet fso-gpsd fournit l'équivalent de gpsd à l'exécution.

De fait, afin de choisir parmi ces multiples fournisseurs, il est nécessaire de dire explicitement lequel sera intégré, comme l'on peut voir dans l'exemple suivant, visible dans openembedded/conf/distro/shr.conf :

PREFERRED_PROVIDER_gpsd = "fso-gpsd"

Ici, cette ligne nous permet d'assurer que lorsque bitbake enregistre gpsd en tant que dépendance d'un paquet, ce sera en fait fso-gpsd qui sera considéré.

2.7 Overrides

Il existe dans OE/bitbake un mécanisme appelé « Override », qui permet de définir des options spécifiques selon le paquet, le matériel, ou encore selon un mot-clé défini par la distribution. Par exemple, SHR définit le mot-clé shr dans ses overrides, comme vu dans openembedded/conf/distro/shr.conf :

OVERRIDES = "local:${MACHINE}:shr:angstrom:${TARGET_OS}:${TARGET_ARCH}:build-${BUILD_OS}:fail-fast:pn-${PN}"

On constatera par exemple que ce mot-clé est utilisé dans la recette de e-wm, dans openembedded/recipes/e17/e-wm_svn.bb :

SRC_URI_append_shr = " file://illume-disable-screensaver.patch;patch=1 "

Autrement dit, lorsque le mot-clé shr fait partie des OVERRIDES, un fichier additionnel sera présent au niveau des sources (en l'occurrence, un patch). Selon la configuration locale de votre environnement, donc, vous aurez (ou non) ce patch. Ceci permet de rendre un paquet « spécifique » selon la situation : la machine, la distribution... le tout sans affecter tout le monde ! Ici, pour SHR, le patch désactive le mode économiseur d'écran d'illume, le gestionnaire de fenêtres. Cette option était indésirable pour SHR, mais potentiellement utile pour d'autres.

Cette logique est identique pour le matériel (on utilisera les mots-clés correspondant au nom de la machine, om-gta02 par exemple), tel que visible dans la recette de génération de l'image SHR (openembedded/recipes/images/shr-image.inc) :

ROOTFS_POSTPROCESS_COMMAND_append_om-gta02 = ";shr_rootfs_gta02_postprocess"

Cette directive ajoute une procédure lors de la génération du rootfs (l'image) d'un GTA02.

Ces « overrides » peuvent être ciblés, comme ici, ou génériques, comme on peut le voir dans la recette d'e-wm, encore, dans openembedded/recipes/e17/e-wm_svn.bb :

do_install_append() {

#Do some stuff

}

Ici, la phase d'installation générée par bitbake sera étendue par cette procédure. Il existe à cet effet append et prepend, qui permettent respectivement de suffixer ou de préfixer une procédure.

2.8 Testez votre paquet

Il existe plusieurs solutions pour tester votre paquet. La plus simple est bien entendu de le copier via scp sur votre périphérique.

Vous pouvez également construire un feed de votre arbre de paquets, et l'exposer via HTTP, afin de pouvoir le rajouter dans les sources d'opkg.

Enfin, il est également possible d'émuler un périphérique, via Qemu. Les instructions afin de faire fonctionner ce dernier étant relativement complexes, nous vous conseillons de vous référer à http://wiki.openmoko.org/wiki/Qemu afin d'obtenir l'ensemble des instructions nécessaires.

3. FSO (Freesmartphone.Org)

3.1 Introduction

Depuis quelques années, l'importance des ordinateurs tournant sous GNU/Linux est devenue de plus en plus apparente, particulièrement dans le monde des périphériques embarqués, PDA, téléphones, Tablet PC et netbooks. Les bénéfices d'une architecture kernel efficace, et d'une abstraction matérielle permettent un portage relativement « simple » vers de nouveaux périphériques (dans l'intérêt des professionnels faisant commerce de telles choses), et donc de les supporter en un temps très court pour les mettre sur le marché avec peu d'investissement. Des périphériques tels que le Motorola série EZX, l'Openmoko Freerunner, les Nokia N8x0, les HTC G1/G2, et le très récemment présenté Palm Pre montrent le succès que peut apporter Linux en tant que système d'exploitation sur des périphériques embarqués, et encouragent à l'adoption de systèmes d'exploitation libres pour de telles applications.

Autant cela peut avoir un sens pour le kernel, autant la situation est complètement différente en ce qui concerne l’userland, c'est-à-dire les logiciels tournant au-dessus du kernel, les applications en contact direct avec l'utilisateur. Dans ce domaine, le libre a donné cours à des douzaines de solutions mutuellement incompatibles, et parfois à moitié finies.

Lorsqu'on regarde outre l'apparent bénéfice de la « liberté de choix », qui est un des facteurs majeurs ayant amené à cette situation, on rencontre des problèmes presque insurmontables, tant pour les utilisateurs que pour les développeurs:

- Pour chaque produit, les développeurs applicatifs ont à supporter une énorme quantité de bibliothèques disparates, de langages de programmation spécifiques, et de nouvelles abstractions. Supporter plus d'une plate-forme embarquée sous GNU/Linux est complexe, consommateur en temps et coûteux.

- De la même façon, les utilisateurs finaux devront apprendre comment opère chaque programme depuis le début pour chaque nouvelle plate-forme. Réutiliser des « métaphores » éprouvées et fonctionnelles est presque impossible.

L'initiative Freesmartphone.Org est une approche pour défragmenter l'espace « mobile », améliorer l'intéroceptivité des plateformes embarquées basées sur GNU/Linux actuelles et futures. Elle consiste en un middleware qui se base sur Dbus en tant que standard de communication inter-processus. Les personnes derrière freesmartphone.org se considèrent eux-mêmes comme un complément du très réussi projet « freedesktop.org » [FDO], qui se base lui-même sur Dbus, afin de supporter l'interopérabilité au niveau du monde du PC de bureau, par exemple entre GNOME et KDE.

Freesmartphone.org offre donc un framework basé sur Dbus, de services matériels abstraits pour les développeurs, tels que du « power management », de la téléphonie GSM, de la configuration réseau, gestion du temps, de la position géographique, des profils, etc. Utiliser ce framework simplifie énormément le développement d'applications pour les périphériques embarqués. Il supporte une architecture applicative « propre » (c'est-à-dire une séparation de la représentation et de la logique métier), et encourage les développeurs à se concentrer sur des applications innovantes ou des interfaces utilisateurs, plutôt que d'avoir à traiter les problèmes issus des spécificités des périphériques ou des technologies sous-jacentes (de nombreux modems GSM, par exemple, ont des commandes spécifiques...)

Ainsi, des solutions comme openBmap [OBM], un programme permettant d'enregistrer les positions GPS de la couverture du réseau GSM, dans le but à terme d'obtenir sa position géographique à partir de l'identité de la cellule GSM à laquelle le téléphone est actuellement connecté, peuvent faire usage de différentes ressources, sans se soucier de la façon « réelle » par laquelle ils doivent interagir avec le matériel : ces programmes s'enregistrent au niveau du framework, et communiquent avec lui de la même façon quel que soit le périphérique sous-jacent. Le programme est donc automatiquement portable sur différents matériels !

3.2 Architecture

 

fso-architecture

 

Fig. 1 : Diagramme d'architecture de freesmartphone.org

Bien que l'initiative freesmartphone.org ne fournisse qu'un middleware, il est important de noter comment celui-ci interagit avec les autres composants. Le diagramme de référence de l'architecture du framework montre une architecture quatre-tiers, séparée selon les couches suivantes :

3.2.1 Couche applicative

Cette couche communique avec la couche middleware seulement via Dbus. Ceci permet un grand niveau de liberté pour la couche applicative, puisque cela implique qu'il n'existe aucune contrainte de langage ou de toolkit graphique.

3.2.2 Couche middleware

La couche middleware contient l'ensemble des services freesmartphone.org. Le middleware est composé de sous-systèmes distincts, séparés en deux niveaux d'abstraction. Les sous-systèmes communiquent tant au niveau horizontal que vertical via Dbus : ceci est une fonctionnalité importante puisqu'elle permet de multiples niveaux de granularité en termes de serveur/processus.

3.2.3 Couche de services de bas niveau

Cette couche de services de bas niveau contient les solutions existantes pour manipuler des choses telles que la configuration réseau, le bluetooth, l'audio, etc. Certains, parmi ces services, offrent également des primitives Dbus.

3.2.4 Couche kernel

La couche kernel contient les pilotes matériels, et fournit un accès bas niveau via sysfs, procfs, ioctls et des interfaces similaires.

3.3 Sous-systèmes middleware « bas-niveau »

Les sous-systèmes middleware sont séparés en service de haut niveau (en bleu) et de bas niveau (en rouge). Considérons d'abord les services de bas niveau :

3.3.1 Périphérique (device)

Ce service a pour charge le contrôle des périphériques, tels que l'audio, la luminosité de l'écran, les LED, le vibreur, les accéléromètres, mais également le power control pour les périphériques sans démon dédié. Il s'occupe aussi des notifications de charge et de la RTC. Sur certains systèmes, il fait également suivre les évènements de boutons, et notifie au sujet de l'état d'inactivité du système.

3.3.2 GSM

Le service de bas niveau GSM s'attend à disposer d'un modem compatible avec le standard GSM 07.07, GSM 07.05 et les spécifications GSM afférentes, parlant un protocole AT par un lien série. Si GSM 07.10 est supporté, un démon de multiplexage est utilisé afin d'exporter les différents liens séries virtuels capables de communiquer via AT.

3.3.3 GPS

Le service de bas-niveau GPS s'attend à un périphérique GPS communiquant via NMEA ou UBLOX UBX4 par un nœud « device ». Un service auxiliaire fonctionnant séparément implémente la compatibilité avec le démon gpsd.

3.4 Sous-systèmes middleware « haut-niveau »

3.4.1 Usage

Le sous-système « Usage » s'occupe de coordonner les pré-requis entrée/sortie des applications (pensez notamment au comptage de référence pour les ressources). Les applications ne sont pas supposées « allumer » ou « éteindre » les périphériques, puisqu'elles n'ont aucune connaissance des logiciels concurrents qui pourraient également utiliser le périphérique en question. Il s'occupe aussi des fonctions de « suspend » et « resume » haut niveau, notamment car préparer un modem GSM à se suspendre ne peut pas sainement être fait en espace kernel, puisque l'on a besoin d'envoyer plusieurs commandes AT afin de prévenir des mauvais « wakeup » . Ces commandes sont spécifiques aux périphériques et à la situation, et doivent donc être gérées au niveau de l'espace utilisateur.

3.4.2 Téléphone (phone)

Le sous-système « phone » peut-être utilisé pour créer et manipuler des communications type « voix » sur de nombreux protocoles. Il se connecte également au bluetooth, afin de faciliter l'accès au contrôle des oreillettes.

3.4.3 PIM

Le sous-système PIM offre un moyen d'enregistrer et de requêter les données personnelles de l'utilisateur : contacts, messages, tâches...

3.4.4 Réseau (networking)

L'API de « networking » (réseau) fournit des méthodes de haut niveau pour la configuration réseau des périphériques disponibles (WiFi, USB...).

3.4.5 Évènements (events)

Le service d'évènements gère des règles qui connectent des évènements (tels qu'un appel entrant, l'insertion du chargeur, etc.), via des filtres (par exemple selon le profil choisi, silencieux ou vibreur), à d'autres évènements (comme jouer la sonnerie). Dépendant des règles, le service d'évènements peut faire appel à d'autres sous-systèmes.

Notez que le service d'évènements n'est là qu'en tant qu'« aide », des applications complètes pouvant elles-mêmes gérer ce genre de choses.

3.4.6 Preferences

Le sous-système « preferences » contient l'ensemble des préférences utilisateurs : les différents types de profils, et leur sonnerie associée, etc.

3.4.7 Temps (time)

Le sous-système « time » agrège différentes sources afin de pouvoir manipuler et mettre à jour la « timezone » et l'heure correctement. Il contient également un service d'alarme que vous pouvez utiliser.

3.5 Interfaces applicatives

3.5.1 Dbus

Un des paradigmes majeurs de freesmartphone.org (FSO) est l'homogénéité des interfaces : FSO supporte des interfaces Dbus cohérentes destinées aux développeurs d'applications. Ceci est dû à la compréhension du fait que les développeurs d'applications doivent se concentrer sur la logique métier plutôt que tenter de visualiser les problèmes que peuvent causer une multitude de bibliothèques ou des interfaces de communication entre les processus, disponibles dans le monde du libre. L'homogénéité et la cohérence sont des paradigmes importants, et c'est pourquoi l'architecture n'offre qu'un et un seul moyen d'interagir avec le middleware.

Bien que cela puisse paraître comme la « réinvention de la roue », c'est un point important pour l'adoption d'un middleware : souvent, des sous-systèmes réutilisent en fait des roues existantes, mais en couvrent les détails peu ragoûtant derrière des interfaces Dbus.

Dbus est une technologie très flexible de communication entre processus client/serveur : il supporte des interfaces orientées tant au niveau procédurales qu'objets, des invocations synchrones ou asynchrones, tout autant que de la communication point à point ou point à multipoint.

Puisque la popularité de Dbus augmente sans cesse, des solutions tierces basées sur Dbus, telles que bluez4 [BLUEZ], connman [CONN], wpa-supplicant [WPAS], peuvent souvent être utilisées par le framework directement, et, si nécessaire, être améliorées par des appels de plus haut niveau afin de pouvoir supporter les problématiques transversales.

3.5.2 Comment comprendre les interfaces ?

Afin de communiquer avec un sous-système de FSO via son interface Dbus, il est nécessaire de connaître trois choses :

- Nom du bus : Le nom du bus identifie le processus au niveau du serveur auquel les « invocations » Dbus seront délivrées. Dépendant de l'implémentation, de multiples sous-systèmes peuvent être dans le même processus ou être répartis sur plusieurs. Dans tous les cas, un sous-système freesmartphone.org possède un nom unique de la forme org.freesmartphone.subsystem, où subsystem est, à la rédaction de cet article, un parmi les suivants : odeviced, ousaged, ogsmd, ogpsd, oeventsd, otimed, onetworkd, opreferencesd, opimd.

- Chemin de l'objet : Le chemin de l'objet identifie quel objet au niveau serveur recevra les invocations Dbus. De multiples objets peuvent être implémentés sur un seul chemin au niveau du serveur. Les chemins d'objets doivent être formatés comme des chemins de fichier, avec / en tant que séparateur. Chaque objet Dbus freesmartphone.org possède le préfixe /org/freesmartphone/. La liste suivante montre l'ensemble des objets exportés par le sous-système org.freesmartphone.odeviced. Notez que les objets sont dynamiques : dépendant du cas d'utilisation et de la disponibilité du matériel et des composants logiciels, les objets peuvent apparaître et disparaître à tout moment durant le cycle de vie du sous-système.

/

/org

/org/freesmartphone

/org/freesmartphone/Device

/org/freesmartphone/Device/Audio

/org/freesmartphone/Device/CPU

/org/freesmartphone/Device/Display

/org/freesmartphone/Device/Display/0

/org/freesmartphone/Device/Display/gta02_bl

/org/freesmartphone/Device/IdleNotifier

/org/freesmartphone/Device/IdleNotifier/0

/org/freesmartphone/Device/Info

/org/freesmartphone/Device/Input

/org/freesmartphone/Device/LED

/org/freesmartphone/Device/LED/gta02_aux_red

/org/freesmartphone/Device/LED/gta02_power_blue

/org/freesmartphone/Device/LED/gta02_power_orange

/org/freesmartphone/Device/LED/neo1973_vibrator

/org/freesmartphone/Device/PowerControl

/org/freesmartphone/Device/PowerControl/Bluetogta02_aux_redoth

/org/freesmartphone/Device/PowerControl/UsbHost

/org/freesmartphone/Device/PowerControl/WiFi

/org/freesmartphone/Device/PowerSupply

/org/freesmartphone/Device/PowerSupply/ac

/org/freesmartphone/Device/PowerSupply/adapter

/org/freesmartphone/Device/PowerSupply/apm

/org/freesmartphone/Device/PowerSupply/battery

/org/freesmartphone/Device/PowerSupply/usb

/org/freesmartphone/Device/RealTimeClock

/org/freesmartphone/Device/RealTimeClock/0

/org/freesmartphone/Device/RealTimeClock/rtc0

- Nom de l'interface : Les interfaces regroupent des invocations de méthodes Dbus en catégories. Une interface Dbus définit les signatures des méthodes et signaux disponibles : c'est le contrat d'API entre un client et un serveur Dbus. De multiples interfaces peuvent être implémentées par un objet. Chaque interface freesmartphone.org a le préfixe org.freesmartphone. La liste suivante présente les interfaces exposées par l'objet Dbus /org/freesmartphone/Device/LED/0, fourni par org.freesmartphone.odeviced.

[METHOD] org.freedesktop.DBus.Introspectable.Introspect()

[METHOD] org.freesmartphone.Device.LED.BlinkSeconds( i:seconds, i:delay_on, i:delay_off )

[METHOD] org.freesmartphone.Device.LED.GetName()

[METHOD] org.freesmartphone.Device.LED.SetBlinking( i:delay_on, i:delay_off )

[METHOD] org.freesmartphone.Device.LED.SetBrightness( i:brightness )

[METHOD] org.freesmartphone.Device.LED.SetNetworking( s:interface, s:mode )

3.5.3 Comment utiliser les interfaces ?

En tant qu'exemple d'utilisation des services Dbus freesmartphone.org, nous allons montrer la séquence d'initialisation « typique » de la téléphonie GSM, où nous nous enregistrons auprès du sous-système, puis du réseau GSM, et enfin, émettons un appel. Avant de commencer, veuillez noter les choses suivantes :

- Les exemples de code suivant utilisent les primitives Dbus disponibles dans le langage Python [PYTH], qui offre une manière très simple et aisée d'utiliser Dbus via un interpréteur de commandes interactif. Les concepts s'appliquent bien entendu à tous les autres langages supportant Dbus, bien que la quantité de code nécessaire puisse varier du tout au tout.

- L'exemple fourni se servira de Dbus de manière synchrone. Bien que la méthode asynchrone soit presque toujours à préférer (puisque le client local restera actif et pourra faire autre chose en attendant la réponse du serveur Dbus distant), les appels synchrones sont plus simples à visualiser et à mettre en place.

- Nous ne montrerons que la gestion d'erreur applicative la plus basique. En travaillant avec Dbus, vous devez être prêt à gérer le fait que les objets peuvent apparaître ou disparaître à tout moment, ce qui signifie bien entendu que chaque appel peut échouer. Des applications robustes prendront ceci en considération.

Bien entendu, il sera également supposé que vous disposez d'un périphérique embarqué de type GTA02, avec le framework installé. Veuillez vous référer à la procédure d'installation de SHR afin d'en disposer un prêt à l'emploi.

La première étape est d'importer le module de support Dbus où toutes les déclarations et définitions nécessaires se trouvent. Connectons-nous donc à notre GTA02, et effectuons la commande suivante :

$ python

Python 2.6.2 (r262:71600, Apr 23 2009, 11:37:56)

[GCC 4.3.3] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import dbus

>>>

L'étape suivante est de récupérer un identifiant vers un bus Dbus, où se trouvent les objets qui nous intéressent. Dbus supporte deux types de bus par défaut : un bus système (pour des services au niveau système, qui démarrent avec celui-ci), et un bus de session (par utilisateur, qui démarre avec chaque session X11). Les sous-systèmes freesmartphone.org se trouvent sur le bus système, similaires en cela à beaucoup d'autres services d'abstraction matérielle.

>>> bus = dbus.SystemBus()

>>>

Comme avec de nombreux autres systèmes client/serveur, avant de pouvoir communiquer avec un serveur distant, vous devez récupérer un identifiant local qui agira en tant que « proxy » du service distant. Ici, vous avez besoin du triplet susnommé : nom du bus, chemin de l'objet, et signature de l'interface. Une séquence typique d'initialisation GSM doit appeler des méthodes localisées sur l'objet GSM, mais appartenant à des interfaces différentes. Aussi, nous allons créer des proxies pour tous au préalable :

>>> oproxy = bus.get_object('org.freesmartphone.ogsmd', '/org/freesmartphone/GSM/Device')

>>> gsmdevice = dbus.Interface(oproxy, 'org.freesmartphone.GSM.Device')

>>> gsmsim = dbus.Interface(oproxy, 'org.freesmartphone.GSM.SIM')

>>> gsmnet = dbus.Interface(oproxy, 'org.freesmartphone.GSM.Network')

>>> gsmcall = dbus.Interface(oproxy, 'org.freesmartphone.GSM.Call')

Une fois que nous disposons de ces proxies d'interface, nous sommes prêts à appeler des méthodes sur ces objets. Afin d'être capable d'écouter des signaux Dbus, vous avez besoin d'un mainloop, ce qui est plus complexe. Dans le cadre de cet exemple « simple », nous ne montrerons que les appels de méthodes.

La procédure pour initialiser la téléphonie GSM ressemble « en gros » à :

- Allumer l'antenne. Si nécessaire, envoyer le code PIN.

- S'enregistrer avec le fournisseur de téléphonie.

Allumer l'antenne peut-être fait grâce à org.freesmartphone.GSM.SetAntennaPower(bool). Cette méthode ainsi que toutes les autres peuvent être trouvées dans la documentation de référence de freesmartphone.org [FSODOCS]. Selon la documentation pour cet appel, nous pouvons obtenir une erreur potentielle org.freesmartphone.GSM.SIM.AuthFailed, dans quel cas nous aurons à envoyer le code PIN avant de pouvoir aller plus loin.

try:

gsmdevice.SetAntennaPower(true)

except DBus.DBusException( e ):

if e.get_dbus_name() == 'org.freesmartphone.GSM.SIM.AuthFailed':

gsmsim.SendAuthCode( '1234' )

else:

print 'Unknown Error'

Si cet extrait de code (que vous pouvez directement écrire dans l'interpréteur Python) marche correctement, alors nous sommes prêts pour nous enregistrer avec le fournisseur de téléphonie.

>>> gsmnet.Register()

Veuillez noter que s'enregistrer auprès d'un réseau GSM peut prendre quelque temps. Ne soyez donc pas surpris si cet appel bloque pendant 30 secondes ou plus. Pour vérifier que nous sommes bien enregistrés auprès du réseau que nous souhaitons, nous pouvons, par exemple, afficher le nom du fournisseur de téléphonie auquel nous sommes connectés. Celui-ci s'obtient via une structure qui est envoyée en tant que résultat de la méthode org.freesmartphone.GSM.Network.GetStatus() :

>>> print gsmnet.GetStatus()

dbus.Dictionary({dbus.String(u'code'): dbus.String(u'20810', variant_level=1), dbus.String(u'cid'): dbus.String(u'72CD', variant_level=1), dbus.String(u'act'): dbus.String(u'GSM', variant_level=1), dbus.String(u'provider'): dbus.String(u'F SFR', variant_level=1), dbus.String(u'lac'): dbus.String(u'5529', variant_level=1), dbus.String(u'strength'): dbus.Int32(72, variant_level=1), dbus.String(u'mode'): dbus.String(u'automatic', variant_level=1), dbus.String(u'registration'): dbus.String(u'home', variant_level=1)}, signature=dbus.Signature('sv'))

Si tout marche comme prévu, le résultat devrait donc être similaire à celui affiché ci-dessus (veuillez consulter la documentation freesmartphone.org afin de connaître la signification de chaque champ). Nous constatons bien que le champ provider a pour valeur F SFR, ce qui était attendu.

Enfin, puisque nous sommes enregistrés auprès du réseau GSM, nous pouvons maintenant essayer d'appeler quelqu'un. Ceci peut être effectué via org.freesmartphone.GSM.Call.Initiate(string,string), le premier paramètre étant le numéro à appeler, et le deuxième étant le type d'appel.

>>> gsmcall.Initiate('123', 'voice')

3.6 Étendre le framework

Les développeurs de freesmartphone.org ont tout récemment commencé à travailler sur la seconde implémentation de référence : FSO 2.0 (iso fonctionnelle avec la version 1). Pour un grand nombre de raisons, qui n'ont que peu d'intérêt pour cet article, la première implémentation avait été faite en Python, qui impose des limitations dues à la haute consommation processeur, et à la signature mémoire de la machine virtuelle. La prochaine version est en train d'être implémentée avec le langage Vala [VALA], un langage de haut niveau aux multiples possibilités, qui se compile en C ANSI, et s'intègre extrêmement bien avec des bibliothèques supportant des API C.

Dans cette section, nous allons montrer un exemple bref permettant de créer un sous-système freesmartphone.org et un module se conformant à FSO 2.0. La plupart du travail à effectuer sera couvert par la bibliothèque libfsoframework, qui contient les parties suivantes :

- un « logger » avec de multiples destinations possibles ;

- l'accès à des fichiers de configuration ;

- un gestionnaire de modules, qui gère le cycle de vie de ces modules ;

- une abstraction de sous-système qui enregistre les modules auprès de Dbus ;

- des classes permettant la gestion des travaux asynchrone ;

- le support des classes de communication Kobject et Netlink ;

- de nombreuses fonctions de type « helper ».

3.6.1 Programme principal

Le programme principal de fsoexampled :

GLib.MainLoop mainloop;

FsoFramework.Logger logger;

public static int main( string[] args )

{

logger = FsoFramework.createLogger( "fsoexample" );

logger.info( "fsoexample starting up..." );

var subsystem = new FsoFramework.DBusSubsystem( "fsoexample");

subsystem.registerPlugins();

uint count = subsystem.loadPlugins();

logger.info( "loaded %u plugins".printf( count ) );

mainloop = new GLib.MainLoop( null, false );

mainloop.run();

return 0;

}

Après la création d'un logger au niveau processus, il s'enregistre lui-même en tant que nouveau sous-système Dbus appelé fsoexample. L'abstraction de sous-système utilisera ce nom afin de chercher les valeurs de configuration se trouvant dans /etc/frameworkd.conf pour les modules définis.

Pour enregistrer un module au sous-système, vous devez donc rajouter une section (vide) à ce fichier.

# Subsystem configuration for fsoexample:

[fsoexample]

# Example plugin

[fsoexample.example]

Après avoir compilé ce programme, et l'avoir linké avec libfsoframework, le framework cherchera votre module example dans le chemin canonique : ${prefix}/lib/cornucopia/modules/<subsystem>/<plugin>.so

3.6.2 Code du module

Le sous-système appellera une fonction spécifique de votre module appelée fso_factory_function(). C'est le lieu idoine pour créer vos objets Dbus ou pour faire une initialisation du module. Ici, nous allons juste créer un objet HelloWorld. Notez que la fonction factory a comme paramètre le sous-système que vous avez créé précédemment. Sauvegardez ce paramètre quelque part, afin de pouvoir l'utiliser pour enregistrer des objets Dbus.

internal FsoExample.HelloWorld instance;

public static string fso_factory_function( FsoFramework.Subsystem subsystem ) throws Error

{

instance = FsoExample.HelloWorld( subsystem );

return 'fsoexample.example';

}

3.6.3 Interface Dbus du module

Notre objet HelloWorld doit exposer une méthode HelloWorld() qui retournera une chaîne. Pour ceci, nous allons créer la classe d'interface Dbus suivante :

[DBus (name = 'org.freesmartphone.Example') ]

public interface ExampleInterface

{

public abstract string HelloWorld();

}

3.6.4 Implémentation du module Dbus

L'implémentation du module ressemble donc à la classe suivante :

class HelloWorld : public ExampleInterface

{

private FsoFramework.Subsystem subsystem;

public HelloWorld( FsoFramework.Subsystem subsystem )

{

this.subsystem = subsystem;

subsystem.registerServiceName( 'org.freesmartphone.fsoexampled' );

subsystem.registerServiceObject( 'org.freesmartphone.fsoexampled', '/org/freesmartphone/Example/HelloWorld', this );

}

public string HelloWorld()

{

return 'Hello World from the Example Plugin!';

}

}

Le constructeur contient deux appels importants utilisant le paramètre subsystem fournit par la fonction factory (voir plus haut) :

- registerServiceName() est une méthode de sous-système qui enregistre un service Dbus sous un nom donné. Cette méthode peut-être utilisée plusieurs fois, tant que cela est fait depuis le même processus, puisque les noms de bus ne peuvent pas être partagés entre plusieurs processus.

- registerServiceObject() est une méthode de sous-système qui enregistre un objet Dbus donné sous un chemin donné.

Enfin, nous implémentons la méthode HelloWorld susnommée, méthode qui sera accessible en tant que org.freesmartphone.ExampleInterface.HelloWorld().

Le résultat de tout cela est que, lorsque vous lancerez le processus fsoexampled, et que ce module sera chargé, un service Dbus sera présent sur org.freesmartphone.fsoexampled, et fournira notre objet HelloWorld sur le chemin /org/freesmartphone/Example/HelloWorld.

4. SHR (Stable hybrid release)

 

shr

 

Fig. 2 : L'interface standard de SHR

4.1 Installer SHR

Deux images sont disponibles : la version « lite », et la version normale, cette dernière contenant plus de logiciels que la première. Veuillez vous référer au site de SHR afin d'obtenir des informations complémentaires sur le contenu [SHR]. Afin de l'installer, il vous faudra donc télécharger l'image et son kernel sur http://build.shr-project.org.

Pour un développeur, le choix se porte tout naturellement sur unstable. Téléchargeons donc l'image et son kernel (il sera supposé que le développeur souhaite installer une « lite » sur un GTA02) :

$ wget http://build.shr-project.org/shr-unstable/images/om-gta02/uImage-om-gta02-latest.bin

$ wget http://build.shr-project.org/shr-unstable/images/om-gta02/shr-lite-image-om-gta02.jffs2

Il nous reste ensuite à flasher ces deux fichiers sur notre périphérique, via dfu-util (disponible dans toutes les bonnes crémeries ou gestionnaires de paquets).

La procédure afin de mettre votre périphérique dans un état permettant de le flasher est la suivante :

- Appuyez sur [AUX] et restez appuyé.

- Appuyez sur [POWER] jusqu'à ce que le périphérique démarre

- Connectez-le à votre ordinateur, et tapez les commandes suivantes sur ce dernier :

$ dfu-util -a kernel -R -D uImage-om-gta02-latest.bin

$ dfu-util -a rootfs -R -D shr-lite-image-om-gta02.jffs2

Il ne vous reste plus qu'à redémarrer votre périphérique, et à profiter de la distribution !

4.2 Architecture

 

shr-architecture

 

Fig. 3 : Diagramme d'architecture de SHR

Suite à de nouvelles discussions sur la liste de diffusion de développement de SHR, voici le schéma d'architecture générale adoptée récemment.

Dans ce schéma, nous constatons qu'Ophonekitd, en noir, est un démon central, qui va être le point d'accès global pour tous les appels de l'interface utilisateur : ce démon écoute les évènements du framework FSO via les bibliothèques en orange (qui permettent de simplifier l'interfaçage avec Dbus en C ou Vala), et va les redistribuer vers l'interface utilisateur correspondante.

Un ensemble fonctionnel de « primitives interfaces utilisateur » a ainsi été défini, délimitant en contextes fonctionnels les différentes parties de ce que les développeurs SHR jugent une « interface utilisateur standard » pour un smartphone. On citera, par exemple, le contexte « Dialer », le contexte « Contact », « Message », etc. Ces différents contextes fonctionnels sont définis par des spécifications Dbus, à partir desquelles des headers C et Vala seront produits, permettant d'implémenter directement des bibliothèques satisfaisant aux contraintes des spécifications.

Considérons un exemple : si l'évènement d'un appel entrant est émis par le framework, Ophonekitd aura pour charge d'instancier l'écran utilisateur correspondant, en choisissant la bonne « bibliothèque » dans laquelle se trouve cet écran. Cet écran continuera son cycle de vie par lui-même, et aura pour charge d'émettre des appels vers le framework pour les tâches de plus « bas » niveau qu'il souhaitera accomplir : passer un appel, lister les contacts, etc. Il pourra néanmoins faire appel aux services Dbus exposés par Ophonekitd, afin d'interagir avec les autres écrans : par exemple, l'écran pour passer un appel pourra comporter un bouton pour afficher la liste de contacts, qui ne fera qu'appeler (via Dbus) l'écran de sélection de contacts.

Cette architecture permet ainsi d'offrir un niveau de modularité supplémentaire à l'utilisateur : il n'a pas besoin de choisir une « suite » correspondant à une bibliothèque gérant toutes les parties de la téléphonie. S'il préfère la bibliothèque A pour les contacts, il peut préférer la bibliothèque B pour les messages, et le but de cet architecture est typiquement de répondre à ce besoin. Cela permet donc, par corrélation, d'avoir des interfaces utilisant des toolkits différents, voire d'instancier dynamiquement en fonction du contexte une bibliothèque spécifique (par exemple, si je n'ai plus de batterie, je souhaiterai limiter mes ressources CPU, et donc j'utiliserai une bibliothèque « graphique » ncurses pour afficher mes appels, parce que ncurses, c'est bien !).

Enfin, cela permet aussi de limiter les constructions d'écrans en les « préchargeant », afin non seulement de limiter les ressources consommées (qui sont malheureusement rares), mais également de rendre l'affichage des écrans plus rapide.

4.3 Travailler sur un paquet « SHR » localement

SHR fournit de base, dans la configuration, un fichier appelé local-builds.inc que vous pouvez trouver dans shr-unstable/conf, par exemple, si vous suivez les instructions de la première partie.

Si vous souhaitez être capable de « cloner » les dépôts de sources SHR, et être capable de les modifier localement dans votre copie du dépôt git, alors il vous faudra vous servir de ce fichier. La première chose à faire est de l'inclure dans votre conf/local.conf :

$ echo "require local-builds.inc" >> shr-unstable/conf/local.conf 

Ensuite, il vous faut définir sur quel paquet vous souhaitez travailler. L'exemple par défaut concerne libframeworkd-phonegui-efl, qui est l'interface utilisateur de téléphonie délivrée par défaut. Supposons que nous souhaitions travailler dessus, nous aurons juste à changer les paramètres suivants :

SRC_URI_pn-libframeworkd-phonegui-efl = "file:///path/to/source/shr"

SRCREV_pn-libframeworkd-phonegui-efl = "LOCAL"

S_pn-libframeworkd-phonegui-efl = "${WORKDIR}/shr/${PN}"

Ici, SRC_URI_pn-libframeworkd-phonegui-efl indique le chemin complet vers la copie locale du dépôt de sources dans lequel se trouve sur le git original les sources de libframeworkd-phonegui-efl. Ce dossier sera entièrement copié pour la phase « fetch » par bitbake et, donc, l'endroit où se trouvent les sources dans le répertoire de travail de bitbake doit être également modifié (troisième ligne). Enfin, comme on ne considère plus le gestionnaire de versions, mais des fichiers locaux, il faut changer la SRCREV, afin que bitbake ne plante plus au calcul de celle-ci, ne pouvant pas en trouver en local. C'est ce que fait la deuxième ligne.

Lorsque vous compilerez ce package, donc, le nom des paquets générés contiendra LOCAL au lieu du nom normal de révision.

Si vous souhaitez travailler sur d'autres logiciels, il vous suffit de répéter cette procédure en changeant les chemins, et noms, en fonction du logiciel sur lequel vous souhaitez travailler. Il ne vous reste plus qu'à vous y mettre, bonne chance !

5. Hackable:1

5.1 Pourquoi Debian ?

L'utilisation de Debian a été privilégiée pour les raisons suivantes :

- 18000 paquets disponibles ;

- 1500 développeurs ;

- strict au niveau des licences ;

- qualité des paquets.

5.2 Pourquoi Gnome mobile ?

Gnome mobile est une spécification qui décrit les composants privilégiés de Gnome pour les plateformes mobiles. Hackable:1 adhère à cette spécification pour les raisons suivantes :

- framework mature ;

- beaucoup de développeurs sont disponibles ;

- documentation assez riche et de bonne facture ;

- support du i18n (y compris le bidi).

5.3 Installation et lancement

5.3.1 Préparation de la micro SD

Actuellement, Hackable:1 est fournie sous la forme d'images pré-installées qu'il suffit de décompresser sur une carte micro SD. Il est évidemment nécessaire de posséder :

- un Openmoko Freerunner ;

- un ordinateur avec un lecteur de carte micro SD ;

- une carte micro SD d'une capacité d'au moins 1 Go (2 Go conseillés).

Concernant le choix de la carte, il faut veiller à prendre une classe 4 au minimum (classe 6 conseillée).

Préparation de la carte :

Nous allons formater la carte en 2 partitions :

- partition 1 : 8Mo en fat ;

- partition 2 : ext2 pour tout le reste.

Insérez la carte dans le lecteur de votre poste de travail. La première chose à déterminer est le nom du périphérique. Pour cela, lancez la commande suivante :

# dmesg | tail

Puis, notez le nom du périphérique qui gère la carte micro SD.

Ensuite, démontez-la (umount) et, en root, lancez fdisk :

# fdisk /dev/sdX

Avec sdX comme nom du périphérique.

Si des partitions existent déjà, il faut les détruire en tapant d (il faut taper d autant de fois qu'il y a de partitions). Ensuite, ajoutez une nouvelle partition :

- n

- primary partition

- partition number : 1

- size : +8M

Changez le type en vfat :

- t

- 4

Ajoutez une autre partition :

- n

- primary partition

- partition number : 2

Finalisez les modifications en tapant w.

 

h1-fdisk

 

Fig. 1 : Partitionnement de la carte micro SD

Il faut maintenant formater les deux nouvelles partitions. La première partition doit être en vfat :

# mkfs.vfat /dev/sdX1

Et la seconde en ext2 :

# mkfs.ext2 /dev/sdX2

 

h1-mkfs

 

Fig. 2 : Formatage des deux partitions précédemment créées

5.3.2 Récupération et installation des archives

Téléchargez les archives sur votre poste de travail :

# wget http://download.hackable1.org/h1-fat_partition-rev4.tar.gz

# wget http://download.hackable1.org/h1-ext2_partition-rev4-classic-rc1.tar.gz

En root, extrayez les archives dans un répertoire temporaire, puis montez les 2 partitions précédemment créées.

Allez dans le répertoire de la partition fat, puis :

# tar xzmof /path/to/h1-fat_partition-rev4.tar.gz

Faites la même chose avec la partition ext2 :

# tar xzf /path/to/h1-ext2_partition-rev4-classic-rc1.tar.gz

5.3.3 Démarrage et premiers pas

Le Freerunner doit démarrer sur la carte SD. Pour cela :

- Appuyez sur le bouton [AUX].

- En même temps, appuyez sur le bouton [POWER].

- Relâchez le bouton [AUX] en gardant le bouton [POWER] appuyé, un menu doit apparaître.

- Choisissez la deuxième ligne avec le bouton [AUX], puis appuyez sur [POWER] pour démarrer depuis la carte.

Si vous souhaitez que le Freerunner démarre par défaut sur la carte SD, un tutoriel est disponible à l'adresse suivante : http://www.hackable1.org/wiki/DefaultBoot.

Une fois démarré, la fenêtre de sélection du code PIN apparaît, ainsi que la page d'accueil.

 

h1_homepage

 

Fig. 3 : Écran d'accueil de Hackable:1 sur le Freerunner

Afin de pouvoir se connecter au Freerunner via le câble USB, lancez sur votre poste de travail, en root, les commandes suivantes :

# iptables -A POSTROUTING -t nat -j MASQUERADE -s 192.168.0.0/24

# sysctl -w net.ipv4.ip_forward=1

# ip addr add 192.168.0.200/24 dev usb0

# ifconfig usb0 up

Ensuite, connectez-vous avec :

# ssh root@192.168.0.202

root@192.168.0.202's password:

Le mot de passe est root.

Et voilà, vous êtes maintenant connecté et prêt à travailler !

5.4 Compilation d'un programme : prototypage

Hackable:1 possède tous les outils pour être directement opérationnel. Dans ce chapitre, je vais prendre le classique hello world disponible sous Debian Lenny.

Connectez-vous sur le Freerunner, puis ajoutez la ligne suivante dans /etc/apt/sources.list :

deb-src http://ftp2.de.debian.org/debian lenny main

Ensuite :

apt-get update && apt-get source -b hello

Après quelques minutes, le paquet devrait être construit et disponible. En effet, tout est disponible sur la micro SD pour compiler directement dessus. Afin d'accélérer la phase de compilation, on peut (et c'est même conseillé) utiliser distcc (voir plus bas).

Cette méthode, assez pratique, sert principalement pour de la mise au point et du prototypage rapide de programmes pas trop volumineux. En effet, la phase d'édition des liens est toujours réalisée sur le Freerunner et est consommatrice de ressources.

Pour des logiciels plus conséquents et un déploiement plus classique, il convient d'utiliser un cross-compilateur.

5.5 Utilisation du cross-compilateur

5.5.1 Installation

Hackable:1 met à disposition des développeurs un cross-compilateur complet et fonctionnel, basé sur emdebian. Il est disponible sous plusieurs formes :

- en version précompilée stable pour les architectures i386 et amd64 ;

- en version daily build toujours pour les architectures i386 et amd64 ;

- depuis le dépôt SVN de Hackable:1 et qu'il convient de générer sur son poste.

Ici, nous utiliserons la version précompilée stable pour i386.

Récupérez l'archive sur votre poste de travail :

# wget http://download.hackable1.org/cross/Hackable1-Openmoko-Freerunner-cross-2009.529-i386.tar.gz

Ensuite, en root :

# mkdir cross

# tar -xzvpf path/to/Hackable1-Openmoko-Freerunner-cross-2009.529-i386.tar.gz -C cross

Configuration du réseau :

Il sera peut être nécessaire de configurer /etc/resolv.conf avec les bons serveurs DNS. Le plus simple est de copier celui de votre système :

# cp /etc/resolv.conf cross/etc/resolv.conf

Démarrage.

En root, tapez la commande suivante :

# /usr/bin/env -i HOME=/root PATH=$PATH SHELL=$SHELL TERM=$TERM /usr/sbin/chroot cross /bin/bash

Et voilà vous êtes maintenant prêt à utiliser le cross compilateur !

5.5.2 Utilisation

Lors de la compilation, il faut utiliser le compilateur dédié et les bibliothèques associées. Ceux-ci sont situés dans le répertoire /usr/arm-linux-gnueabi/.

pkg-config est configuré pour aller chercher ces bibliothèques grâce aux variables d'environnement suivantes :

PKG_CONFIG_LIBDIR="/usr/arm-linux-gnueabi/usr/lib/pkgconfig:/usr/arm-linux-gnueabi/usr/share/pkgconfig"

PKG_CONFIG_SYSROOT_DIR="/usr/arm-linux-gnueabi"

Compilation d'un logiciel qui utilise Autoconf/Automake : l'utilisation de l'option --host devrait fonctionner dans la plupart des cas :

# ./configure --host=arm-linux-gnueabi

# make

Autre possibilité :

make CC=arm-linux-gnueabi-gcc

Compilation du noyau Linux : pour configurer le noyau pour une plateforme ARM.

# make ARCH=arm menuconfig

Pour lancer la compilation :

# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi

5.5.3 Exemple : compilation de hello, world

Ajoutez la ligne suivante dans /etc/apt/sources.list :

deb-src http://ftp2.de.debian.org/debian lenny main

Ensuite :

apt-get update && apt-get source hello

Allez dans le répertoire hello-2.2, puis tapez :

#./configure --host=arm-linux-gnueabi

#make

Copiez le binaire src/hello sur le Freerunner (via un scp par exemple) et exécutez-le. Vous devriez voir apparaître :

# ./hello

Hello, world!

5.5.4 Exemple : compilation de Neod

Neod est le logiciel qui gère entre autres les boutons [AUX], [POWER] et la gestion de l'énergie. Il est un peu moins trivial à compiler que le simple hello world.

Récupérez les sources :

# svn co svn://svn.hackable1.org/hackable1

Allez dans le répertoire de neod :

# cd hackable1/trunk/src/core/neod

Puis, lancez autogen.sh :

# autogen.sh --host=arm-linux-gnueabi

Il est nécessaire de modifier le fichier ltmain.sh qui vient d'être généré pour que libtool utilise les bibliothèques du Freerunner plutôt que les natives (en utilisant l'option -inst-prefix-dir).

Ajoutez à la ligne 2784 du fichier ltmain.sh :

esac

fi

test -f "$inst_prefix_dir$add" && add="$inst_prefix_dir$add" # ajouter cette ligne

if test "$linkmode" = prog; then

Ensuite, relancez le script configure :

# ./configure --host=arm-linux-gnueabi

Puis, lancez la compilation :

make LDFLAGS="-inst-prefix-dir /usr/arm-linux-gnueabi -L/usr/arm-linux-gnueabi/lib -L/usr/arm-linux-gnueabi/usr/lib -Wl,-rpath-link /usr/arm-linux-gnueabi -Wl,-rpath-link /usr/arm-linux-gnueabi/usr/lib"

Après quelques minutes, le binaire devrait être construit.

Un file sur src/neod nous indique que le format est bien le bon :

# file neod

# neod: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.14, not stripped

On peut s'en assurer en le copiant en lieu et place de celui présent sur le Freerunner et en relançant le processus neod.

5.5.5 Utilisation de distcc

Le cross compilateur est fourni avec un environnement complet dont distcc qui permet de déporter les phases de compilation sur votre machine. Voici les étapes pour le démarrer.

Lancez l'environnement (en root) :

# /usr/bin/env -i HOME=/root PATH=$PATH SHELL=$SHELL TERM=$TERM /usr/sbin/chroot cross /bin/bash

Loguez-vous sous le compte utilisateur hackable1 :

# su - hackable1

Démarrez le démon distcc :

# distccd --daemon --allow '192.168.0.202'

Et voilà, ensuite il suffit de se connecter sur le Freerunner et de lancer une compilation classique !

Hackable:1 sur le Freerunner utilise par défaut distcc s'il est disponible sur votre poste de travail. Ce comportement est configuré dans le fichier ~/.bashrc avec les lignes suivantes :

export CC="distcc arm-linux-gnueabi-gcc"

alias dh='export DISTCC_HOSTS="192.168.0.200"'

alias dh1='export DISTCC_HOSTS="192.168.1.200"'

export DISTCC_HOSTS="192.168.0.200"

5.6 Trucs et astuces

5.6.1 Ajouter une entrée dans la page d'accueil

Si vous voulez que votre application soit visible depuis le menu d'accueil, il suffit de créer un fichier monappli.desktop dans le répertoire /usr/share/applications/ du Freerunner. Ce fichier suit la spécification de freedesktop.org (http://standards.freedesktop.org/desktop-entry-spec/latest/).

Exemple de fichier :

[Desktop Entry]

Name=woosh! Browser

Comment=Minimalistic but fast Browser

Encoding=UTF-8

Version=1.0

Type=Application

Exec=woosh

Icon=woosh

Terminal=false

Categories=GTK;Application;PIM;mainapps

SingleInstance=true

StartupNotify=true

Les catégories sont définies dans le répertoire /usr/share/matchbox/vfolders. Vous pouvez modifier et créer d'autres catégories sur le modèle de celles existantes.

5.6.2 Relancer l'interface graphique sans redémarrer

Si, lors de vos développements, vous avez besoin de relancer l'interface graphique et tous les logiciels lancés au démarrage, vous pouvez utiliser la commande suivante afin d'éviter un redémarrage complet du Freerunner :

#/etc/init.d/xserver-hackable1 restart

5.6.3 Utiliser x2x

x2x permet d'utiliser sa souris et son clavier sur le Freerunner. Pour l'activer, lancez la commande suivante sur votre poste de travail (en étant déjà connecté avec le Freerunner) :

# ssh -X root@192.168.0.202 "/usr/bin/x2x -east -to :0.0"

root@192.168.0.202's password:

Rentrez le mot de passe (root).

Maintenant, vous pouvez déplacer votre souris sur la droite de votre écran et elle devrait apparaître sur le Freerunner. Votre clavier devient alors actif sur le Freerunner.

5.6.4 Lancer une application graphique depuis votre poste

Afin de lancer une application graphique depuis votre poste (depuis la connexion SSH), il faut lancer la commande suivante :

# ssh root@192.168.0.202

192.168.0.202's password:

debian-gta02:~# export DISPLAY=:0

Ensuite, vous pouvez lancer n'importe quelle application graphique depuis cette console.

5.6.5 Déporter l'affichage depuis le Freerunner sur votre poste

Vous pouvez utiliser votre poste de travail comme périphérique d'affichage.

Préparation du poste de travail :

- Installez le logiciel Xephyr (apt-get install xserver-xephyr sous Debian) sur votre poste de travail.

- Démarrez-le avec la commande :

# Xephyr :1 -ac -2button -host-cursor -screen 480x640 -dpi 150

Sur une console ssh connectée sur le Freerunner, lancez un export DISPLAY vers votre poste :

# export DISPLAY=192.168.0.200:1

Ensuite, n'importe quelle application graphique lancée depuis cette console sera affichée sur votre poste.

5.7 Hackable:1, en quelques mots

Hackable:1 permet d'effectuer ses premiers pas en développement sur le Freerunner en quelques minutes. On peut même s'amuser avec des langages plus exotiques comme Erlang avec un simple apt-get install erlang.

Le cross-compilateur est présenté de manière rapide. Je vous invite à aller voir la page dédiée sur le wiki Dbus avec plus particulièrement la méthode pour cross-compiler un paquet Debian.

Pour information, ce cross-compilateur est généré par un outil similaire à Debootstrap qui permet de générer à partir du dépôt SVN :

- un cross-compilateur ;

- des images prêtes à l'emploi pour des cartes SD ou à flasher directement sur le Freerunner.

Conclusion

À l'issue de cet article, vous devriez être en mesure de pouvoir développer des logiciels pour un GTA01/GTA02, qui est, rappelons-le, le seul essai commercial de téléphone (presque) entièrement libre sur tous les points. Que vos préférences vous mènent vers Debian ou vers OpenEmbedded, vous devriez être en mesure de choisir la distribution adaptée à vos besoins, et commencer à donner de vous-même pour participer à cette fabuleuse aventure qui, nous l'espérons, ne manque pas d'avenir. Aussi, n'hésitez pas à réagir sur nos listes de diffusion, soumettre des rapports de bogues ou encore à créer vos propres logiciels ! Tous les outils sont dès à présent entre vos mains.

Références

[OBM] : http://www.openbmap.org

[OEGIT] : http://cgit.openembedded.net

[SHR] : http://trac.shr-project.org

[SHRGIT] : http://git.shr-project.org

[FSO] : http://trac.freesmartphone.org

[FSOGIT] : http://git.freesmartphone.org

[FSODOCS] : http://docs.freesmartphone.org

[FDO] : http://www.freedesktop.org

[BLUEZ] : http://www.bluez.org

[CONN] : http://moblin.org/projects/connection-manager

[WPAS] : http://hostap.epitest.fi/wpa_supplicant

[GPSD] : http://gpsd.berlios.de

[PYTH] : http://www.python.org

[VALA] : http://www.vala-project.org

 



Articles qui pourraient vous intéresser...

Prise en main de la NVIDIA Jetson Nano

Magazine
Marque
GNU/Linux Magazine
Numéro
247
Mois de parution
avril 2021
Domaines
Résumé

Les cartes de type Raspberry Pi ne sont pas forcément les plus adaptées pour y faire tourner des programmes mettant en œuvre des réseaux de neurones en embarqué. Aussi, de nouvelles cartes dédiées à l’IA apparaissent et nous allons découvrir dans cet article l’une de ces cartes, la Jetson Nano de NVIDIA.

Arithmétique sur divers systèmes embarqués aux ressources contraintes : les nombres à virgule fixe

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
113
Mois de parution
mars 2021
Domaines
Résumé

Tracer les fractales de Mandelbrot ou de Newton sur de petits microcontrôleurs 8 bits ou 32 bits nous donne l’opportunité d’appréhender la représentation des nombres en virgule fixe pour une implémentation efficace de l’arithmétique – même sur des nombres complexes – sur systèmes embarqués à ressources réduites. Pouvoir tester le même code sur une multitude de plateformes impose de structurer son code pour séparer la partie algorithmique et l’accès aux ressources matérielles : nous allons proposer une architecture de code et de Makefile compatible à la fois avec des tests sur PC et sur diverses architectures de microcontrôleurs, en faisant appel aux stubs.

CrossDev sous Eclipse

Magazine
Marque
GNU/Linux Magazine
HS n°
Numéro
112
Mois de parution
janvier 2021
Domaines
Résumé

Le développement logiciel nécessite l’utilisation d’outils pour l’écriture, la compilation et le débogage de code. La prise en main de ces outils n’est pas toujours évidente, alors lorsqu’on en maîtrise un, autant l’utiliser dans le maximum de cas. Eclipse permet cela et nous allons le voir dans le cas du développement embarqué.

Facilitez le déploiement de vos Raspberry Pi en créant vos propres images préconfigurées

Magazine
Marque
Hackable
Numéro
35
Mois de parution
octobre 2020
Domaines
Résumé

Ne vous est-il pas arrivé d'avoir un Raspberry Pi et sa carte mémoire sans écran ni clavier et ni souris à proximité pour le configurer lors de sa mise en service ou tout bonnement, lorsque vous souhaitez mettre en route votre projet basé sur Raspberry Pi ? Comme nombre d'applications industrielles ou domotiques, il est possible de préparer une carte mémoire avec une préconfiguration qui permet un tel démarrage. C'est ce que nous allons voir dans cet article.

MiSTer : La solution rétro ultime ?

Magazine
Marque
Hackable
Numéro
35
Mois de parution
octobre 2020
Domaines
Résumé

Imaginez, un matériel unique capable de simuler fidèlement n'importe quel ordinateur, console et borne d'arcade rétro, sans émulation et vous donnant accès à une collection presque infinie de programmes, de démos et de jeux. Le tout compatible avec du matériel moderne (HDMI, USB, etc.), activement développé et accessible pour un budget raisonnable (mais pas économique pour autant). Cette solution existe, c'est MiSTer !