Linux Embedded

Le blog des technologies libres et embarquées

Introduction à Ofono

Présentation

Ofono, une pile téléphonique pour systèmes Linux

Ofono est une pile téléphonique développée par Intel dont le développement est aujourd'hui assuré par la communauté. Ofono est distribué sous une licence GPL-2.0+ et est écrit en langage C.

Une pile téléphonique est un framework permettant de faire abstraction du matériel (le modem en lui-même) et du protocole de communication entre le CPU et le modem : Hayes AT, QMI,…. Ce type de framework permet aussi d'offrir une interface utilisateur générique, en ce qui concerne les usages les plus courant d'un modem : appels, SMS et des méthodes spécifiques à un matériel.

Pour garantir la généricité, l'interface utilisateur est assurée par le formalisme DBus :

  • Ofono est un processus enregistré sur le bus système.
  • Un modem est un objet possédant des interfaces.
  • Chaque interface possède des méthodes (use cases).
  • Certaines interfaces déclarent des objets, eux-même pouvant exécuter des méthodes.

Le schéma ci-dessous décrit la hiérarchie interne d'Ofono.

 

Ofono est un framework pensé de manière minimaliste. L'empreinte mémoire de la stack sur un système linux est de 1,5Mo pour les dépendances (librairies) et 1,7 Mo pour le binaire ofonod. Il utilise très peu de librairies annexes (glib et dbus), ainsi l'intégration sur un système en est facilité sur des systèmes embarqués. Il est possible d'utiliser Ofono avec du Bluetooth et des gestionnaires de connexions tels que BlueZ ou ConnMan.

L'intérêt d'utiliser une pile téléphonique réside dans le fait de s'abstraire du type de modem et du type de génération de télécom (GSM, GPRS, 3G, LTE). Ofono masque ce genre de détails dont l'application utilisatrice n'a pas à se soucier.

Usage dans l'embarqué

Ofono est un projet déjà utilisé dans l'industrie mais aussi dans les produits grand public. On le retrouve notamment dans différents systèmes d'exploitation.

Sailfish OS

Sailfish Os est un système d'exploitation développé à partir de Mer Linux, il est embarqué sur le smartphone Jolla développé par la société du même nom.

MeeGo

MeeGo est une distribution Linux développée par Intel et Nokia, embarquant Ofono et elle-même embarquée sur le N9, smartphone réalisé par Nokia en 2011.

Tizen

Tizen est un système d'exploitation pour plate formes mobiles développé conjointement par la fondation Linux, Samsung et Intel.

Ubuntu Touch

Ubuntu Touch est l'OS développé par la société Canonical pour les plate formes mobiles. Comme les OS précédents, il embarque Ofono.

Chacun des OS cités précédemment à été embarqué sur des matériels différents. Cela implique de gérer des modems différents.

Dans les système présentés ci-dessus, on retrouve majoritairement la combinaison : Ofono-ConnMan afin d'assurer la gestion des connexions de données via le modem. Bien que ce soit le modem 3G qui envoie effectivement les données, c'est ConnMan qui crée et gère l'interface réseau associée à cette connexion, Ofono ayant pour rôle la transmission des informations relatives au modem (adresse IP, état du réseau, force du signal, ...) à ConnMan.

État du développement actuel / futur d'ofono.

Bien que le dépôt git d'Ofono soit régulièrement mis à jour, rien n'indique de changement majeur à venir. Actuellement le dépôt principal d'Ofono est alimenté par des développeurs améliorant le support des drivers. Dans le "langage Ofono", améliorer le support des drivers revient à implémenter la prise en charge des commandes DBus pour différents modems.

Une importance particulière est donnée au RIL modem. RIL signifie Radio Interface Layer, c'est l'interface matériel-logiciel généralisée par Android. Ofono peut gérer le matériel basé sur la technologie RIL, ainsi, on a l'architecture suivante :

image tirée de : https://sailfishos.org/wiki/Cellular_Telephony_Architecture

Le développement du support pour le RIL modem permet d'améliorer la compatibilité avec Androïd pour un OS embarquant Ofono.

