Bibliothèque de rendu pure pour les écrans OSSM — pages de texte, chaînes de caractères, icônes et tests visuels
Aperçu
La bibliothèque lib/ui est une couche de rendu pure qui dessine les écrans OSSM dans un tampon U8g2. Elle n'a aucune dépendance matérielle, pas de FreeRTOS ni de mutex – elle prend un pointeur u8g2_t* et dessine des pixels. La sécurité des threads et les E/S d’affichage sont gérées par le service d’affichage.
Cette séparation signifie que la bibliothèque peut fonctionner en natif (x86) pour des tests visuels automatisés sans ESP32.
Dépendances : U8g2, QRCode
Source : Software/lib/ui/src/
TextPage
TextPage est la structure principale pour les écrans basés sur le contenu. Elle couvre les pages d'aide, les écrans d'erreur, l'état de la mise à jour, la configuration WiFi, le couplage – tout ce qui est principalement du texte avec des codes QR en option.
struct TextPage {
const char* title = nullptr;
const char* subtitle = nullptr;
const char* body = nullptr;
const char* bottomText = nullptr;
const char* qrUrl = nullptr;
uint8_t qrVersion = 3;
int qrScale = 2;
bool centerBody = false;
int scrollPercent = -1;
};Tous les champs sont facultatifs. Définissez uniquement ce dont vous avez besoin.
| Champ | Type | But |
|---|---|---|
title | const char* | Texte en gras en haut, avec une ligne de séparation en dessous |
subtitle | const char* | Texte de graisse moyenne ou en gras sous le titre ; se divise automatiquement si trop large |
body | const char* | Texte avec retour automatique à la ligne ; prend en charge \n comme saut de ligne |
bottomText | const char* | Épinglé en bas de l'écran (y=62) |
qrUrl | const char* | Code QR affiché en bas à droite ; limite la largeur du texte |
qrVersion | uint8_t | Version QR (par défaut 3) |
qrScale | int | Échelle de pixels QR (par défaut 2) |
centerBody | bool | Centrer le corps du texte |
scrollPercent | int | Afficher l'indicateur de défilement (0 à 100) ; -1 pour le masquer |
Ordre de rendu
drawTextPage() effectue le rendu dans cet ordre :
- Effacer le plein écran (en-tête + page + pied de page)
- Code QR — coin inférieur droit, réduit la largeur du texte disponible
- Titre — police en gras, suivie d'une ligne de séparation horizontale
- Sous-titre : essaie d’abord la graisse moyenne ; revient en gras ; est réparti sur deux lignes s’il est encore trop large
- Corps — avec retour automatique à la ligne via
drawWrappedText()si un titre est présent ; style de titre centré (drawStr::title) si le corps est le seul champ - Texte du bas — fixé à y=62
- Indicateur de défilement — barre de défilement sur le bord droit si
scrollPercent >= 0
Usage
// Use a predefined page
ui::drawTextPage(&u8g2, ui::pages::helpPage);
// Or build one inline
ui::TextPage page;
page.title = "Custom Title";
page.body = "Some content\nwith line breaks";
page.scrollPercent = 50;
ui::drawTextPage(&u8g2, page);Pages prédéfinies
TextPages.h définit les instances statiques TextPage dans l'espace de noms ui::pages. Elles utilisent des chaînes de caractères de Strings.h :
| Page | Champs utilisés |
|---|---|
helpPage | title, body, bottomText, qrUrl |
updateCheckingPage | body |
noUpdatePage | body, bottomText |
updatingPage | title, body |
errorPage | title |
wifiDisconnectedPage | title, body, bottomText, qrUrl |
wifiConnectedPage | title, body, bottomText |
pairingPage | title, body |
Exemple de définition :
static const TextPage helpPage = {
.title = helpTitle,
.body = helpBody,
.bottomText = helpBottom,
.qrUrl = helpQr,
};Chaînes de caractères
Toutes les chaînes d'interface utilisateur résident dans Strings.h sous l'espace de noms ui::strings. Elles sont stockées en mémoire flash à l'aide de PROGMEM :
static const char helpTitle[] PROGMEM = "Get Help";
static const char helpBody[] PROGMEM = "On Discord,\nor GitHub";Progmem.h définit PROGMEM comme une opération sans effet sur les plates-formes non Arduino, de sorte que les chaînes se compilent à la fois sur ESP32 et sur les compilations de test natives.
Catégories
| Catégorie | Exemples |
|---|---|
| Image de marque | researchAndDesire, kinkyMakers |
| Interface utilisateur générale | error, homing, idle, restart, settings, skip |
| Menus/modes | simplePenetration, strokeEngine, streaming, pairing, update, wifi |
| Commandes de mouvement | speed, stroke, sensation, depth, buffer, accel, max |
| Avertissements | speedWarning, homingTookTooLong, strokeTooShort |
| Aide | helpTitle, helpBody, helpBottom, helpQr |
| Mise à jour | updateChecking, noUpdateBody, updatingTitle, updatingBody |
| WiFi | wifiSetup, wifiBody, wifiBottom, wifiQr, wifiConnected |
| Couplage | pairingTitle, pairingBody |
| Motifs | patternName0–patternName6, patternDesc0–patternDesc6 |
Tableaux de motifs
Les noms et descriptions des motifs du Stroke Engine sont des tableaux indexés :
static const char* const strokeEngineNames[7] = {
patternName0, patternName1, patternName2,
patternName3, patternName4, patternName5,
patternName6,
};
static const char* const strokeEngineDescriptions[7] = {
patternDesc0, patternDesc1, patternDesc2,
patternDesc3, patternDesc4, patternDesc5,
patternDesc6,
};Éléments de menu
MenuItems.h associe les valeurs d'énumération Menu:: aux chaînes d'affichage :
static const char* menuStrings[Menu::NUM_OPTIONS] = {
ui::strings::simplePenetration, ui::strings::strokeEngine,
ui::strings::streaming, ui::strings::pairing,
ui::strings::update, ui::strings::wifiSetup,
ui::strings::helpTitle, ui::strings::restart,
};Images et icônes
Icônes (glyphes de police)
Les icônes d'état utilisent la police d'icône Siji. Les glyphes sont définis dans DisplayConstants.h :
namespace IconGlyph {
constexpr uint16_t WIFI_OFF = 0xe218;
constexpr uint16_t WIFI_CONNECTING = 0xe219;
constexpr uint16_t WIFI_CONNECTED = 0xe21a;
constexpr uint16_t WIFI_ERROR = 0xe21b;
constexpr uint16_t BLE_CONNECTED = 0xe00b;
constexpr uint16_t BLE_SMALL = 0xe0b0;
constexpr uint16_t EXCLAMATION = 0xe0b3;
}drawHeaderIcons() affiche les états WiFi et BLE dans le coin supérieur droit de l'écran. Les états d'erreur superposent des pixels supplémentaires (points d'exclamation) au glyphe de base.
Logos (bitmaps XBM)
Les logos sont des tableaux d'octets PROGMEM XBM dans Logos.h :
RDLogo— Research & Desire, 57x50 pixelsKMLogo— Kinky Makers, 50x50 pixels
Ils sont dessinés via la structure LogoData et drawLogo() :
struct LogoData {
const char* title;
const uint8_t* bitmap;
int w, h, x, y;
};Animation Hello
HelloAnimation.h contient des images correspondant aux positions Y précalculées pour l'animation de démarrage « OSSM ». Chaque image spécifie des décalages Y par lettre :
struct HelloFrame {
int heights[4]; // Y position for O, S, S, M
};drawHelloFrame() restitue une seule image. La suite de tests assemble toutes les images dans un GIF.
Autres fonctions de dessin
L'API de rendu complète (ui.h) :
| Fonction | But |
|---|---|
drawTextPage() | Rendre une structure TextPage |
drawMenu() | Menu défilant avec sélection en surbrillance |
drawPlayControls() | Barres de vitesse/course/sensation pour les modes de fonctionnement |
drawPreflight() | Contrôle de sécurité avant le mouvement (bouton de vitesse à zéro) |
drawHeaderIcons() | Icônes d'état WiFi et BLE |
drawQR() | Code QR autonome |
drawHelloFrame() | Image d'animation de démarrage unique |
drawLogo() | Logo XBM avec titre |
Espaces de noms d'assistance dans DrawExtensions.h :
drawStr::centered()— texte centré horizontalementdrawStr::multiLine()— texte multiligne avec retour automatique à la ligne et prise en charge UTF-8drawStr::title()— texte gras centré à une position fixedrawShape::scroll()— indicateur de barre de défilementdrawShape::settingBar()— barre verticale étiquetée avec niveau de remplissagedrawShape::settingBarSmall()— barre verticale compacte (sans étiquette)
Tests et sortie visuelle
La bibliothèque d'affichage dispose de tests natifs qui restituent chaque variante d'écran et exportent des images pour un examen visuel.
Exécution de tests
pio test -e test -f test_displayImageMagick (magick) doit être installé pour la conversion PNG. Sans cela, les fichiers PBM sont toujours générés mais les PNG sont ignorés.
Comment ça marche
- Les tests créent un écran U8g2 SSD1306 128x64 entièrement logiciel (sans matériel, avec une implémentation I2C sans effet)
- Chaque test appelle les fonctions
ui::draw*()pour effectuer le rendu dans le tampon savePBM()écrit le tampon sous forme de bitmap PBM P4- Une fois tous les tests terminés, ImageMagick convertit le PBM en PNG (couleurs inversées, échelle 400 %).
- Les images de l'animation Hello sont assemblées dans un GIF
Structure de sortie
test/test_display/_output/
├── pbm/ # Raw bitmaps (generated by tests)
│ ├── textpage/
│ │ ├── combos/ # Field combinations (title+body, all fields, etc.)
│ │ ├── scroll/ # Scroll positions (0%, 50%, 100%)
│ │ ├── stress/ # Edge cases (UTF-8, long strings)
│ │ ├── qr/ # QR code variants
│ │ ├── body/ # Body rendering with/without title
│ │ ├── subtitle/ # Subtitle font sizing
│ │ ├── pages/ # All predefined pages
│ │ └── patterns/ # Stroke engine pattern descriptions
│ ├── header_icons/ # WiFi × BLE status combinations
│ ├── logos/ # RD logo, KM logo
│ ├── hello/ # Animation frames
│ ├── menu/ # Menu rendering variants
│ └── play_controls/ # Preflight, play modes
└── png/ # Same structure, converted to PNGCouverture des tests
| Fichier de test | Ce qu'il couvre |
|---|---|
test_textpage.cpp | Combinaisons de champs TextPage, tests de stress, QR, débordement de sous-titres, disposition du corps |
test_pages.cpp | Toutes les pages prédéfinies, descriptions des motifs du Stroke Engine |
test_scroll.cpp | Barre de défilement aux valeurs limites et aux cas particuliers |
test_header_icons.cpp | Les 20 combinaisons d'états WiFi × BLE |
test_logos.cpp | Logo RD, logo KM |
test_hello.cpp | Toutes les images de l'animation Hello, génération du GIF |
test_menu.cpp | Menu avec différents nombres d'éléments, texte long, retour automatique à la ligne |
test_play_controls.cpp | Commandes pour Preflight, Simple Penetration, Stroke Engine et Streaming |