jzland docs
Riferimento tecnico

Protocollo scheda e cervello

Il formato dei frame binari tra la scheda e il computer, i tipi di messaggio e il collegamento.

La scheda parla con il Mac sulla seriale USB nativa (CDC-ACM, dispositivo "JZ Companion link"). Nessun JSON, nessun TLS: frame binari piccoli, mandati solo quando qualcosa cambia. L'altra metà del dispositivo composito è una tastiera HID ("JZ Companion keys"), usata dai widget per le scorciatoie senza passare dal companion.

Frame

A5 5A | len u16 LE | widget u8 | kind u8 | campi… | crc8
  • len conta i byte da widget all'ultimo campo (crc escluso). Massimo 2048.
  • crc8: polinomio 0x07, valore iniziale 0, calcolato sugli stessi byte di len.
  • widget: indice nel registro della scheda. 0xFF è il sistema (shell).
  • kind: vedi sotto.

Campo: key u8 | type u8 | [len u16 LE] | valore

typevalore
0int32 little-endian (4 byte, niente len)
1stringa UTF-8 (len byte, senza NUL)
2byte grezzi (len byte)

Chiavi scalari: 0x00..0x0E. Liste: JZ_K(i, campo) = ((i + 1) << 4) | campo, fino a 14 elementi (i da 0 a 13) con 16 campi ciascuno. 0x0F (JZ_F_COUNT, int) dice quanti elementi ci sono.

Tipi di messaggio (kind)

kinddirezionesignificato
1 DATAhost → devicestato di un widget. Le chiavi sono documentate in testa a ui/widgets/<id>.c
2 EVENTdevice → hostazione dell'utente. Chiave 0xFE int = azione; le altre sono argomenti. L'azione 0 significa "widget mostrato": il cervello risponde con un DATA fresco
3 HELLOdevice → hostal collegamento, a pezzi: un campo stringa per widget, key = indice, valore = id. Nel primo pezzo anche le chiavi riservate 0xF0–0xFE (vedi sotto: versione del protocollo, del firmware, id della scheda, numero dei widget). Il cervello risponde quando ha ricevuto tutti gli id
4 TIMEhost → devicechiave 0 int epoch UTC, chiave 1 int offset locale in minuti. Aggiorna l'RTC
5 BLOBentrambepezzo di un blob: 0 int slot, 1 int offset, 2 int totale, 3 bytes. Host → device: immagini (slot scelto dal widget). Device → host: audio del microfono, widget 0xFF, slot 0xA0, PCM 16 kHz mono 16 bit, 1024 byte per frame
6 PINGentrambela scheda risponde con un PING
7 THEMEhost → devicechiave 0 int: 1 scuro, 0 chiaro
8 FOCUShost → devicechiave 0 str: id del widget da mostrare
9 SCENEdevice → hostchiave 0 int: scena premuta (0 riunione, 1 focus, 2 stream, 3 pausa, 4 fine)
10 BUTTONdevice → hostchiave 0 int: tasto (0 BOOT, 1 PWR), chiave 1 int: 1 se tenuto. BOOT tenuto = "muto ovunque": il cervello muta microfono di sistema, Discord e la riunione in modo idempotente
11 STOREentrambearchivio dei widget: chiave 0 str nome (pomodoro.oggi), 1 bytes valore, 2 int mtime (epoch). Vince il più recente. Al collegamento la scheda manda le modifiche fatte da staccata, il cervello risponde con tutto l'archivio
12 LAYOUThost → devicedisposizione dei widget: chiave 0 str la barra di BOOT (id separati da \n, vuota = i confermati), chiave 1 str i gruppi del mission control, uno per riga nome\tid,id (vuota = per categoria). La scheda la salva e la usa anche staccata
13 CATALOGdevice → hostdopo l'HELLO, a pezzi: chiave = indice del widget, str nome\tcategoria\tdescrizione. Serve alla pagina del cervello
14 LOGdevice → hostuna riga di log della scheda: chiave 0 int livello (0 debug, 1 info, 2 warn, 3 error), 1 str fonte (ui, wifi, board…), 2 str messaggio, 3 int millisecondi dall'accensione, 4 str campi in più, uno per riga nome=valore. Il cervello la mette nei suoi log con la scheda come origine
15 FLAGShost → devicevalori delle feature flag già calcolati per questa scheda. Lista: JZ_K(i,0) str nome, JZ_K(i,1) int valore (sì/no e numeri) oppure JZ_K(i,2) str valore (varianti). Chiave 0 int pezzo (da 0), 1 int pezzi totali: quando arriva l'ultimo pezzo i valori ricevuti sostituiscono tutti i precedenti. La scheda li salva e usa i predefiniti del codice per le flag mai ricevute
16 HOSThost → devicesubito dopo l'HELLO: chiave 0 int versione del protocollo, 1 str sistema (mac, windows, linux), 2 str nome del cervello ("MacBook Air di Jacopo"), 3 str versione del cervello. La scheda sceglie le scorciatoie giuste (⌘ o Ctrl) dal sistema
17 PAIRentrambeabbinamento e stretta di mano del canale cifrato (widget 0xFF): chiave 0 int = passo, gli altri campi dipendono dal passo. In chiaro finché il canale non c'è, cifrato dopo. Passi, campi ed errori in abbinamento.md
18 SEALEDentrambeun frame del canale cifrato (widget 0xFF): chiave 0 bytes = contatore u64 LE (8) ‖ cifrato ‖ tag (16), ChaCha20-Poly1305. Dentro c'è il corpo di un frame qualunque (da widget all'ultimo campo), fino a 2048 byte: la busta può superare il massimo di 30 byte. Dopo l'abbinamento la scheda e il cervello si parlano solo così (abbinamento.md)
19 COMMANDhost → deviceun comando del cervello alla scheda, accettato solo dentro il canale cifrato (scheda abbinata): chiave 0 str nome. pin_reset: toglie il PIN di blocco (PIN dimenticato), azzera gli errori e sblocca. aggiorna: aggiornamento del firmware, chiavi 1 str URL, 2 int dimensione, 3 str SHA-256 (hex), 4 str firma Ed25519 (hex) del messaggio jz-ota-1 ‖ sha256 ‖ versione, 5 str versione

