Une implémentation de printf() embarqué avec contexte

Je ne connais pas de logiciel embarqué sans une utilisation de printf(), au moins pour des besoins de débogage. La version proposée ici permet de sortir des données sur différents périphériques dans un même logiciel.

Présentation

Soit on utilise la fonction de la librairie standard, soit une fonction “maison” si on a besoin d’optimisation, par exemple en retirant le support des flottants.

Beaucoup d’implémentations utilisent un gros buffer, forcément limité, pour traiter le traitement du formattage. C’est dommage, surtout dans l’embarqué où la RAM est souvent limitée. La version que je vous propose sort les charactères à la volée, c’est à dire directement après traitement, donc l’usage en RAM est très limité.

En outre, il est souvent pratique de sortir du printf() vers de multiples périphériques : un UART, un écran LCD, un module RF, un fichier en émoire Flash … Ma version de printf() se base donc sur un contexte d’entrée permettant de garder un coeur de code générique.

A noter que je n’ai pas implémenté en lui-même le traitement du formattage, vous trouverez beaucoup d’implémentations différentes. Vous pouvez à loisir le changer, en essayant de choisir une implémentation sans buffer tampon.

Le code

Le code est disponible là :

github

Voici un exemple d’usage :

#include <stdio.h>

#include "sys_printf.h"

static void display_print_to_screen(const char *format, ...);

int main(void)
{
	display_print_to_screen("Hello, %s!\r\n", "firmware");

	return 0;
}

static void custom_print(char c)
{
	putchar(c);  // custom putchar (uart_writechar(), lcd_write_char() ...)
}

static void display_print_to_screen(const char *format, ...)
{
	sys_print_ctx_t printCtx; // our printf context

	printCtx.pPutc = custom_print; // specific putchar for that interface
	printCtx.len = 0; // init to zero, character counter
	printCtx.maxLen = 255; / max length to push

	int *varg = (int *) (&format);

	(void)sys_printf(&printCtx, 0, varg);
}

Créer facilement un hotspot 4G sur Raspberry PI

Certes, il est plus facile d’acheter un hotspot tout fait, mais j’en ai vraiment marre des produits dont le support finit toujours par terminer sans plus aucune mise à jour de la part du fabricant. Je préfère donc opter pour un système plus souple et OpenSource. Mon usage de ce hotspot 4G : ligne internet pro de secours, hotspot multimédia pendant le week-end.

Matériel

Pour ce projet, il faut rassembler :

  • Un Raspberry PI 2 (avec clé WiFi) ou 3, avec un boîtier quelconque
  • Cable ethernet (pour la mise en service)
  • cable liaison série/USB FTDI ou clavier/écran ou en SSH (paramétrage initial)
  • Dongle 4G Huawei e3372

hotspot

J’aime bien utiliser un câble FTDI pour me brancher sur le PI, ce qui permet d’avoir la console Linux même sans réseau. Et c’est plus pratique que de jongler avec un clavier/écran supplémentaire.

Pour le branchement du câble série FTDI, il faut brancher le Tx du Pi sur le Rx du module USB, et le Rx du Pi sur le Tx du module, puis brancher la masse. Le brochage est inscrit au dessus du connecteur du module, en tout petit !

hotspot

Concernant le dongle, le Huawei est très bien et a l’avantage de fonctionner sans aucune manipulation sous Linux. J’ai acheté une version directement sur AliExpress avec une antenne amplificatrice intérieure.

hotspot

Logiciel