Mise en place dans un projet Linux embarqué

Yocto

Pour embarquer Ofono dans Yocto, la procédure est très simple. Ofono est déjà embarqué dans la distribution poky. Il suffit ainsi de créer l'image core-image-base pour avoir Ofono. Cependant, la recette doit être mise à jour.

Voici une copie du fichier ofono_git.bb permettant de récupérer et compiler la dernière version d'Ofono.

require ofono.inc
S = "${WORKDIR}/git"
SRCREV = "14544d5996836f628613c2ce544380ee6fc8f514"
PV = "0.12-git${SRCPV}"
PR = "r5"

SRC_URI = "git://git.kernel.org/pub/scm/network/ofono/ofono.git \
    file://ofono"

do_configure_prepend () {
     ${S}/bootstrap
}

Nous allons utiliser l'image, core-image-base afin d'embarquer Ofono et pourvoir tester le tout avec qemu. En regardant les images features ainsi que les images extra features de la distribution, on s'aperçoit qu'Ofono n'est pas embarqué dans l'image.

Il faut donc indiquer à Yocto d'intégrer le paquet Ofono dans core-image-base.

touch $YOCTO_SRC/meta/recipes-core/images/core-image-base.bbappend

→ Edition du fichier bbappend

IMAGE_FEATURES_append += "ssh-server-openssh"
IMAGE_INSTALL_append += "ofono"

On peut compiler donc compiler l'image contenant Ofono et l'exécuter via qemu :

  • compilation : bitbake core-image-base
  • exécution : run qemux86

Le shell suivant apparaît.

En cherchant la liste des processus lancés par systemd on obtient le résultat suivant :

Buildroot

L'objectif est de compiler une image buildroot contenant Ofono. Il faut télécharger ou cloner la dernière version de Buildroot.

$wget https://buildroot.org/downloads/buildroot-2016.08.1.tar.gz
$git clone https://git.buildroot.net/buildroot

La configuration de la cible est faite via menuconfig. Ofono est intégré de base dans buildroot, il suffit de l'activer.

make qemu_x86_defconfig
make menuconfig

Des dépendances doivent être satisfaites afin qu'Ofono puisse être compilé :

BR2_USE_WCHAR [=y] && BR2_TOOLCHAIN_HAS_THREADS [=y] && BR2_USE_MMU [=y] && !BR2_STATIC_LIBS [=n] && BR2_TOOLCHAIN_HAS_SYNC_4 [=y]

Afin d'avoir les wchar et les librairies dynamiques, les threads et C++ il suffit de sélectionner la glibc dans :

→ Toolchain

→ C library

Une fois ces dépendances satisfaites, le paquet ofono est accessible dans le menu :

→ Target packages

→ Hardware handling

La compilation est lancée avec « make » qui laisse le temps d'aller boire un (gros) café. Lorsque la compilation est terminée, l'image générée par buildroot se lance avec qemu :

qemu-system-x86_64 -kernel bzImage -drive file=rootfs.ext2 -append "root=/dev/sda console=ttyAMA0,115200" -serial stdio

Ofono est bien présent sur la distribution.

Compilation croisée

Comment configurer et compiler les sources d'Ofono pour une cible particulière ?

Cette étape consiste à faire, à la main, ce que font Buildroot et Yocto avec leurs scripts. Nous ne détaillerons pas comment installer le compilateur croisé, cela sort du cadre de cet article.

L'exemple suivant concerne une cible ARM classique : le raspberry pi.

En premier lieu, il faut cloner le dépôt de Ofono :

git clone git://git.kernel.org/pub/scm/network/ofono/ofono.git

Ensuite, il faut exécuter autotools afin de créer le script "configure". Pour cela, Ofono fournit un script appelé « bootstrap ». Il suffit de le lancer :

./bootstrap.

Pour s'assurer qu'Ofono est compilé pour ARM il faut ajouter le chemin vers le compilateur croisé dans le path :

export PATH=$PATH:<chemin-vers-cross-compiler>

Exécuter le script configure en spécifiant la cible :

./configure --host=arm-linux

