tag:linuxfr.org,2005:/tags/mobian/publicLinuxFr.org : les contenus étiquetés avec « mobian »2023-06-01T15:26:56+02:00/favicon.pngtag:linuxfr.org,2005:Post/436542023-05-30T21:30:04+02:002023-05-31T11:15:01+02:00[SMARTPHONES & OS] : Retours d'expériences<p>Bonsoir,</p>
<p>Voila maintenant un moment que j'essaie quelques OS de téléphone.</p>
<p>Dans l'ordre suivant :<br>
-android<br>
-sailfish<br>
-e os<br>
-mobian</p>
<p>Dans le souci de l'opensource et le libre, j'essaie de me tourner d'avantage vers des OS type Linux.</p>
<p>Mes applications principales en plus du classique GPS se tournent vers des clients XMPP/Matrix pour du chat ou de la video.</p>
<p>-<strong>SalfishOS</strong>, je l'ai testé avec un htc one m8 et c'était pas facile de porter le projet sur ce téléphone.<br>
L'écosystème applicatif n'étant pas aussi développé qu'android et le manque de temps pour continuer m'a fait arrêter.<br>
Et puis, il y a la partie UI propriétaire qui me plaisait pas beaucoup.</p>
<p>-Ensuite, j'ai vu le projet <strong>E OS (Murena)</strong> que j'ai testé, qui est un fork d'android avec un purge des lignes de code google (autant que faire ce peu).<br>
Je n'ai pas inspecté leur roadmap mais c'est honorable et peut être aussi un modèle économique.</p>
<p>Le fairephone est aussi interessant mais assez couteux également.</p>
<p>Cet OS fonctionne bien, avec quelques fonctionnalités intéressantes en plus.</p>
<p>-Puis, je me suis mis à l'OS <strong>Mobian</strong> pour être au plus proche de debian que j'utilise quotidiennement.<br>
J'ai acheté le pinephone. L'OS est développé par une communauté.<br>
Le plus gros problème c'est dès que tu utilises des applications un peu gourmandes, la batterie part assez vite !</p>
<p>Et d'après un internaute, les OS linux ne feront jamais assez bien en terme d'<strong>autonomie de la batterie</strong> qu'android à moins d'implémenter les fonctions suivante :<br>
-l'OS sauvegarde l'état de chaque application et peut la suspendre/fermer <br>
-sauvegarde en mémoire l'interface utilisateur et freeze les applications pour reprendre plus tard</p>
<p>Les OS linux comme ceux disponible sur le pinephone : Manjaro, Plasma Mobile (en), Ubuntu Touch, PostmarketOS, Sailfish OS, Mobian, GloDroid</p>
<p>On me dit que la <strong>majorité des personnes qui cherchent un autre OS</strong> se tournent vers postmarketOS et le smartphone onePlus6, je ne sais pas pourquoi exactement.</p>
<p>Que pensez-vous des projets d'OS sous linux et qu'utilisez-vous comme OS/smartphone ?</p>
<p>Avec Mobian et le pinephone, j'arrive à une journée maximum avec peu d'applications et une 4G/Wifi raisonnable. Le GPS est très long à accrocher une position (via plusieurs satellites).</p>
<p>Merci pour vos retours d'expériences.</p>
<p>Bonne journée.</p>
<div><a href="https://linuxfr.org/forums/linux-embarque/posts/smartphones-os-retours-d-experiences.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/131413/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/forums/linux-embarque/posts/smartphones-os-retours-d-experiences#comments">ouvrir dans le navigateur</a>
</p>
electro575https://linuxfr.org/nodes/131413/comments.atomtag:linuxfr.org,2005:Diary/399012021-09-02T22:45:50+02:002021-09-03T08:34:04+02:00Simuler un clic avec libevdev et uinputLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#toc-pr%C3%A9ambule">Préambule</a></li>
<li><a href="#toc-probl%C3%A8me-et-solution">Problème et solution</a></li>
<li>
<a href="#toc-libevdev--r%C3%A9cup%C3%A9rer-les-%C3%A9v%C3%A8nements-des-p%C3%A9riph%C3%A9riques-dentr%C3%A9e">libevdev – récupérer les évènements des périphériques d’entrée</a><ul>
<li><a href="#toc-ouverture-du-p%C3%A9riph%C3%A9rique-et-r%C3%A9ception-des-%C3%A9v%C3%A8nements-tactiles">Ouverture du périphérique et réception des évènements tactiles</a></li>
<li><a href="#toc-gestion-des-%C3%A9v%C3%A8nements">Gestion des évènements</a></li>
</ul>
</li>
<li><a href="#toc-uinput--g%C3%A9n%C3%A9rer-des-%C3%A9v%C3%A8nements">uinput – générer des évènements</a></li>
<li><a href="#toc-compilation-et-installation">Compilation et installation</a></li>
<li><a href="#toc-future-work">Future work</a></li>
<li><a href="#toc-conclusion">Conclusion</a></li>
</ul>
<h2 id="toc-préambule">Préambule</h2>
<p>Samedi 7 août, 14h UTC+2 : une pluie de tous les enfers se déchaîne. Il pleut tout l’après-midi, mais c’est la tempête surtout pendant une demi heure. Le sol est inondé. Les gens courent, l’imper sur lequel je comptais jette l’éponge, mon téléphone pas étanche dans la poche de l’imper pas étanche est mouillé et c’est le drame : il ne s’allume plus.</p>
<p>Dimanche 8 août. Le téléphone refonctionne (son module wifi et Bluetooth démarre bien quand bon lui semble, mais il finira par refonctionner normalement quelques jours plus tard. Ouf).</p>
<p>… mais une bande de l’écran ne répond plus au tactile. Cette bande correspond pile poil à la barre d’état de l’environnement graphique, Phosh. C’est la même qu’on trouve aussi sur iOS et Android, rien de remarquable : on en a besoin pour accéder aux différentes fonctionnalités activables et désactivables et il n’y a guère d’autres interactions possibles sur cette barre. Vous connaissez certainement.</p>
<p>Bon, c’est chiant, mais en même temps, je n’ai aucune envie de changer l’écran pour si peu. Alors, que faire ?</p>
<h2 id="toc-problème-et-solution">Problème et solution</h2>
<p>Sur Phosh, la seule interaction possible sur cette barre est un clic, pour la dérouler. L’idée n’a pas tardé à arriver : on pourrait simuler un clic déclenché par une autre interaction, par exemple en posant trois doigts n’importe où sur l’écran. Il se trouve que le téléphone tourne sur une Debian, adaptée pour mobile (Mobian), tout ce qu’il y a de plus classique à part ça. On doit bien pouvoir faire quelque chose sur un tel système bidouillable sans devoir télécharger des centaines de mégas de SDK et accepter des licences pénibles, non ?</p>
<p>Bien sûr que oui, sinon ce journal n’existerait pas !! Phosh est basé sur Wayland, donc les solutions basées sur un serveur X11 comme <code>xdotools</code> sont très vite écartées. Il va falloir taper plus bas dans la pile logicielle. Il nous faudra également une manière de surveiller les tapes tactiles pour détecter quand trois doigts sont appuyés sur l’écran.</p>
<h2 id="toc-libevdev--récupérer-les-évènements-des-périphériques-dentrée">libevdev – récupérer les évènements des périphériques d’entrée</h2>
<p>Une recherche « Komen kon fé pour détecté les tapes ? » me mène rapidement sur <a href="http://who-t.blogspot.com/2013/09/libevdev-handling-input-events.html">cet article</a> du blog de Peter Hutterer, alias Who-T, de chez Red Hat. Peter, c’est <em>le</em> monsieur input de l’écosystème libre. La référence ultime. Quand tu tombes sur son blog, tu sais que tu ne vas pas lire de conneries. Il a donné une présentation super intéressante à la linux.conf.au 2020 <a href="https://lca2020.linux.org.au/schedule/presentation/79/">"Write a single library to handle all input devices, it'll be easy" they said…</a>, que je vous recommande vivement si vous comprenez l’anglais. C’est assez accessible et beaucoup plus intéressant que ça en a l’air. D’ailleurs, il y annonce qu’il cherche désespérément des gens pour travailler avec lui dans le domaine et que le <a href="https://en.wikipedia.org/wiki/Bus_factor">bus factor</a> est dangereusement proche de 1, mais que ce n’est pas très sexy comme domaine, parce qu’il faut péniblement prendre en charge et tester manuellement chaque matériel avec ses spécificités pour que le reste du monde n’ait pas besoin de s’emmerder avec ça et que tout fonctionne <em>out of the box</em>, et que les gens préfèrent généralement travailler sur d’autres trucs. Donc si ce journal suscite des vocations, ne vous censurez pas, contactez-le…</p>
<p>Bref, il nous raconte que :</p>
<blockquote>
<p>libevdev is a wrapper library to access /dev/input/eventX devices and provide their events through a C API.</p>
</blockquote>
<p>Traduction :</p>
<blockquote>
<p>libevdev est une bibliothèque qui enrobe les périphériques /dev/input/eventX et fournit leurs évènements à travers une API C.</p>
</blockquote>
<p>Parfait, ça ! Bon, c’était en 2013, mais tout fonctionne encore pareil. Ouf !</p>
<blockquote>
<p>Why use a library though? The kernel interface is relatively simple, but it has a few pitfalls. For one, device data is accessed through ioctl(2) and can cause weird bugs [1]. Second, not all events work in the same way. e.g. EVIOCGABS doesn't work the same for multi-touch axes, simply because the slot protocol has different semantics than the normal EV_ABS protocol. EV_REP has different handling as EV_ABS, EV_SYN is a special case anyway, etc. libevdev tries to avoid having to think about the differences and does sanity checks for the various calls.</p>
</blockquote>
<p>Traduction (romancée) :</p>
<blockquote>
<p>Mais pourquoi utiliser une bibliothèque ? L’interface noyau est relativement simple, mais elle a quelques soucis. Ça va être chiant, franchement on s’est embêtés à faire une bibliothèque toute propre qui uniformise tous vos affreux périphériques tous les plus différents les uns que les autres, utilisez ça si vous ne voulez pas finir dans une pièce blanche avec une camisole. Pitié, on sait de quoi on parle, on s’est sacrifiés pour vous alors maintenant, faites-nous plaisir et utilisez libevdev.</p>
</blockquote>
<p>Bon, ça a l’air bien libevdev, on va utiliser ça. Peter nous explique en détail comment faire dans son article en s’appuyant sur <a href="https://gitlab.freedesktop.org/libevdev/libevdev/blob/master/tools/libevdev-events.c">cet exemple simple</a>. Pour votre plaisir je vais le faire de ma manière ici.</p>
<h3 id="toc-ouverture-du-périphérique-et-réception-des-évènements-tactiles">Ouverture du périphérique et réception des évènements tactiles</h3>
<p>Commençons donc par inclure les bons entêtes, et on va ouvrir le périphérique qui correspond à la dalle tactile de mon téléphone et écouter les évènements qui arrivent :</p>
<pre><code class="c"><span class="c1">// (Tout le code C dans ce journal est copyright 2013 Red Hat, Inc, copyright 2021 moi, licence MIT)</span>
<span class="cp">#include</span> <span class="cpf"><stdbool.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><errno.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><fcntl.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><string.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><unistd.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><libevdev/libevdev.h></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">rc</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">struct</span> <span class="n">libevdev</span> <span class="o">*</span><span class="n">dev</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="n">open</span><span class="p">(</span><span class="s">"/dev/input/by-path/platform-1c2ac00.i2c-event"</span><span class="p">,</span> <span class="n">O_RDONLY</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">perror</span><span class="p">(</span><span class="s">"Failed to open device"</span><span class="p">);</span>
<span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">rc</span> <span class="o">=</span> <span class="n">libevdev_new_from_fd</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="o">&</span><span class="n">dev</span><span class="p">);</span>
<span class="k">do</span> <span class="p">{</span>
<span class="k">struct</span> <span class="n">input_event</span> <span class="n">ev</span><span class="p">;</span>
<span class="n">rc</span> <span class="o">=</span> <span class="n">libevdev_next_event</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">LIBEVDEV_READ_FLAG_NORMAL</span><span class="o">|</span><span class="n">LIBEVDEV_READ_FLAG_BLOCKING</span><span class="p">,</span> <span class="o">&</span><span class="n">ev</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">rc</span> <span class="o">==</span> <span class="n">LIBEVDEV_READ_STATUS_SUCCESS</span><span class="p">)</span> <span class="p">{</span>
<span class="n">handle_event</span><span class="p">(</span><span class="o">&</span><span class="n">ev</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">while</span> <span class="p">(</span><span class="n">rc</span> <span class="o">==</span> <span class="n">LIBEVDEV_READ_STATUS_SYNC</span> <span class="o">||</span> <span class="n">rc</span> <span class="o">==</span> <span class="n">LIBEVDEV_READ_STATUS_SUCCESS</span> <span class="o">||</span> <span class="n">rc</span> <span class="o">==</span> <span class="o">-</span><span class="n">EAGAIN</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">rc</span> <span class="o">!=</span> <span class="n">LIBEVDEV_READ_STATUS_SUCCESS</span> <span class="o">&&</span> <span class="n">rc</span> <span class="o">!=</span> <span class="o">-</span><span class="n">EAGAIN</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Failed to handle events: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="o">-</span><span class="n">rc</span><span class="p">));</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">rc</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="nl">out</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span><span class="n">fd</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">close</span><span class="p">(</span><span class="n">fd</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">dev</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
<span class="n">libevdev_free</span><span class="p">(</span><span class="n">dev</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="n">rc</span><span class="p">;</span>
<span class="p">}</span></code></pre>
<p>Décortiquons tout ça :</p>
<ol>
<li>on ouvre le périphérique qui correspond à la dalle tactile avec <code>open</code>
</li>
<li>on passe le périphérique à libevdev pour pouvoir l’utiliser à travers la bibliothèque, avec <code>libevdev_new_from_fd</code>
</li>
<li>on boucle sur les évènements qui arrivent, en récupérant le prochain évènement avec <code>libevdev_next_event</code> (appel bloquant)</li>
<li>on passe ces évènements à une fonction <code>handle_event</code> que nous nous apprêtons à construire</li>
</ol>
<p>Il y a toute la gestion des erreurs, avec l’entier <code>rc</code> qui contient le code de retour, initialisé à 1 comme ça par défaut on retourne une erreur et on le passera à 0 quand tout se sera bien passé. On groupe le nettoyage à la fin de la fonction, accessible par des <code>goto</code> (en cas d’erreur) avec l’étiquette <code>out</code> qui va bien.</p>
<p>Le fonctionnement normal du programme est de ne jamais s’arrêter de lui-même. On ne compte pas débrancher l’écran tactile en cours d’utilisation. On attend continuellement des évènements à traiter.</p>
<p>Le programme peut être lancé en tant qu’utilisateur simple, puisqu’un utilisateur simple peut accéder en lecture aux périphériques d’entrée. D’ailleurs, si vous vous disiez que Wayland vous protégeait des keyloggers parce que ça isole correctement les applications entre elles, eh bien c’est raté, la couche d’en dessous se charge de donner les accès.</p>
<p>Bon, alors, on se la fait cette gestion des évènements ??</p>
<p>Eh ben oui, allons-y…</p>
<h3 id="toc-gestion-des-évènements">Gestion des évènements</h3>
<p>Alors là, on implémente la fonction <code>handle_event</code> qui manque dans la section précédente. On cherche à repérer le moment où trois doigts sont posés sur l’écran, ni plus, ni moins.</p>
<pre><code class="c"><span class="k">static</span> <span class="kt">int</span> <span class="nf">handle_event</span><span class="p">(</span><span class="k">struct</span> <span class="n">input_event</span> <span class="o">*</span><span class="n">ev</span><span class="p">,</span> <span class="k">struct</span> <span class="n">libevdev_uinput</span><span class="o">*</span> <span class="n">uidev</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">static</span> <span class="kt">int</span> <span class="n">max_finger_id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">static</span> <span class="kt">bool</span> <span class="n">pressed</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="k">static</span> <span class="kt">int</span> <span class="n">must_click_on_btn_release</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="k">switch</span> <span class="p">(</span><span class="n">ev</span><span class="o">-></span><span class="n">type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="nl">EV_ABS</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ev</span><span class="o">-></span><span class="n">code</span> <span class="o">==</span> <span class="n">ABS_MT_SLOT</span><span class="p">)</span> <span class="p">{</span>
<span class="n">max_finger_id</span> <span class="o">=</span> <span class="n">max</span><span class="p">(</span><span class="n">max_finger_id</span><span class="p">,</span> <span class="n">ev</span><span class="o">-></span><span class="n">value</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="nl">EV_KEY</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ev</span><span class="o">-></span><span class="n">code</span> <span class="o">==</span> <span class="n">BTN_TOUCH</span><span class="p">)</span> <span class="p">{</span>
<span class="n">pressed</span> <span class="o">=</span> <span class="n">ev</span><span class="o">-></span><span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="nl">EV_SYN</span><span class="p">:</span>
<span class="k">if</span> <span class="p">(</span><span class="n">max_finger_id</span> <span class="o">==</span> <span class="mi">2</span> <span class="o">&&</span> <span class="n">pressed</span><span class="p">)</span> <span class="p">{</span>
<span class="n">must_click_on_btn_release</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">must_click_on_btn_release</span> <span class="o">&&</span> <span class="o">!</span><span class="n">pressed</span><span class="p">)</span> <span class="p">{</span>
<span class="n">simclick</span><span class="p">();</span>
<span class="n">must_click_on_btn_release</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">max_finger_id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span></code></pre>
<p>La structure <code>input_event</code> qu’on reçoit a trois champs qui nous intéressent : <code>type</code>, <code>code</code> et <code>value</code>. Le premier donne le type général de l’évènement, le deuxième spécifie plus précisément et le troisième est une info qui dépend de l’évènement (par exemple, quelle touche de clavier a été enfoncée).</p>
<p>Trois évènements nous concernent :</p>
<ul>
<li>le type <code>EV_ABS</code>, avec le code <code>MT_SLOT</code>. <code>ABS</code>, c’est pour absolu. Ça concerne les évènements qui ont des coordonnées absolues comme les écrans tactiles, à l’opposé des évènements relatifs comme les déplacements de souris. <code>MT_SLOT</code>, pour <em>mutltitouch slot</em>, permet de pister un doigt sur un écran tactile. Chaque doigt a son numéro, par ordre d’arrivée sur l’écran, en commençant par 0, puis 1, puis… vous avez compris. Quand vous déplacez vos doigts sur l’écran, ça va générer plein d’évènements mais chaque doigt aura toujours le même numéro (<em>slot</em>). C’est bien pratique. Vous imaginez, s’il fallait re-déduire le numéro de chaque doigt, évènement par évènement ? Heureusement que c’est fait pour nous !!</li>
<li>le type <code>EV_KEY</code>, avec le code <code>BTN_TOUCH</code>. <code>BTN</code> pour <em>button</em>. Quand vous enfoncez un ou des doigt(s), ça génère un évènement <code>BTN_TOUCH</code> avec une valeur <code>true</code>, et quand vous le(s) relâchez, ça génère un évènement avec une valeur <code>false</code>.</li>
<li>le type <code>EV_SYN</code>. C’est un évènement particulier, de synchronisation. Quand vous faites quelque chose sur votre écran (ou tout autre périphérique d’entrée), ça peut générer plusieurs évènements, pour la même action. Par exemple : « il s’est passé quelque chose avec le doigt 1 (<code>EV_ABS</code>). Il a été retiré de l’écran (<code>EV_KEY</code>). Ces évènements seront alors regroupés entre deux évènements de synchronisation <code>EV_SYN</code>.</li>
</ul>
<p>Vous vous dites peut-être alors qu’il va falloir stocker tout un état entre plusieurs évènements, au moins jusqu’au prochain « <code>EV_SYN</code> », voire plus, pour réagir quand on a assez d’info. J’ai pour cela choisi d’utiliser des variables statiques, qui persistent entre deux appels de la fonction <code>handle_event</code>. Ultra pratique. C’est comme des globales, mais pas accessibles depuis les autres fonctions. Ça rend la fonction totalement impure et il faut faire attention, ça rend potentiellement les tests unitaires pour cette fonction compliqués (je suis tombé sur <a href="https://stackoverflow.com/questions/49387056/unit-test-in-a-c-function-with-a-static-variable">cet échange « amusant » avec un gars qui doit tester un code d’avion qu’il ne peut pas vraiment modifier</a> en rédigeant le journal, <a href="https://www.ibm.com/support/pages/component-testing-c-how-test-static-variable-function">il y a des astuces intéressantes chez IBM</a>), mais en même temps ça colle parfaitement avec ce que j’ai envie de faire et je n’ai pas prévu de faire de tests unitaires.</p>
<p>Bref, en gros, ça fonctionne comme ça :</p>
<ul>
<li>quand on reçoit un numéro de doigt on enregistre son numéro (slot), s’il est plus grand que le numéro qu’on connait déjà.</li>
<li>quand un (des) doigt(s) est (sont) appuyé(s) ou relâché(s), on stocke ça dans <code>pressed</code>
</li>
<li>quand la fin d’un bloc d’évènements arrive :
<ul>
<li>si on réalise que exactement 3 doigts on été pressés (<code>max_finger_id == 2 && pressed</code>), on enregistre le souhait de générer un clic quand les doigts sont relâchés (<code>must_click_on_btn_release</code>);</li>
<li>si on réalise que tous les doigts ont été relâchés et qu’on souhaitait générer le clic, on le génère en appelant la fonction <code>simclick</code> et on oublie le souhait de générer un clic</li>
<li>on réinitialise le numéro de doigts max.</li>
</ul>
</li>
</ul>
<p>Notes :</p>
<ul>
<li>en jouant avec libevdev, on peut avoir l’impression qu’il manque des évènements. En fait, si on s’attendait à avoir un évènement mais que celui-ci aurait eu la même valeur que le dernier évènement reçu du même type et du même code, on ne le reçoit pas une nouvelle fois. Ainsi, si vous voulez écrire des interactions compliquées, <em>il ne faudrait pas réinitialiser votre état après chaque évènement <code>EV_SYN</code></em>, ce serait une erreur. Il n’y a probablement qu’en pratiquant et en se payant le mur soi-même que ça devient clair.</li>
<li>Pourquoi attendre que les doigts soient relâchés ? Pourquoi ne pas simplement générer un clic dès qu’on voit que tous les doigts ont été pressés ? Eh bien parce que c’est plus intuitif à l’utilisation. Si vous alliez poser un 4ᵉ doigt par exemple, trop tard, vous avez déjà généré le clic qui correspond à 3 doigts (or, je vous montre une version simplifiée de <code>handle_event</code>, et j’ai effectivement une gestion différente pour un 4ᵉ doigt). Et aussi, à cause d’un problème dont je parle dans la section suivante.</li>
</ul>
<p>Notre détection des 3 doigts est maintenant complète. Youpeee ! C’est déjà ça ! Vous pourriez vous arrêter là. Si vous vouliez par exemple exécuter une commande quand trois doigts sont appuyés, vous avez gagné. Il suffit d’appeler <code>system</code> ou <code>fork</code> + une version de <code>exec</code>.</p>
<p>Mais nous, on veut simuler un clic, alors c’est parti.</p>
<h2 id="toc-uinput--générer-des-évènements">uinput – générer des évènements</h2>
<p>J’apprends rapidement que pour simuler des clics (donc produire des évènements d’entrée « fake »), on peut utiliser l’interface du noyau Linux uinput. Pour <a href="https://who-t.blogspot.com/2013/09/libevdev-creating-uinput-devices.html">citer Who-T</a> :</p>
<blockquote>
<p>uinput is the kernel interface to create evdev devices that, for most purposes, look the same as real devices </p>
</blockquote>
<p>Traduction :</p>
<blockquote>
<p>uinput est l’interface noyau pour créer des périphériques evdev qui, pour la plupart des situations, ressemblent comme deux gouttes d’eau à des périphériques réels</p>
</blockquote>
<p>Très bien !</p>
<p>On continue à lire :</p>
<blockquote>
<p>As the evdev interface, the uinput interface requires you to handle a few structs and ioctls, not necessarily in an obvious way. libevdev wraps that for you.</p>
</blockquote>
<p>Traduction :</p>
<blockquote>
<p>Comme pour l’interface evdev, l’interface uinput vous demande de gérer quelques structures et ioctls, pas forcément de manière évidente. libevdev vous enrobe tout ça pour vous.</p>
</blockquote>
<p>Traduction :</p>
<blockquote>
<p>Rendez-vous service, utilisez libevdev-uinput. Sérieux.</p>
</blockquote>
<p>Bon, très bien, nous allons utiliser libevdev-uinput pour simuler un clic. </p>
<p>Comme pour la section précédente, Peter fait une très bonne présentation sur son article, et je vais vous la faire à ma sauce. Les exemples d’utilisations de libevdev et libevdev-uinput ne courent pas spécialement les rues d’internet alors ça ne peut pas faire trop de mal.</p>
<p>On peut créer un périphérique d’entrée virtuel de zéro, en spécifiant toutes ses caractéristiques, et notamment les types d’évènement qu’il est capable de générer. Mais en fait, il y a une manière plus simple de faire : il est possible de copier un périphérique existant, tout simplement. Et ça tombe bien, parce qu’on en a déjà un sous la main qu’on utilise déjà : c’est l’écran tactile. En plus, ça permettra vraiment de simuler exactement ce qu’il se serait passé si on avait nous-même touché l’écran tactile au bon endroit (c’est-à-dire, là où il est mort, si vous suivez), et Phosh n’y verra que du feu.</p>
<p>On va reprendre la ligne qui charge notre dalle tactile :</p>
<pre><code class="c"> <span class="n">rc</span> <span class="o">=</span> <span class="n">libevdev_new_from_fd</span><span class="p">(</span><span class="n">fd</span><span class="p">,</span> <span class="o">&</span><span class="n">dev</span><span class="p">);</span></code></pre>
<p>Le périphérique est chargé dans la structure <code>dev</code> si l’opération a réussi.</p>
<p>On va lui donner un nom à l’aide de la fonction <code>libevdev_set_name</code> et le copier dans une nouvelle structure semblable, <code>uidev</code>, à l’aide de la fonction <code>libevdev_uinput_create_from_device</code>.</p>
<p>On déclare la structure au début de la fonction main avant toute utilisation de <code>goto</code> :</p>
<pre><code class="c"> <span class="k">struct</span> <span class="n">libevdev_uinput</span><span class="o">*</span> <span class="n">uidev</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span></code></pre>
<pre><code class="c"> <span class="n">libevdev_set_name</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="s">"Fake device clicking on the top of the screen"</span><span class="p">);</span>
<span class="n">rc</span> <span class="o">=</span> <span class="n">libevdev_uinput_create_from_device</span><span class="p">(</span><span class="n">dev</span><span class="p">,</span> <span class="n">LIBEVDEV_UINPUT_OPEN_MANAGED</span><span class="p">,</span> <span class="o">&</span><span class="n">uidev</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">rc</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Failed to create fake device (%s)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">strerror</span><span class="p">(</span><span class="o">-</span><span class="n">rc</span><span class="p">));</span>
<span class="k">goto</span> <span class="n">out</span><span class="p">;</span>
<span class="p">}</span></code></pre>
<p>Faudra pas oublier de libérer le périphérique dans la section <code>out</code> de <code>main</code>:</p>
<pre><code> if (uidev != NULL) {
libevdev_uinput_destroy(uidev);
}
</code></pre>
<p>On va passer à uidev à <code>handle_event</code> pour qu’elle puisse la passer à simclick:</p>
<ul>
<li>
<code>handle_event(&ev);</code> devient <code>handle_event(&ev, uidev);</code>
</li>
<li>
<code>static int handle_event(struct input_event *ev)</code> devient <code>static int handle_event(struct input_event *ev, struct libevdev_uinput* uidev)</code>
</li>
<li>
<code>simclick();</code> devient <code>simclick(uidev);</code>
</li>
</ul>
<p>La fonction <code>simclick</code> est assez bête. J’ai pris le <a href="https://gitlab.freedesktop.org/libevdev/libevdev/blob/master/tools/libevdev-events.c">programme d’exemple de Peter</a>, je l’ai compilé, je l’ai lancé et j’ai appuyé sur mon écran tactile. J’ai pu voir tous les évènements qui étaient générés et j’ai bêtement copié tout ça en adaptant les coordonnées de l’évènement pour que ça clique au bon endroit. Petite subtilité avec le <em>tracking id</em> pour discerner les évènements générés :</p>
<pre><code class="c"><span class="k">static</span> <span class="kt">void</span> <span class="nf">simclick</span><span class="p">(</span><span class="k">struct</span> <span class="n">libevdev_uinput</span><span class="o">*</span> <span class="n">uidev</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">static</span> <span class="kt">int</span> <span class="n">tracking_id</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">15</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">15</span><span class="p">;</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_MT_SLOT</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_MT_TRACKING_ID</span><span class="p">,</span> <span class="n">tracking_id</span><span class="o">++</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_MT_POSITION_X</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_MT_POSITION_Y</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_MT_TOUCH_MAJOR</span><span class="p">,</span> <span class="mi">22</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_MT_WIDTH_MAJOR</span><span class="p">,</span> <span class="mi">22</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_KEY</span><span class="p">,</span> <span class="n">BTN_TOUCH</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_X</span><span class="p">,</span> <span class="n">x</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_Y</span><span class="p">,</span> <span class="n">y</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_SYN</span><span class="p">,</span> <span class="n">SYN_REPORT</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_ABS</span><span class="p">,</span> <span class="n">ABS_MT_TRACKING_ID</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_KEY</span><span class="p">,</span> <span class="n">BTN_TOUCH</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="n">libevdev_uinput_write_event</span><span class="p">(</span><span class="n">uidev</span><span class="p">,</span> <span class="n">EV_SYN</span><span class="p">,</span> <span class="n">SYN_REPORT</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="p">}</span></code></pre>
<p>… C’est… laborieux, mais pas très compliqué.</p>
<p>Et voilà, on a fini !<br>
Si vous lancez le programme, si tout va bien, vous pourrez voir votre périphérique virtuel apparaitre dans la liste produite par la commande <code>libinput list-devices</code> :</p>
<pre><code>Device: Goodix Capacitive TouchScreen
Kernel: /dev/input/event2
Group: 3
Seat: seat0, default
Capabilities: keyboard touch
Tap-to-click: n/a
Tap-and-drag: n/a
Tap drag lock: n/a
Left-handed: n/a
Nat.scrolling: n/a
Middle emulation: n/a
Calibration: identity matrix
Scroll methods: none
Click methods: none
Disable-w-typing: n/a
Accel profiles: n/a
Rotation: n/a
…
Device: Fake device clicking on the top of the screen
Kernel: /dev/input/event6
Group: 6
Seat: seat0, default
Capabilities: keyboard touch
Tap-to-click: n/a
Tap-and-drag: n/a
Tap drag lock: n/a
Left-handed: n/a
Nat.scrolling: n/a
Middle emulation: n/a
Calibration: identity matrix
Scroll methods: none
Click methods: none
Disable-w-typing: n/a
Accel profiles: n/a
Rotation: n/a
</code></pre>
<p>Les plus attentifs et les plus attentives auront remarqué qu’on ne supprime jamais les évènements initiaux correspondant aux trois doigts appuyés sur l’écran tactile. Et, oui, il s’agit d’une limitation. Je ne sais pas (encore) faire. Il y a peut-être moyen d’enregistrer notre périphérique virtuel et de bloquer le vrai périphérique et de filtrer les bons évènements. Il ne faut probablement pas tous les filtrer, mais peut-être juste les évènements <code>BTN_TOUCH</code> par exemple si ça suffit (peut-être pas). Sinon, ça pourrait avoir des effets de bords indésirables. Donc oui, si je ne fais pas attention, je déclenche des clics dans les applications actuellement affichées sur l’écran.</p>
<p>Note : contrairement à juste capter des évènements, simuler un périphérique nécessite d’être root (ou peut-être d’appartenir au bon groupe, mais je n’ai pas trop creusé).</p>
<h2 id="toc-compilation-et-installation">Compilation et installation</h2>
<p>C’est pas le tout, mais maintenant, il faut que le programme tourne et se lance au démarrage. Déjà, il faut installer le paquet de développement de libevdev (libevdev-dev chez les debianeux, libevdev-devel chez les rpmistes).</p>
<p>Puis, on compile et on installe :</p>
<pre><code>gcc simclick.c $(pkg-config --libs --cflags libevdev) -o simclick
sudo cp simclick /usr/local/bin/simclick
</code></pre>
<p>On fait un service systemd :</p>
<pre><code class="bash">cat > /etc/systemd/system/simclick.service <span class="s"><<EOF</span>
<span class="s">[Unit]</span>
<span class="s">Description=Simulate top click using three fingers</span>
<span class="s">ConditionFileIsExecutable=/usr/local/bin/simclick</span>
<span class="s">After=phosh.service</span>
<span class="s">[Service]</span>
<span class="s">Type=simple</span>
<span class="s">ExecStart=/usr/local/bin/simclick</span>
<span class="s">RemainAfterExit=no</span>
<span class="s">[Install]</span>
<span class="s">WantedBy=multi-user.target</span>
<span class="s">EOF</span></code></pre>
<p>(je réalise qu’il faudra adapter ce <code>After=phosh.service</code>, d’ailleurs, et peut-être trouver une autre cible pour le rendre plus générique, là ça le rend spécifique à Phosh)</p>
<p>Et au redémarrage, ça marche tout seul.</p>
<h2 id="toc-future-work">Future work</h2>
<p>(J’aurais pu titrer « Pistes d’amélioration » mais allez, ça me fait plaisir de nommer cette section comme ça.)</p>
<p>Pour l’instant j’utilise Phosh, mais je compte à plus ou moins court terme passer à Plasma Mobile, qui est d’ailleurs maintenant l’environnement par défaut du PinePhone (quelques trucs bloquants mais de moins en moins, et tant mieux, parce ça me convient mieux. Mais du coup, l’interaction sur la barre d’état pour la dérouler est vraiment un glisser vers le bas comme sous Android, donc la fonction <code>simclick</code> sera autrement plus compliquée. Mais ça ne devrait pas être trop difficile à faire, surtout qu’on peut enregistrer les évènements et presque les copier bêtement dans le code.</p>
<p>On pourrait s’amuser à rendre l’interaction plus intuitive en permettant demandant à ce que l’utilisateur fasse un glissé, peut-être avec deux doigts seulement. On peut imaginer tout un tas d’interactions pratique qui ne sont pas fournies par l’environnement. Il faut cependant trouver le moyen de garder la fonction <code>handle_event</code> lisible et claire, parce que pour avoir un peu tester, ça devient vite le bronx. Ou organiser autrement : faire une fonction par interaction. Pas toujours simple parce que parfois il y a des conflits. Tout bêtement, après un glissé, vous ne voulez pas déclencher l’action déclenchée par un touché simple. </p>
<p>Bon, on ne va pas se mentir, tout ça, c’est pour susciter votre esprit bidouilleur, mais restons les pieds sur terre : m’amuser avec des interactions tactiles sur le téléphone passera certainement après un tas de trucs que j’ai envie de faire donc il est peu probable que j’y passe un temps fou. À la base, c’est juste pour contourner cette zone morte de mon écran :-)</p>
<h2 id="toc-conclusion">Conclusion</h2>
<p>J’espère que vous avez apprécié ce journal. Si vous avez des questions ou des remarques, n’hésitez pas. En tout cas, ça fait un mois que j’utilise ce petit programme, sans accros ! Ça tourne et ça ne plante pas (ou, en tout cas, moins fréquemment que le téléphone lui-même !), et je m’y suis fait, j’aime plutôt bien taper sur l’écran avec trois doigts pour dérouler ce menu ! </p>
<p>Références :</p>
<ul>
<li>Le code complet décrit dans ce journal : <a href="https://paste.chapril.org/?37aacff5e147e0b5#FbqoSBgy89n12jEd3anFNx4CEca8FY5tZ5qfcdD4Bw2L">https://paste.chapril.org/?37aacff5e147e0b5#FbqoSBgy89n12jEd3anFNx4CEca8FY5tZ5qfcdD4Bw2L</a>
</li>
<li><a href="http://who-t.blogspot.com/2013/09/libevdev-handling-input-events.html">libevdev – handling input events</a></li>
<li><a href="https://who-t.blogspot.com/2013/09/libevdev-creating-uinput-devices.html">libevdev – creating uinput devices</a></li>
<li>Le code d’exemple de départ : <a href="https://gitlab.freedesktop.org/libevdev/libevdev/blob/master/tools/libevdev-events.c">https://gitlab.freedesktop.org/libevdev/libevdev/blob/master/tools/libevdev-events.c</a>
</li>
</ul>
<div><a href="https://linuxfr.org/users/raphj/journaux/simuler-un-clic-avec-libevdev-et-uinput.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/125293/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/raphj/journaux/simuler-un-clic-avec-libevdev-et-uinput#comments">ouvrir dans le navigateur</a>
</p>
raphjhttps://linuxfr.org/nodes/125293/comments.atomtag:linuxfr.org,2005:Diary/392402020-07-07T02:35:38+02:002020-07-07T02:35:38+02:001er retour sur le PinePhoneLicence CC By‑SA http://creativecommons.org/licenses/by-sa/4.0/deed.fr<h2 class="sommaire">Sommaire</h2>
<ul class="toc">
<li><a href="#toc-qualit%C3%A9-et-%C3%A9volution-du-mat%C3%A9riel">Qualité et évolution du matériel</a></li>
<li><a href="#toc-support-du-mat%C3%A9riel-et-drivers">Support du matériel et drivers</a></li>
<li>
<a href="#toc-offre-logicielle">Offre logicielle</a><ul>
<li><a href="#toc-ubuntu-touch">Ubuntu Touch</a></li>
<li><a href="#toc-postmarketos">PostmarketOS</a></li>
<li><a href="#toc-mobian">Mobian</a></li>
<li><a href="#toc-les-autres">Les autres</a></li>
</ul>
</li>
<li><a href="#toc-le-mot-de-la-fin">Le mot de la fin</a></li>
</ul>
<p>Salut Nal,</p>
<p>Comme ça fait bientôt 6 mois que je possède ce smartphone un peu particulier, et que ça m'a été demandé gentiment, je te propose une petite revue de la bête.</p>
<p>Pine64, entreprise bien connue des amateurs de bestioles à base de ARM, propose depuis des années des cartes de développement basées sur le <a href="https://fr.wikipedia.org/wiki/SoC" title="Définition Wikipédia">SoC</a> Allwinner A64. Ils ont eu l'idée saugrenue de fabriquer un smartphone sur les mêmes bases, en laissant comme à leur habitude le soin à la communauté de prendre en charge l'aspect logiciel.</p>
<p>Les caractéristiques du PinePhone sont les suivantes:</p>
<ul>
<li>Allwinner A64, donc (quad core Cortex-A53 + GPU Mali 400)</li>
<li>2 Go de RAM LPDDR3</li>
<li>eMMC 16Go</li>
<li>Écran tactile 5.95" (résolution 720x1440)</li>
<li>Modem 4G/LTE Quectel EG25</li>
<li>Contrôleur Wifi/Bluetooth Realtek 8723CS</li>
<li>Caméras avant (2MP) et arrière (5MP avec flash)</li>
<li>6 interrupteurs permettant de désactiver le modem, le wifi, les caméras ou le micro (le dernier permettant d'utiliser la sortie casque comme port série, indispensable pour le debug)</li>
</ul>
<p>Côté connectique, on a:</p>
<ul>
<li>1 emplacement pour carte SIM</li>
<li>1 slot micro-SD</li>
<li>1 port USB-C (USB 2.0 + HDMI/DisplayPort)</li>
</ul>
<p>Ce téléphone est proposé à 150$, auxquels il faudra ajouter les frais de port et, selon votre bonne étoile, les frais de douane.</p>
<p>Des caractéristiques qui n'ont donc pas de quoi inquiéter les ténors du marché, mais l'intérêt de ce smartphone n'est clairement pas la performance : il s'agit ici de garder le contrôle sur son informatique.</p>
<p>En effet, la quasi-totalité des OS disponibles sont entièrement libres (y compris les drivers) et très peu de blobs binaires sont nécessaires : seul le module Wifi/BT a besoin d'un firmware propriétaire ; les caméras sont utilisables avec uniquement du code libre, mais certaines fonctionnalités (autofocus notamment) peuvent ne pas fonctionner sans un firmware binaire additionnel.</p>
<h2 id="toc-qualité-et-évolution-du-matériel">Qualité et évolution du matériel</h2>
<p>Un premier point important, est que le PinePhone est fabriqué par "petites" séries (environ 5000 exemplaires), et son matériel évolue à chaque fois:</p>
<ul>
<li>Le premier batch est la version "Brave Heart" (rev. 1.1), pour les développeurs et utilisateurs n'ayant pas froid aux yeux</li>
<li>Ensuite est venue la version "UB Ports Community Edition" (rev. 1.2), corrigeant quelques défauts matériels gênants</li>
<li>La prochaine version sera la "PostmarketOS Community Edition" (rev. 1.2a), avec le remplacement de quelques composants mais un PCB normalement identique</li>
</ul>
<p>À noter également, les schémas électroniques sont disponibles au format PDF, mais il ne s'agit pas d'Open Hardware pour autant.</p>
<p>Sur la version 1.1 qui est la mienne, il manque une ligne de communication entre le modem et le SoC, ce qui complexifie la gestion de l'ensemble et diminue la fiabilité du tout: si le téléphone est mis en veille, il est tout à fait possible de rater un appel entrant (un gros travail est cependant en cours pour essayer de palier à ça)</p>
<p>La version 1.2 utilise 2 composants inadaptés au niveau du contrôleur USB-C, rendant l'utilisation de ce dernier impossible pour autre chose que charger le téléphone ou proposer des fonctionnalités de type "USB gadget".</p>
<p>La version 1.2a, si tout va bien, devrait être suffisamment aboutie pour ne plus souffrir de ces défauts de jeunesse.</p>
<p>En dehors de ces défauts de conception, et compte tenu du prix, la qualité est au rendez-vous, et je n'attends personnellement pas plus (ni moins !) d'un smartphone à moins de 200€, surtout si ce dernier me permet de faire tourner un Linux plus ou moins "standard".</p>
<p>Il y a toutefois de petites anecdotes "amusantes" (une fois qu'on a trouvé la solution), comme par exemple le signal audio qui "repisse" sur le port série, et peut amener quelques surprises si la fonctionnalité "Magic SysRq" est activée dans le kernel ;)</p>
<h2 id="toc-support-du-matériel-et-drivers">Support du matériel et drivers</h2>
<p>En parlant de kernel, tous les drivers nécessaires sont libres à 100% (y compris pour le GPU grâce au driver libre <code>lima</code>), bien que pas toujours intégrés au noyau <em>mainline</em>. Il y a cependant un gros travail en cours sur ce sujet, et chaque version majeure de Linux apporte son lot de nouveaux drivers pour ce smartphone. Le noyau de référence est disponible sur <a href="https://gitlab.com/pine64-org/linux">Gitlab</a>.</p>
<p>S'agissant d'un système ARM, le noyau est chargé comme souvent par le bootloader U-boot, nécessitant lui aussi quelques patches ne s'étant pas frayé un chemin vers la version mainline, et maintenu lui aussi sur <a href="https://gitlab.com/pine64-org/u-boot">Gitlab</a>. On trouve aussi <code>ARM Trusted Firmware</code>, pour lequel aucun patch n'est nécessaire depuis la version 2.3 sortie en avril.</p>
<p>Enfin, le A64 intègre un coeur OpenRISC <a href="https://linux-sunxi.org/AR100">AR100</a> pouvant être utilisé comme <a href="https://developer.arm.com/documentation/dui0922/latest/introduction/the-system-control-processor">System Control Processor</a> et nécessitant son propre firmware. Il existe une <a href="https://github.com/crust-firmware/crust">implémentation libre</a> de celui-ci, visant à permettre la mise en veille du système ("Suspend-to-RAM")</p>
<p>Ceci dit, tout ne fonctionne pas à l'heure actuelle et certains problèmes critiques n'ont toujours pas de solution fiable:</p>
<ul>
<li>les caméras commencent tout juste à être supportées à peu près correctement</li>
<li>le driver de l'USB-C n'est pas encore au point</li>
<li>le Wifi fait parfois des siennes lorsque 2 AP servent le même réseau</li>
<li>la gestion de l'alimentation reste le plus gros point noir, puisque la durée de vie de la batterie est de l'ordre de 4 heures (monte à 14h avec la mise en veille, mais avec le risque de "perdre" le modem au réveil, un reboot étant alors nécessaire).</li>
</ul>
<h2 id="toc-offre-logicielle">Offre logicielle</h2>
<p>Comme dit précédemment, la majorité des systèmes disponibles pour ce smartphone sont libres et basés sur GNU/Linux au lieu de l'habituel Android. On retrouve donc un choix conséquent et riche dans lequel chacun pourrait trouver son compte. Je ne cite ici que les plus gros projets, sachant que j'en ai utilisé très peu au final.</p>
<h3 id="toc-ubuntu-touch">Ubuntu Touch</h3>
<p>Maintenu par la communauté <a href="https://ubports.com/fr/">UBPorts</a> depuis que Canonical a jeté l'éponge, c'est sans doute le plus avancé des Linux mobiles, mais aussi le plus "particulier", justement en raison de sa filiation avec Ubuntu (serveur graphique Mir, système de fichiers en lecture seule nécessitant l'utilisation de containers "Libertine" pour installer des applications "classiques"…).</p>
<p>C'était le premier OS complet disponible sur PinePhone à ma connaissance, et ses développeurs ont largement contribué à faire avancer le support matériel et bien défriché le chemin pour les suivants, gloire leur soit rendue !</p>
<h3 id="toc-postmarketos">PostmarketOS</h3>
<p>Basé sur Alpine Linux et pensé au départ pour donner une seconde vie à nos vieux smartphones délaissés par leurs fabricants, <a href="http://postmarketos.org/">PostmarketOS</a> est plus proche d'une distribution Linux classique. Il propose un script (<code>pmbootstrap</code>) permettant de générer une image customisée avec l'environnement graphique de votre choix et l'installer directement sur le téléphone.</p>
<h3 id="toc-mobian">Mobian</h3>
<p>Mon préféré, et pour cause : je suis l'initiateur et mainteneur de ce projet.</p>
<p><a href="https://mobian-project.org/">Mobian</a> se veut être une version de Debian dédiée aux appareils mobiles, l'idée étant de se baser sur Debian Bullseye (l'actuelle testing) et ne fournir que les packages manquants (kernel et environnement graphiques) ou nécessitant des modifications (u-boot, gtk, certaines applications GNOME pour lesquelles les patches ne peuvent être acceptés upstream pour le moment).</p>
<p>On y retrouve donc tous les paquets présents dans Debian, et l'environnement graphique choisi est <a href="https://developer.puri.sm/Librem5/Software_Reference/Environments/Phosh.html">Phosh</a>, développé par Purism (gloire à eux aussi !) pour leur <a href="https://fr.wikipedia.org/wiki/Librem%205" title="Définition Wikipédia">Librem 5</a>, donnant une expérience proche de GNOME (dont proviennent d'ailleurs la majorité des applications).</p>
<h3 id="toc-les-autres">Les autres</h3>
<p>Il existe quantité d'autres projets, pour la plupart basés sur des distributions existantes, qu'elles soient spécialisées (Maemo Leste, LuneOS, Nemo Mobile) ou généralistes (Fedora, OpenSUSE, Arch, Manjaro), sans parler d'initiatives plus particulières comme SXMO basé sur le <em>window manager</em> <a href="http://dwm.suckless.org/">dwm</a>, aussi je t'invite à te rendre sur le <a href="https://forum.pine64.org/forumdisplay.php?fid=121">forum de Pine64</a> où tu trouveras une mine d'infos et de projets divers et variés.</p>
<h2 id="toc-le-mot-de-la-fin">Le mot de la fin</h2>
<p>Alors concrètement, ça donne quoi un PinePhone au quotidien ? Eh bien, j'utilise le mien comme téléphone principal depuis bientôt 4 mois sans trop de difficultés pour les fonctions liées à la téléphonie (SMS et appels téléphoniques) et le web, sachant que je ne suis que très rarement loin d'une prise secteur (du coup l'autonomie limitée m'impacte peu).</p>
<p>Certaines fonctions "essentielles" sont encore manquantes ou mal gérées (sauf peut-être sous Ubuntu Touch) : au-delà des photos, l'agenda n'est toujours pas utilisable, tout comme les alarmes ; les MMS ne sont pas supportés non plus, et il reste encore de nombreux bugs un peu partout dans le système.</p>
<p>Le manque d'applications peut aussi parfois être un problème, mais de nouvelles sont adaptées ou développées en permanence, et les choses devraient encore s'améliorer avec les sorties attendues de GTK 4 et GNOME 3.38.</p>
<p>En conclusion, le PinePhone est loin d'être prêt pour le grand public (ça tombe bien, ce n'est pas sa cible), et il ne peut pas être utilisé comme téléphone principal si vous avez besoin de compter dessus. En revanche, c'est une plateforme formidable pour développer et une réelle satisfaction de pouvoir maitriser son OS et se tenir loin des siphons à données personnelles habituels.</p>
<p>Je m'arrête là parce qu'il se fait tard, mais il y aurait encore tellement à dire, donc n'hésite pas à me relancer dans les commentaires ;)</p>
<p>Bonne nuit Nal !</p>
<div><a href="https://linuxfr.org/users/a-wai/journaux/1er-retour-sur-le-pinephone.epub">Télécharger ce contenu au format EPUB</a></div> <p>
<strong>Commentaires :</strong>
<a href="//linuxfr.org/nodes/121009/comments.atom">voir le flux Atom</a>
<a href="https://linuxfr.org/users/a-wai/journaux/1er-retour-sur-le-pinephone#comments">ouvrir dans le navigateur</a>
</p>
a-waihttps://linuxfr.org/nodes/121009/comments.atom