Chiavi riservate nell'HELLO: 0xFE protocol, 0xFD firmware, 0xFC device, 0xFB total. Versione attuale del protocollo: 2.

Il companion dovrebbe mandare TIME e THEME subito dopo l'HELLO, poi un DATA per il widget che riceve l'evento "mostrato" e, da lì in poi, un DATA ogni volta che lo stato cambia. La scheda tiene in cache l'ultimo DATA di ogni widget: cambiare schermata non aspetta il companion.

Collegamento

  • Apri la seriale a qualsiasi baud (è USB) e alza DTR: la scheda considera il companion collegato quando DTR è alto, manda l'HELLO e accende il punto verde nella barra in alto.
  • Un frame corrotto viene scartato in silenzio: il parser cerca il prossimo A5 5A.

HID

Tastiera (report 1) e consumer control (report 2). I widget chiamano jz_hid_key(mods, tasto), jz_hid_media(…) e jz_hid_type("testo\n"). Le combinazioni usate dai widget sono scritte nel loro commento di testa. Il companion non c'entra: funzionano con la scheda attaccata a qualunque computer.

Esempio

DATA per pr_review (indice 3): 4 PR in attesa, una in lista.

A5 5A  len  03 01
  00 00 04 00 00 00              key 0, int 4
  0F 00 01 00 00 00              JZ_F_COUNT, int 1
  10 01 1A 00 "feat: filtri per cliente…"   JZ_K(0,0), str
  11 01 11 00 "webion/gestionale"           JZ_K(0,1), str
  12 01 05 00 "marco"                       JZ_K(0,2), str
  13 01 03 00 "2 h"                         JZ_K(0,3), str
crc

Un riferimento in C per codifica e decodifica è ui/src/proto.c; il simulatore stampa a console i frame che la scheda manderebbe ([link] …) e le scorciatoie HID ([hid] …).

On this page