Il est possible que le script sorte en erreur du fait de la non-détection de librairies nécessaires à Ofono. Dans ce cas, il convient de trouver ces librairies dans le sysroot du cross-compiler et d'ajouter les chemins idoines dans la variable d'environnement PKG_CONFIG_PATH.

Lorsque le script configure a créé le makefile adéquat, il ne reste plus qu'à compiler Ofono. On le compile en utilisant la commande make. Il faut noter que Ofono, lors de la compilation, ressort un grand nombre de warnings.

Une fois l'exécutable généré, il faut le transférer sur la cible. Chaque développeur a sa préférence scp, tftp,.... A noter qu'Ofono doit être installé dans le répertoire /usr/sbin.

L'exécution d'Ofono se fait avec la commande suivante :

/usr/sbin/ofonod -n

Configuration

Ofono n'a pas besoin de configuration à proprement parler, en effet la détection du modem est automatique. Le seul besoin en termes de configuration concerne systemd. Grâce à systemd, il est possible de lancer Ofono automatiquement tout en spécifiant les dépendances devant être au préalable lancées pour assurer son bon fonctionnement.

Voici un exemple de fichier ofono.service :

[Unit]
Description=Telephony service
After=syslog.target

[Service]
Type=dbus
BusName=org.ofono
ExecStart=@installpath@/ofonod -n
Restart=always
StandardError=null

Utilisation (cookbook)

Cas d'utilisation utilisateur

Ofono est utilisé via des commandes Dbus. Pour plus de documentation concernant l'utilisation de Dbus, l'article suivant est tout indiqué : http://www.linuxembedded.fr/2015/07/comprendre-dbus/

Les différents cas d'usages décrits ont été choisis parce que ce sont des fonctionnalités de base d'un téléphone. Comme dit dans la première partie, l'interface de Ofono est standard. Les seules commandes « spécifiques » sont celles qui implémentent des fonctionnalités propres à chaque modem.

Les cas d'usages sont des enchaînements de commande dbus-send provoquant l'appel d'une ou de plusieurs méthodes relatives à une ou plusieurs interfaces. La documentation d'Ofono décrit les différentes interfaces. Chaque fichier décrit une interface. Ofono, de base, contient 50 interfaces différentes dont voici quelques exemples :

  • sms.txt ↔ l'interface permettant d'envoyer et recevoir des SMS,
  • voicecall.txt ↔ l'interface permettant de passer et recevoir des appels vocaux,
  • network.txt ↔ l'interface permettant d'initier une connexion de données,
  • etc.

Créer une fonctionnalité avec Ofono consiste à invoquer des méthodes dans un ordre précis. Or, toutes ces méthodes étant décrites dans la documentation, utiliser Ofono revient beaucoup à cette célèbre maxime des forums techniques : RTFM NOOB !

En premier lieu, pour un modem, on peut afficher chaque interface grâce à la méthode suivante :

dbus-send –system –print-reply –dest=org.ofono / org.ofono.Manager.GetModems

Avant de tester ces cas d'utilisation, il convient que le modem soit :

  1. Allumé :
dbus-send --system --print-reply --dest=org.ofono /ril0 org.ofono.ModemManager.SetProperty variant:string:"Powered" variant:boolean:true

2. Connecté à un réseau :

dbus-send --system --type=method_call --print-reply --dest=org.ofono /cinterionpxs8_0 org.ofono.Modem.SetProperty string:"Online" variant:boolean:true

3. Autorisé à envoyer et recevoir de la donnée :

envoyer un SMS

Pour envoyer un SMS, les méthodes à invoquer sont contenues dans l'interface MessageManager. Une de ces méthodes se nomme Send et prend pour argument une chaîne représentant le numéro ainsi qu'une 2ème chaîne représentant le message. Par exemple, pour un RIL modem :

dbus-send --system --print-reply --dest=org.ofono /ril0 org.ofono.MessageManager.Send string:"+33600000000" string:"testsms"

recevoir SMS

Recevoir un SMS consiste à espionner le bus system de Dbus pour récupérer le message « incoming message » de l'interface MessageManager :