Pour flasher une image Raspian, j’ai utilisé l’utilitaire Etcher, disponible pour Linux, Windows et MacOS (https://etcher.io/). Concernant la distribution, préférez une Raspbian Lite, sans interface graphique (https://www.raspberrypi.org/downloads/raspbian/).

hotspot

Sous Windows, TeraTerm est très bien, aussi bien pour la liaison série que le SSH. Ne mettez pas l’écho car la console Linux le fait.

Concernant la connexion par SSH, récupérez l’adresse IP du Raspberry PI assignée par votre box/routeur. Attention par défaut le SSH est désactivé sur la raspian lite. Il faut créer un fichier (vide) se nommant juste ‘ssh’, sans extension, à la racine de la carte SD (partition boot) pour l’activer. Question de sécurité !

Voici ma configuration de TeraTerm pour que la console soit plus lisible :

hotspot hotspot hotspot

Mise en oeuvre

Préparation

Branchez d’abord votre clé Huawei sur un PC Windows (je n’ai pas testé sur un Linux), on a ainsi accès à une page web intégrée permettant de paramétrer le code PIN et le réseau préféré. Dans le cas de Free, imposez du LTE (4G) uniquement pour bénéficier du quota 4G maximal et éviter le hors forfait en 3G dont le quota est bien plus limité (3Go !).

J’ai également coché l’option permettant de ne pas demander le code PIN.

Branchez les périphériques

Branchez la clé Huawei et, si vous avez un Raspberry PI 2, un dongle Wifi compatible.

Point d’accès Wifi

Connectez-vous comme vous voulez, voici les paramètres de connexion :

  • login : pi
  • pass : raspberry

Tout d’abord, il faut installer le paquet suivant, le démon en tâche de fond réalisant la passerelle proprement dite :

sudo apt-get install hostapd

Nous allons ensuite installer une interface graphique de paramétrage (https://github.com/billz/raspap-webgui) :

wget -q https://git.io/voEUQ -O /tmp/raspap && bash /tmp/raspap
sudo apt-get install hostapd

Par défaut, nous avons les paramètres suivants :

IP address: 10.3.141.1
	Username: admin
	Password: secret
DHCP range: 10.3.141.50 to 10.3.141.255
SSID: raspi-webgui
Password: ChangeMe

Après redémarrage, un réseau wifi apparaît :

hotspot

Connectez-vous à l’aide des paramètres ci-dessus et changez ce qu’il vous plaît (le SSID Wifi, le mot de passe …)

hotspot

Packager vos applications Qt sous Linux

Il fut un temps où il fallait générer des packages pour chaque distribution (Ubuntu, Fedora, Arch …) en utilisant à chaque fois un format spécifique et des commandes alamniquées au possible. De plus, il fallait également suivre de près les évolutions de chaque distribution pour la gestion des dépendances. Horrible, surtout lorsque l’on est seul. Heureusement, les temps ont changé !

Les concurrents

Si la génération de packages au format des distribution a un sens si votre application est officiellement supportée (suivi des patchs de s&écurité, partage des librairies …), cela n’as pas vraiment grand intérêt lorsque vous voulez distribuer une application seule par votre propre canal de diffusion.

Depuis quelques années, nous voyons plusieurs formats concurrents permettant de générer un package “tout compris” contenant votre exécutable et toutes les ressources tierces nécessaires à son fonctionnement (images, sons, librairies dynamiques …). Cependant, ces nouveaux standards ne reposent pas tous sur la même architecture. On notera donc :

  • AppImage
  • Snap (le format créé par Ubuntu)
  • Flatpak

Pour la comparaison entre les trois, je vous redirige vers des tableaux comparatifs très bien faits, ici : https://github.com/AppImage/AppImageKit/wiki/Similar-projects

Préparations

Tout d’abord, il faut télécharger une application, au format AppImage justement, qui permet de générer notre package. C’est le pendant Linux des outils windeployqt et macdeployqt disponibles en standard dans votre installation de Qt pour respectivement Windows et MacOS. Il s’agit de linuxdeployqt : https://github.com/probonopd/linuxdeployqt.

Une fois téléchargé, ajoutez la propriété “exécutable” au fichier, soit via votre gestionnaire de fichier, soit en ligne de commandes (chmod +x linuxdeployqt-continuous-x86_64.AppImage)

libpst

Ensuite, compilez votre application en release puis créer une arborescence

└── usr
    ├── bin
    │   └── your_app
    ├── lib
    └── share
        ├── applications
        │   └── your_app.desktop
        └── icons
            └── <theme>
                └── <resolution>
                    └── apps
                        └── your_app.png

Remplacer et par le standard Freedesktop. Voici une série de commandes permettre de créer le squelette :

mkdir -p usr/bin
mkdir -p usr/lib
mkdir -p usr/share/applications
mkdir -p usr/share/icons/hicolor/512x512

Voici notre fichier contenant les informations standards, toujours en suivant les recommandations de Freedesktop :

[Desktop Entry]
Type=Application
Name=Ultimate QR Code
Comment=QR Code generator
Exec=UltimateQRCode
Icon=ultimateqrcode_logo
Categories=Graphics;2DGraphics;

Au final, voici notre arborescence :

usr/
├── bin
│   └── UltimateQRCode
├── lib
└── share
    ├── applications
    │   └── ultimateqrcode.desktop
    └── icons
        └── hicolor
            └── 512x512
                └── ultimateqrcode_logo.png

7 directories, 3 files

Exécution

Maintenant, lançons la commande de génération, attention c’est un peu longuet, surtout à la première exécution. J’ai rencontré plusieurs difficultés ici :

  • Ayant Qt d’installé sur le système ET dans mon répertoire ‘home’, il faut préciser à l’outil lequel utiliser (sans le tilde, il ne fait pas l’expansion du chemin comme bash)
  • Il faut l’option -qmldir si vous utilisez QML (comme dans notre exemple), et pointer vers la racine de votre dépôt de sources
  • J’ai échoué quelques fois sur la syntaxe du fichier .desktop, c’est pénible car la vérification est faite vers la fin

Voici la commande utilisée :

~/Applications/linuxdeployqt-continuous-x86_64.AppImage usr/share/applications/ultimateqrcode.desktop -qmake=/home/anthony/Qt/5.11.1/gcc_64/bin/qmake -appimage -qmldir=/home/anthony/git/ultimateqrcode/

Oui ça fait peur, la commande a tendance à ne rien faire pendant longtemps mais ça finit par terminer, avec succès on espère. Pour ma part, j’ai un fichier nommé Ultimate_QR_Code-x86_64.AppImage, et qui fonctionne ! Notez qu’il est mis “exécutable” automatiquement par le script.

Enfin, j’ai demandé à ce que mon application, UltimateQRCode, soit référencée dans AppImageHub, un projet communautaire de référencement d’applications au format AppImage (Flatpak et Snap ont des équivalents). Que reste-t-il à faire ? Un petit script Bash regroupant toutes ces étapes à partir du dossier source !

Retrouvez l’application pour Linux - N’IMPRTE LEQUEL ! - ici : https://github.com/arabine/ultimateqrcode/releases/download/latest/Ultimate_QR_Code-x86_64.AppImage

libpst