Glane

Couche capteurs et publication de périphériques pour QNX 8.0 — récolter ce que les capteurs donnent, sans rien perdre.

QNX Global Hackathon · catégorie Low-level Software · dépôt Tradoooo/glane · généré le

Aperçu

Un capteur — réel sur Raspberry Pi 5 ou simulé sous QEMU — est décrit dans un fichier, découvert, calibré, publié dans l'arborescence du système avec horodatage à la source, et sa latence de publication est mesurée et bornée, sans écrire un gestionnaire de ressources à la main.

Le framework existe, l'écosystème n'existe pas

QNX livre un mécanisme de publication de périphériques et un seul publisher (usblauncher_otg, orienté USB/stockage/média). Rien pour les capteurs. Glane ne réinvente pas le mécanisme : il fournit ce qui manque pour s'en servir.

Tout doit être simulable

Aucune simulation sans matériel n'est documentée. Le publisher virtuel est à la fois l'outil de démonstration, le harnais de test en CI, et la raison pour laquelle le projet est vérifiable avant d'avoir une carte.

Mesurer plutôt qu'affirmer

Rien n'est dit sur la latence de publication. Le banc horodaté (source → livraison → abonné) transforme une affirmation en chiffre. Aucun chiffre n'est publié sans sortir de glat.

Les trous exploités (tous sourcés dans la documentation QNX)

Démo live — publisher virtuel

Portage fidèle en JavaScript du générateur synthétique (core/src/virtuel.c) et de la calibration entière (core/src/calib.c, en BigInt). Même table sinusoïdale Q15, même hachage de bruit, même Horner : ce que vous voyez est ce que produit le C, à la mesure près.

Capteur

Calibration

Livraison

Mesures

Qualité

ok saturated stale fault

Latence source → livraison (comme glat)

Déterminisme

Empreinte FNV-1a du journal :

Journal (format CONTRACT §7)


    

Émulateur QNX 8.0 — preuve réelle

Glane compile et s'exécute sur la cible réelle. Le socle core/ (C11 pur) et glaned sont compilés avec qcc (QNX SDP 8.0, variante gcc_ntox86_64), sans aucun warning. Puis une image QNX 8.0 minimale est amorcée dans qemu-system-x86_64 (via -kernel, sans disque ni réseau) et glaned y publie réellement ses mesures : des objets value, quality, seq, ts_ns, unit, info écrits dans l'espace de noms de l'invité, puis relus par ls/cat. L'invité affiche son vrai uname (QNX 8.0), la vraie liste de processus (pidin), et laisse un shell ksh interactif. C'est la « preuve d'usage QNX » exigée par le règlement : du code qui construit et tourne vraiment sur QNX 8.0, pas un simple nom dans le README — et la commande d'amorçage est reproduite ci-dessous.

Preuve de compilation (qcc, QNX SDP 8.0)



  

L'invité QNX 8.0, en direct (vitrine web)

Sur le poste de travail pc, un invité QNX 8.0 réel tourne sous QEMU : glaned y publie ses mesures dans /dev/shmem, un gestionnaire de ressources QNX les réexpose dans /dev/sensors, et un shell ksh attend les touches envoyées par les boutons ci-dessous. La capture de gauche est la console VGA de l'invité ; à droite, la console série où se déroule la publication.

écran de l'invité QNX 8.0 de Glane
connexion…

Vitrine : baptiste-ms-7d18.tail3a8bdf.ts.net:10000 — invite amorcée par -kernel sur l'IFS build-qnx/glane-vitrine-ifs.bin, sans disque ni réseau. Dans l'invité : ls /dev/shmem, cat /dev/shmem/temp-chassis.info.

Fonctionnalités

Tout ce que le dépôt contient aujourd'hui, groupé par nature. Chaque carte cite les exigences (GLA-xx) qu'elle couvre.

Preuves

Chiffres produits en exécutant le code du dépôt (site/gen_data.py), pas recopiés à la main.

Vérifications C par module

Journaux réels (sortie de glaned-sim)



  

Latences mesurées (sortie de glat)

Test de mutation (glane_mutate.py)

Test différentiel C ↔ Python (GLA-05)

Contrat gelé

CONTRACT.md fait foi. Les en-têtes de core/include/glane/ fixent les signatures. Ni les agents ni les contributeurs ne le modifient : ils l'implémentent.

ABI de la mesure — 24 octets

typedef struct {
  uint32_t sensor_id;     /* identifiant issu de la description          */
  uint32_t seq;           /* séquence monotone, jamais réinitialisée      */
  int64_t  ts_ns;         /* horodatage à la source (CLOCK_MONOTONIC)     */
  int32_t  value_milli;   /* valeur en milli-unités (jamais de flottant)  */
  uint16_t unit;          /* GLANE_UNIT_* : C, K, V, mA, deg/s, g, rpm…   */
  uint8_t  quality;       /* OK | STALE | SATURATED | FAULT | UNCERTAIN   */
  uint8_t  flags;         /* FIRST | CALIBRATED | INJECTED | SIMULATED    */
} glane_sample;           /* 24 octets, aucun pointeur */

quality décrit la mesure ; flags décrit son origine. Les mélanger rendrait le rejeu ambigu. L'échelle entière en milli-unités permet au jumeau Python de rejouer la calibration bit à bit.

Arborescence publiée

/dev/sensors/<name>/{value,quality,seq,ts_ns,unit,info}
/dev/sensors/<name>/command/{period,calibrate,inject,selftest}

Nom de capteur : non vide, ≤ 63 octets, charset [a-z0-9._-], sans point initial ou final. Validé côté C (schema.c) avant publication et côté hôte (gschema.py) sur une arborescence réelle — même contrat.

Journal de mesures


  

ts_ns = horodatage à la source ; d_ns = horodatage de livraison. La latence est d_ns − ts_ns : c'est ce que mesure glat.

Calibration

Polynôme de degré ≤ 3, coefficients entiers échelle 10^6, accumulateur __int128. Le terme constant a0 est en milli-unités, a1 est un gain sans dimension. Bornes validées à l'analyse : |x| ≤ 1 048 575, |coef[i]| ≤ 1 048 575 — aucun terme de degré 3 ne déborde.

Outils

Tout est en C11 (socle + outils hôte) ou en Python 3 stdlib uniquement. Aucune dépendance externe.

Exigences (GLA-01 … GLA-24)

Trois niveaux d'ambition : S socle (indispensable à une soumission), C complet (la version visée), X extrême. L'état est dérivé de la matrice de traçabilité.

Matrice de traçabilité

Générée par scripts/glane_trace.py : chaque exigence est reliée aux fichiers et aux tests qui la citent.

100 idées pour aller plus loin

4 lots de 25, sans doublon avec le cahier des charges ni les 25 leviers déjà publiés. Les idées marquées ⭐ sont implémentées. Filtrez par direction ou par lot.

Documentation