Destinatari:Ingegneri firmware embedded, integratori di driver OS e product manager OEM che necessitano di comprendere cosa significhi ogni singolo byte del descrittore di report HID della penna ottica, perché la pagina di utilizzo è suddivisa in una pagina desktop generica più una pagina definita dal vendor, e come estendere la mappa senza compromettere i 230+ driver di livello distributore già sul campo.
Il descrittore di report HID è gli 80-200 byte di firmware più determinanti della penna ottica. È il contratto tra l'MCU della penna e ogni sistema operativo host con cui comunicherà: Windows 10/11, macOS 12/13/14, ChromeOS, Android 9-14, iPadOS 15-17 e il kernel Linux 5.15+. Se il descrittore è errato, la penna inserisce caratteri errati, ignora il tap OID, o peggio, instrada silenziosamente l'audio verso il sink errato. Tra le nostre 47.000+ unità spedite, le regressioni del descrittore hanno causato più ore di debug di qualsiasi altro sottosistema firmware tranne il motore OCR.
Questo articolo prende il descrittore canonico da TC-057 e lo analizza byte per byte, spiega perché ogni campo è impostato in quel modo, e mostra dove un brand ODM può estendere la mappa in sicurezza e dove non può.
1. I Tre Livelli del Contratto HID
Un descrittore di report HID viene analizzato in tre livelli logici:
| Livello | Granularità | Scopo | Lunghezza |
|---|---|---|---|
| Elemento | Corto (1 byte) o Lungo (3 byte) | Tag + dimensione + dati | Variabile |
| Locale | Definito per elemento | Usage, Usage Minimum/Maximum, Designator | Variabile |
| Principale | Racchiude un array di input/output/feature | Collection, End Collection, Input, Output, Feature | Variabile |
Il parser è stateful. Una Collection inizia uno scope, e gli elementi Input/Output/Feature al suo interno descrivono un report. Il descrittore viene elaborato da sinistra a destra, e ogni byte deve essere ben formato. Un singolo byte malformato causa il rifiuto dell'intero descrittore da parte dell'host.
Il nostro descrittore Q6/Q8 è 92 byte. Il descrittore F8 è 76 byte. Il T2/Y6 (con supporto completo consumer-control per la riproduzione cuffie) è 168 byte. La lunghezza del descrittore è codificata nel descrittore HID al momento dell'enumerazione, e l'host la memorizza nella cache. Se si modifica il descrittore in una futura revisione firmware, l'host potrebbe continuare a usare la versione cached, motivo per cui forziamo sempre un reset del bus USB durante l'aggiornamento firmware (vedere TC-075).
2. I Tag degli Elementi Utilizzati dalla Penna Ottica
La specifica HID definisce una tabella di tag; la penna ne utilizza solo 12:
| Tag | Mnemonico | Ruolo | Usato in Q6/Q8 |
|---|---|---|---|
| 0x05 | Usage Page | Cambia pagina | Sì (3 volte) |
| 0x09 | Usage | Seleziona un usage | Sì (4 volte) |
| 0x15 | Logical Minimum | Limita un input/output | Sì (3 volte) |
| 0x25 | Logical Maximum | Limita un input/output | Sì (3 volte) |
| 0x75 | Report Size | Bit per elemento | Sì (3 volte) |
| 0x95 | Report Count | Numero di elementi | Sì (3 volte) |
| 0xA1 | Collection | Apre scope | Sì (2 volte) |
| 0x81 | Input | Definisce un campo di report di input | Sì (3 volte) |
| 0x91 | Output | Definisce un campo di report di output | Sì (1 volta) |
| 0x19 | Utilizzo Minimo | Inizio intervallo | Sì (1 volta) |
| 0x29 | Utilizzo Massimo | Fine intervallo | Sì (2 volte) |
| 0xC0 | Fine Collezione | Chiude l'ambito | Sì (2 volte) |
Restiamo deliberatamente in questo sottoinsieme di 12 tag. La specifica HID ne permette molti altri, ma ogni tag aggiuntivo aumenta la probabilità di un difetto specifico del sistema operativo. Ad esempio, ilPadding (0x5A) tag è tecnicamente legale, ma il hid-core.c del kernel Linux rifiuta alcune sequenze Padding durante la sospensione/ripresa.
3. Le Tre Pagine di Utilizzo
Il descrittore Q6/Q8 utilizza tre pagine di utilizzo:
| Pagina di Utilizzo | Esadecimale | Scopo |
|---|---|---|
| Desktop Generico | 0x01 | Tastiera, mouse, controlli di sistema |
| Consumer | 0x0C | Volume, play/pausa, navigazione traccia |
| Definito dal Venditore | 0xFF00 | Payload evento OID (estensione personalizzata del marchio) |
La pagina Desktop Generico è la collezione tastiera che spediamo. Dichiara un modificatore di 1 byte (8 bit, dimensione report 1 byte, conteggio report 8) e una costante riservata di 1 byte (8 bit, dimensione report 1, conteggio 1). Insieme formano l'intestazione del report della tastiera di boot.
La pagina Consumer è il controllo volume su / volume giù / play-pausa che spediamo per la riproduzione cuffie. È in totale 3 bit.
La pagina Definita dal Venditore 0xFF00 è il payload dell'evento OID: 16 byte per report, senza Report ID, in un report Output in modo che l'host possa anche inviare 16 byte di contesto alla penna se necessario.
4. Mappa Byte per Firmware Q6/Q8 3.3.1
Di seguito è riportato il descrittore canonico per la piattaforma Q6/Q8, indicizzato per byte:
| Byte | Esadecimale | Significato | Perché |
|---|---|---|---|
| 0 | 0x05 | Tag Pagina di Utilizzo (Globale) | Dice al parser che stiamo cambiando pagina |
| 1 | 0x01 | Pagina 0x01 (Desktop Generico) | Apre l'ambito tastiera |
| 2 | 0x09 | Tag Utilizzo (Locale) | Seleziona un utilizzo |
| 3 | 0x06 | Tastiera | Richiesto per il protocollo di boot |
| 4 | 0xA1 | Tag di raccolta (Principale) | Apre la raccolta Applicazione |
| 5 | 0x01 | Applicazione | Applicazione è il wrapper standard |
| 6 | 0x05 | Tag pagina di utilizzo | |
| 7 | 0x07 | Pagina tastiera | I tasti modificatori sono qui |
| 8 | 0x19 | Utilizzo minimo | |
| 9 | 0xE0 | Control sinistro = 224 | Intervallo modificatori 224–231 |
| 10 | 0x29 | Utilizzo massimo | |
| 11 | 0xE7 | GUI destro = 231 | Chiude l'intervallo modificatori |
| 12 | 0x15 | Minimo logico | |
| 13 | 0x00 | 0 | Booleano falso |
| 14 | 0x25 | Massimo logico | |
| 15 | 0x01 | 1 | Booleano vero |
| 16 | 0x75 | Dimensione report | |
| 17 | 0x01 | 1 bit per elemento | Il modificatore è un bitfield |
| 18 | 0x95 | Conteggio report | |
| 19 | 0x08 | 8 elementi | Un bit per modificatore |
| 20 | 0x81 | Tag di input (Principale) | |
| 21 | 0x02 | Dati, Variabile, Assoluto | Modificatore tastiera di avvio standard |
| 22 | 0x95 | Conteggio Report | |
| 23 | 0x01 | 1 elemento | Byte riservato |
| 24 | 0x75 | Dimensione Report | |
| 25 | 0x08 | 8 bit | Un byte riservato |
| 26 | 0x81 | Tag Input | |
| 27 | 0x03 | Costante, Variabile, Assoluto | Il SO si aspetta questo byte riservato |
| 28 | 0x05 | Tag Pagina Usage | |
| 29 | 0x0C | Pagina Consumer | Per tasti multimediali |
| 30 | 0x09 | Usage | |
| 31 | 0xE9 | Aumento Volume | |
| 32 | 0x09 | Usage | |
| 33 | 0xEA | Riduzione Volume | |
| 34 | 0x09 | Usage | |
| 35 | 0xCD | Riproduci/Pausa | |
| 36 | 0x15 | Minimo Logico | |
| 37 | 0x00 | 0 | |
| 38 | 0x25 | Massimo Logico | |
| 39 | 0x01 | 1 | |
| 40 | 0x75 | Dimensione Report | |
| 41 | 0x01 | 1 bit | |
| 42 | 0x95 | Conteggio Report | |
| 43 | 0x03 | 3 elementi | 3 bit media |
| 44 | 0x81 | Tag Input | |
| 45 | 0x02 | Dati, Variabile, Assoluto | |
| 46 | 0xC0 | Fine Collezione | Chiude l'app tastiera |
| 47 | 0x06 | Tag Pagina Usage (esteso) | Pagina usage 2 byte |
| 48 | 0xFF, 0x00 | Pagina 0xFF00 | Definito dal vendor |
| 49 | 0x09 | Usage | |
| 50 | 0x01 | Evento OID | Usage personalizzato |
| 51 | 0xA1 | Collezione | |
| 52 | 0x01 | Applicazione | |
| 53 | 0x15 | Minimo Logico | |
| 54 | 0x00 | 0 | |
| 55 | 0x26 | Massimo Logico (esteso) | Max logico 2 byte |
| 56 | 0xFF, 0x00 | 255 | |
| 57 | 0x75 | Dimensione Report | |
| 58 | 0x08 | 8 bit | |
| 59 | 0x95 | Conteggio Report | |
| 60 | 0x10 | 16 elementi | payload OID 16 byte |
| 61 | 0x09 | Utilizzo | |
| 62 | 0x02 | Payload OID | |
| 63 | 0x91 | Tag di output | |
| 64 | 0x02 | Dati, Variabile, Assoluto | |
| 65 | 0xC0 | Fine Collezione | Chiude la collezione vendor |
I byte rimanenti (da 66 a 91) su Q6/Q8 sono padding per l'allineamento dei byte e un Feature report per il brand ID. Su F8, i byte dal 47 in poi sono rimossi e il descrittore termina al byte 46.
5. Protocollo Boot vs Protocollo Report
La penna di lettura espone una caratteristica Protocol Mode (UUID 0x2A4E su BLE, byte bInterfaceProtocol su USB). Due protocolli sono validi:
| Protocollo | Layout Report | Utilizzato Quando |
|---|---|---|
| Boot | fisso 8 byte (modificatore + riservato + 6 codici tasto) | BIOS, recovery, avvio iniziale |
| Report | definito dal descrittore | Uso normale del SO |
Sul firmware 3.3.1 di Q6/Q8, il valore predefinito è il Protocollo Report. L'host può richiedere il Protocollo Boot scrivendo 0x00 sulla caratteristica Protocol Mode, e il nostro firmware lo rispetta riducendo il report OID da 16 byte al formato boot da 8 byte. Non perdiamo alcun dato; l'ID pagina e il codice OID vengono semplicemente compressi nei byte dei codici tasto.
Per un programma scolastico da 12.000 unità, abbiamo consigliato che il Protocollo Boot fosse abilitato per impostazione predefinita poiché i laptop scolastici eseguono un'immagine Windows bloccata in cui lo stack del driver HID standard si carica in 1,4 s rispetto a 4,8 s per il parser completo del Protocollo Report. Il risparmio di latenza è significativo quando 30 bambini avviano a freddo il sistema all'inizio della lezione.
6. Pagina Definita dal Vendor 0xFF00: Perché l'abbiamo Riservata
Abbiamo riservato 0xFF00 nell'elenco vendor USB-IF nel 2022. La riservazione ci conferisce autorità legale per definire qualsiasi ID di utilizzo da 0x01 a 0xFFFF su quella pagina, e qualsiasi terza parte che desideri interoperare con le nostre penne deve negoziare un intervallo di ID di utilizzo con noi. Il cliente ODM ottiene un sotto-intervallo di 32 utilizzi assegnato al proprio brand ID. I primi 8 di questi 32 sono riservati per il nostro uso interno, lasciando 24 utilizzi per il brand.
È così che lo stesso firmware Q6/Q8 viene spedito a 230+ distributori senza che la loro app parli accidentalmente con la penna di un altro distributore.
7. Il Layout del Report OID
Il report del payload OID da 16 byte è strutturato come segue:
| Byte | Campo | Codifica | Intervallo |
|---|---|---|---|
| 0–3 | ID Pagina | uint32 LE | 0 a 4.294.967.295 |
| 4–7 | Codice OID | uint32 LE | 0 a 4.294.967.295 |
| 8 | Lingua | uint8 | 0–255 (vedere il pacchetto lingua) |
| 9–10 | Sequenza | uint16 LE | 0–65,535 |
| 11–12 | Permanenza (ms) | uint16 LE | 0–65,535 |
| 13 | Flag | uint8 bitmask | bit 0 = ripetizione, bit 1 = audio occupato |
| 14–15 | Riservato | uint16 LE | 0 |
Il byte flag è l'unico che un brand cliente può ridefinire. Allocchiamo i bit 2–7 per flag specifici del brand (es. "modalità test," "diagnostica," "QA in produzione"). I bit 0–1 sono riservati per il nostro firmware.
8. Il Feature Report (Brand ID)
Un Feature Report di 4 byte alla fine del descriptor contiene un Brand ID. Il Feature Report è di sola lettura dall'host e viene impostato durante il provisioning in fabbrica. Serve a due scopi:
- L'app companion legge il Brand ID per determinare quale catalogo contenuti caricare.
- La stazione QA legge il Brand ID per verificare l'integrità del caricamento del firmware.
0x09, 0x03, // Usage (Brand ID)
0x15, 0x00, // Logical Minimum 0
0x26, 0xFF, 0x00, // Logical Maximum 255
0x75, 0x08, // Report Size 8
0x95, 0x04, // Report Count 4
0xB1, 0x02, // Feature (Data, Variable, Absolute)
Il primo byte è l'indice del brand (attualmente abbiamo 38 indici brand assegnati), il secondo è un codice regione (1=UE, 2=US, 3=APAC, 4=MENA, 5=LATAM, 6=SSA), il terzo è una revisione del contenuto (0–255), e il quarto è un CRC sui primi tre.
9. Come il Descriptor si Mappa a GATT
Quando la penna è su BLE, gli stessi byte del descriptor sono serviti dalla caratteristica 0x2A4B (Report Descriptor). Il report stesso viene inviato sulla caratteristica 0x2A4D tramite notifiche. Il Protocol Mode è su 0x2A4E. Il Brand ID Feature report è esposto su una caratteristica definita dal vendor 0x9F01 (sola lettura) sullo stesso servizio HID.
| Voce USB HID | UUID Caratteristica GATT | Proprietà |
|---|---|---|
| Report Descriptor | 0x2A4B | Lettura |
| Report | 0x2A4D | Notifica, Scrittura, ScritturaSenzaRisposta |
| Modalità Protocollo | 0x2A4E | Lettura, Scrittura |
| Brand ID | 0x9F01 (personalizzato) | Lettura |
| Informazioni HID | 0x2A4A | Lettura |
Questa è la tabella GATT documentata in TC-060.
10. Suite di Validazione che Eseguiamo su Ogni Build del Descriptor
Prima che un descriptor venga rilasciato, deve superare:
| Verifica | Strumento | Criterio di Superamento |
|---|---|---|
| Conformità di parsing | Visualizzatore descriptor HID USB-IF | 0 errori, 0 avvisi |
| Avviabilità protocollo boot | USBlyzer | Modifica il report boot con successo |
| Enumerazione SO | Device Manager Windows 10/11 | Elenca come HID Keyboard + HID Vendor Device |
| Accoppiamento iPadOS | iPad 9a gen, iPadOS 17 | Abbina e legge il descrittore |
| Enumerazione ChromeOS | Lenovo Chromebook 14 | Elenca come dispositivo di input |
| Enumerazione macOS | MacBook Air M1 | Informazioni di sistema elenca tutte e 3 le interfacce |
| Enumerazione Android | Pixel 7a, Android 14 | InputDeviceManager riporta tastiera + vendor |
Se una qualsiasi di queste operazioni fallisce, il descrittore viene rifiutato e la build del firmware viene bloccata. Su 86 rilasci di firmware dal 2023, 6 sono stati rifiutati in questa fase e riportati indietro. La causa più comune è un tag Usage Page con la codifica della lunghezza estesa errata, che non supera il controllo macOS ma passa quello Windows.
11. Errori comuni dei clienti
Quando un cliente ODM porta la propria bozza di descrittore, tre errori rappresentano circa l'80% dei rifiuti:
- Salto del byte riservato dopo il modificatore. macOS si aspetta esattamente 9 byte del report della tastiera di boot (8 modificatori + 1 riservato + 6 codici tasto). I clienti spesso comprimono questo a 8 byte, il che rompe il protocollo di boot su Mac.
- Usare
Logical Maximum 0x00FFsenza il tag esteso (0x26). Il formato breve0x25 0xFFfunziona per valori fino a 127. Per valori fino a 255, il tag esteso è obbligatorio. I clienti dimenticano e il descrittore tronca silenziosamente su Linux. - Dichiarare un report di Input all'interno di una collezione Output. Il parser HID non impone una collezione strettamente Output-only, ma alcuni driver OS lo fanno. Noi dichiariamo sempre Output nella collezione OID per rendere esplicita la simmetria.
12. Budget delle prestazioni
Lato host, il descrittore viene analizzato una volta in fase di enumerazione. Lato dispositivo, ogni assemblaggio di report tocca la mappa del descrittore. Il nostro benchmark interno su firmware Q6/Q8 3.3.1:
| Operazione | Cicli | Tempo a 64 MHz |
|---|---|---|
| Ricerca Usage Page | 8 | 125 ns |
| Ricerca Usage ID | 12 | 188 ns |
| Assembla report OID da 16 byte | 240 | 3.75 µs |
| Invia report su USB EP1 IN | 320 | 5.0 µs |
| Invia report su BLE 0x2A4D | 1,840 | 28.75 µs |
| Totale per tocco (USB) | 580 | 9.1 µs |
| Totale per tocco (BLE) | 2,100 | 32.8 µs |
Il valore USB di 9.1 µs è ciò che rende possibile la latenza end-to-end di 6.4 ms. Il valore BLE è la componente dominante della latenza BLE di 32 ms.
13. Il quadro più ampio
Se state valutando una penna che non pubblica apertamente il suo descrittore di report HID, questa è la prima cosa che dovreste chiedere. Un fornitore che rifiuta di condividere il descrittore sta nascondendo la non conformità o sta costruendo su uno stack non-HID che richiederà lavoro sui driver da parte vostra. Il nostro descrittore per firmware Q6/Q8 3.3.1 è di 92 byte e lo pubblichiamo sotto NDA a clienti ODM qualificati su richiesta.
15. Letture correlate
- Penna di lettura USB HID e HID over GATT
- Accoppiamento Bluetooth della penna di lettura SSP Secure Simple Pairing
- Progettazione UUID del servizio e delle caratteristiche BLE della penna di lettura
- Server GATT della penna di lettura e meccanismo di notifica
- Penna di Lettura Ricarica USB Type-C PD QC e BC1.2
- Penna di Lettura Bluetooth 5.0 vs 5.2 vs 5.3
- Penna di Lettura Meccanismo di Aggiornamento Firmware OTA
- Penna di Lettura Dizionario Formato File ed Edizione