Bibliothèque de l'interface utilisateur

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.

ChampTypeBut
titleconst char*Texte en gras en haut, avec une ligne de séparation en dessous
subtitleconst char*Texte de graisse moyenne ou en gras sous le titre ; se divise automatiquement si trop large
bodyconst char*Texte avec retour automatique à la ligne ; prend en charge \n comme saut de ligne
bottomTextconst char*Épinglé en bas de l'écran (y=62)
qrUrlconst char*Code QR affiché en bas à droite ; limite la largeur du texte
qrVersionuint8_tVersion QR (par défaut 3)
qrScaleintÉchelle de pixels QR (par défaut 2)
centerBodyboolCentrer le corps du texte
scrollPercentintAfficher l'indicateur de défilement (0 à 100) ; -1 pour le masquer

Ordre de rendu

drawTextPage() effectue le rendu dans cet ordre :

  1. Effacer le plein écran (en-tête + page + pied de page)
  2. Code QR — coin inférieur droit, réduit la largeur du texte disponible
  3. Titre — police en gras, suivie d'une ligne de séparation horizontale
  4. Sous-titre : essaie d’abord la graisse moyenne ; revient en gras ; est réparti sur deux lignes s’il est encore trop large
  5. 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
  6. Texte du bas — fixé à y=62
  7. 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 :

PageChamps utilisés
helpPagetitle, body, bottomText, qrUrl
updateCheckingPagebody
noUpdatePagebody, bottomText
updatingPagetitle, body
errorPagetitle
wifiDisconnectedPagetitle, body, bottomText, qrUrl
wifiConnectedPagetitle, body, bottomText
pairingPagetitle, 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égorieExemples
Image de marqueresearchAndDesire, kinkyMakers
Interface utilisateur généraleerror, homing, idle, restart, settings, skip
Menus/modessimplePenetration, strokeEngine, streaming, pairing, update, wifi
Commandes de mouvementspeed, stroke, sensation, depth, buffer, accel, max
AvertissementsspeedWarning, homingTookTooLong, strokeTooShort
AidehelpTitle, helpBody, helpBottom, helpQr
Mise à jourupdateChecking, noUpdateBody, updatingTitle, updatingBody
WiFiwifiSetup, wifiBody, wifiBottom, wifiQr, wifiConnected
CouplagepairingTitle, pairingBody
MotifspatternName0patternName6, patternDesc0patternDesc6

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 pixels
  • KMLogo — 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) :

FonctionBut
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é horizontalement
  • drawStr::multiLine() — texte multiligne avec retour automatique à la ligne et prise en charge UTF-8
  • drawStr::title() — texte gras centré à une position fixe
  • drawShape::scroll() — indicateur de barre de défilement
  • drawShape::settingBar() — barre verticale étiquetée avec niveau de remplissage
  • drawShape::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_display

ImageMagick (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

  1. Les tests créent un écran U8g2 SSD1306 128x64 entièrement logiciel (sans matériel, avec une implémentation I2C sans effet)
  2. Chaque test appelle les fonctions ui::draw*() pour effectuer le rendu dans le tampon
  3. savePBM() écrit le tampon sous forme de bitmap PBM P4
  4. Une fois tous les tests terminés, ImageMagick convertit le PBM en PNG (couleurs inversées, échelle 400 %).
  5. 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 PNG

Couverture des tests

Fichier de testCe qu'il couvre
test_textpage.cppCombinaisons de champs TextPage, tests de stress, QR, débordement de sous-titres, disposition du corps
test_pages.cppToutes les pages prédéfinies, descriptions des motifs du Stroke Engine
test_scroll.cppBarre de défilement aux valeurs limites et aux cas particuliers
test_header_icons.cppLes 20 combinaisons d'états WiFi × BLE
test_logos.cppLogo RD, logo KM
test_hello.cppToutes les images de l'animation Hello, génération du GIF
test_menu.cppMenu avec différents nombres d'éléments, texte long, retour automatique à la ligne
test_play_controls.cppCommandes pour Preflight, Simple Penetration, Stroke Engine et Streaming

Sur cette page