dbus-monitor --system "type='signal',interface='org.ofono.MessageManager'"

appeler

Pour appeler avec Ofono, il faut d'abord créer un objet « voicecall ». C'est cet objet qui sera manipulé pour contrôler ou agir sur l'objet.

création de l'objet

dbus-send --system --print-reply --dest=org.ofono /ril0 org.ofono.VoiceCallManager.Dial string:"+33600000000" string:"enabled"

Cette commande crée un objet voicecall qui peut être utilisé pour manipuler l'appel. Par exemple, pour raccrocher l'appel voicecall créé par la précédente commande :

dbus-send --system --print-reply --dest=org.ofono /ril0/voicecall01 org.ofono.VoiceCall.HangUp

recevoir appel

Lors de la réception d'un appel, Ofono va automatiquement créer un objet voicecall. Ainsi, il suffit de récupérer l'identifiant de l'objet voicecall puis d'invoquer la méthode adéquate :

dbus-send --system --print-reply --dest=org.ofono /ril0 org.ofono.VoiceCallManager.GetCalls

Le retour de la méthode est un tableau contenant les chemins des différents appels.

Il ne reste plus qu'a invoquer la méthode « Answer » :

dbus-send --system --print-reply --dest=org.ofono /ril0/voicecall01 org.ofono.VoiceCall.HangUp

l'appel est décroché !

data : ping + wget

Pour créer une connexion data, il faut utiliser l'interface ConnectionManager. Cette interface permet de créer une connexion PPP ou WWAN entre un processeur et une station de base (équipement d'un opérateur) via le modem qui jouera le rôle de l'interface réseau physique.

L'interface ConnectionManager n'est créée que si l'interface NetworkRegistration (gérant l’appariement au réseau) est connectée et initie la connexion aux services Packet Domain Services. Si la connexion est un succès, l'interface ConnectionManager est créée.

Il faut bien comprendre qu'à ce moment le modem n'a pas encore accès à Internet. Il peut juste créer une connexion PPP ou WWAN

PPP et WWAN sont deux interfaces réseaux créées via un modem. L'interface PPP est créée via le port série et l'interface WWAN via le lien USB.

Avant de démarrer une connexion de données, il faut créer un contexte. Un contexte est l'ensemble des informations de la connexion qui seront passées au gestionnaire de connexion (ConnMan ou NetworkManager) :

  • le type d'interface,
  • les informations IP (addresse IP, netmask, Gateway),
  • la méthode d'authentification (CHAP, PAP),
  • L'APN,
  • nom d'utilisateur,
  • mot de passe,
  • Message Center,
  • Message Proxy.

Il faut renseigner ces informations.

dbus-send --system --print-reply --dest=org.ofono /cinterionpxs8_0 org.ofono.ConnectionPreferences.SetProperty string:"Technology" variant:string:"<wwan ou ppp>"
dbus-send --system --type=method_call --print-reply --dest=org.ofono /cinterionpxs8_0/context1 org.ofono.ConnectionContext.SetProperty string:"AccessPointName" variant:string:"<nom de l'APN>"
dbus-send --system --type=method_call --print-reply --dest=org.ofono /cinterionpxs8_0/context1 org.ofono.ConnectionContext.SetProperty string:"Username" variant:string:"<username>”
dbus-send --system --type=method_call --print-reply --dest=org.ofono /cinterionpxs8_0/context1 org.ofono.ConnectionContext.SetProperty string:"Password" variant:string:"<password>

Si la carte SIM est étrangère, il faut autoriser le roaming de données :

dbus-send --system --type=method_call --print-reply --dest=org.ofono /cinterionpxs8_0 org.ofono.ConnectionManager.SetProperty string:"RoamingAllowed" variant:boolean:true
dbus-send --system --type=method_call --print-reply --dest=org.ofono /cinterionpxs8_0/context1 org.ofono.ConnectionContext.SetProperty string:"Active" variant:boolean:true

Une fois le contexte activé, une interface ppp0 ou wwan0 est créée et peut être utilisée :

ping -I ppp0 8.8.8.8
ping -I wwan0 8.8.8.8

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée.