Personalizzare il firmware della scheda terminale ANSI / VT-100
La scheda terminale ANSI / VT-100 per il computer RC2014 utilizza il firmware open source disponibile su GitHub ed è pertanto liberamente modificabile da chiunque. Tuttavia, essendo scritto nel linguaggio Spin proprio dei microcontrollori Parallax Propeller, potrebbe essere difficile, anche per chi è esperto di programmazione di microcontrollori, capirne il funzionamento, cercherò quindi di spiegare il più semplicemente possibile come effettuare alcune piccole modifiche per rendere il firmware un po’ più personale.

Propeller ANSI / VT-100 Terminal
Le indicazioni date di seguito presuppongono una certa familiarità nell’uso degli strumenti a linea di comando tramite il Terminale di Linux o il Prompt dei Comandi di Windows e che siate in posseso di un programmatore in grado di scrivere le EEPROM seriali, oppure dell’adattatore PropPlug per la programmazione in-circuit.
Compilare il firmware
Per prima cosa è necessario scaricare il sorgente da GitHub sul proprio computer per poterlo poi modificare.
Se si dispone del programma git
già installato, il metodo più semplice è quello di “clonare” il repository, cioè crearne una copia sul proprio computer. Aprite una finestra Terminale (o Prompt dei Comandi se utilizzate Windows) e digitate il comando
git clone https://github.com/maccasoft/propeller-vt100-terminal.git
Dopo alcuni istanti, in cui il programma scaricherà tutto il contenuto del repository, troverete nella cartella propeller-vt100-terminal il sorgente completo.
Esempio:
marco@bridge:~$ git clone https://github.com/maccasoft/propeller-vt100-terminal.git Cloning into 'propeller-vt100-terminal'... remote: Counting objects: 130, done. remote: Compressing objects: 100% (13/13), done. remote: Total 130 (delta 7), reused 7 (delta 2), pack-reused 115 Ricezione degli oggetti: 100% (130/130), 641.75 KiB | 378.00 KiB/s, done. Risoluzione dei delta: 100% (72/72), done. Checking connectivity... fatto.
Se non disponete di git e/o non volete usarlo, è comunque possibile scaricare una copia del repository da GitHub utilizzando questo collegamento https://github.com/maccasoft/propeller-vt100-terminal/archive/master.zip. Una volta scompattato l’archivio troverete una cartella con il nome propeller-vt100-terminal-master contenente il sorgente completo.
A questo punto è necessario scaricare e installare il compilatore OpenSpin necessario per compilare il codice sorgente in un formato leggibile dal microcontrollore. Il programma può essere scaricato dalla pagina di download. Nota: la versione presente su quella pagina è stata compilata direttamente dai sorgenti e contiene alcune correzioni necessarie per compilare il nostro codice, se avete una versione precedente di OpenSpin consiglio di aggiornarla.
Il programma non necessita di alcuna installazione, scompattate l’archivio e troverete il programma esegubile chiamato openspin(.exe). Consiglio di spostare il file in una cartella raggiungibile dalla variable di ambiente PATH per non dover scrivere il percorso completo ogni volta.
Adesso siamo pronti a compilare il sorgente, quindi andate nella cartella in cui è stato scaricato e digitate il comando
openspin -b -u -DKEYMAP_IT vt100.spin
Senza dilungarsi troppo sul significato dei parametri, -b e -u servono per generare il codice binario, il parametro -DKEYMAP_IT definisce la mappatura della tastiera, in questo caso italiano, e vt100.spin è il nome del file principale da compilare. Tutti gli altri file saranno inclusi automaticamente e non è necessario specificarli nel comando.
Esempio di compilazione:
propeller-vt100-terminal$ ./openspin -b -u -DKEYMAP_IT vt100.spin Propeller Spin/PASM Compiler 'OpenSpin' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor. Version 1.00.81 Compiled on Apr 27 2018 08:13:09 Compiling... vt100.spin |-usb-fs-host.spin |-com.serial.spin |-com.serial.terminal.spin |-com.serial.spin |-string.integer.spin |-waitvid.80x25.driver.spin |-generic8x16-2font.spin |-keymap_it.spin Done. Unused Method Elimination: 55 methods removed 1 objects removed 1092 bytes saved -------------------------- Program size is 14460 bytes
Se tutto è andato bene e non vengono visualizzati errori, trovete nella stessa cartella il file vt100.binary risultato dalla compilazione del sorgente. Questo file può essere scritto sulla EEPROM usando il programma Propeller Loader, se avete un adattatore PropPlug, oppure tramite un programmatore di EEPROM seriali.
Se la vostra tastiera non è italiana o volete utilizzare una mappatura diversa potete cambiare le ultime due lettere del parametro -DKEYMAP_IT con la sigla del paese che volete utilizzare tra quelli disponibili. Ad esempio openspin -b -u -DKEYMAP_US vt100.spin
per impostare la mappaura per le tastiere degli Stati Uniti, oppure openspin -b -u -DKEYMAP_UK vt100.spin
per le tastiere del Regno Unito. I paesi attualmente disponibili sono DE (Germania), FR (Francia), IT (Italia), UK (Regno Unito) e US (Stati Uniti).
Adesso che abbiamo verificato che la compilazione funziona correttamente possiamo procedere con le personalizzazioni. Ricordate che ogni volta che modificate il codice sorgente è necessario ripetere la procedura di compilazione e di scrittura sulla EEPROM come descritto sopra altrimenti le vostre modifiche non avranno alcun effetto.
Cursore
Con le impostazioni predefinite viene visualizzato un cursore grande e lampeggiante in pieno stile terminali anni ’70. La variable cursor.byte alla linea 103 del sorgente vt100.spin permette di modificare questa impostazione.
cursor.byte{CM} := (cursor.byte{CM} & constant(!CURSOR_MASK)) | constant(CURSOR_ON | CURSOR_BLOCK | CURSOR_FLASH)
Il parametro CURSOR_ON indica che il cursore è visible, CURSOR_BLOCK indica che deve essere visualizzato come un blocco intero e CURSOR_FLASH indica che deve lampeggiare. Cambiando questi parametri è possibile cambiare il cursore predefinito, ad esempio:
cursor.byte{CM} := (cursor.byte{CM} & constant(!CURSOR_MASK)) | constant(CURSOR_ON | CURSOR_ULINE | CURSOR_FLASH)
Visualizza il cursore come un piccolo rettangolo alla base del carattere in stile MS-DOS.
Sostituendo CURSOR_FLASH con CURSOR_SOLID si otterrà un cursore fisso e non più lampeggiante.
cursor.byte{CM} := (cursor.byte{CM} & constant(!CURSOR_MASK)) | constant(CURSOR_ON | CURSOR_BLOCK | CURSOR_SOLID)
I possibili parametri sono elencati più in alto nel sorgente.
CURSOR_ON = vga#CURSOR_ON CURSOR_OFF = vga#CURSOR_OFF CURSOR_ULINE = vga#CURSOR_ULINE CURSOR_BLOCK = vga#CURSOR_BLOCK CURSOR_FLASH = vga#CURSOR_FLASH CURSOR_SOLID = vga#CURSOR_SOLID
Nota: alcune sequenze VT-100 permettono di modificare lo stile del cursore, l’impostazione predefinita rimane in uso finchè non vengono utilizzate tali sequenze.
Tasti Speciali
Una normale tastiera non dispone solo dei tasti alfabetici e numerici ma anche di numerosi tasti speciali, come i tasti funzione, le frecce direzionali, ecc. che in ambito PC permettono di eseguire operazioni speciali. In un terminale tipo VT-100 alcuni di questi tasti hanno assegnata una sequenza di codici, altri non hanno alcuna funzione, semplicemente perchè non erano originariamente previsti nelle tastiere dell’epoca. Il firmware permette di associare una sequenza di codici ad ogni tasto, vediamo come è possibile cambiarla.
In fondo al sorgente vt100.spin troviamo una lunga lista di etichette a cui è stata associata una sequenza di byte.
strKeyInsert byte 0 strKeyHome byte $1B, "[H", 0 strKeyPageUp byte 0 strKeyDelete byte $7F, 0 strKeyEnd byte $1B, "[K", 0 strKeyPageDown byte 0 strKeyUp byte $1B, "OA", 0 strKeyDown byte $1B, "OB", 0 strKeyLeft byte $1B, "OD", 0 strKeyRight byte $1B, "OC", 0 strKeyShiftLeft byte 0 strKeyShiftRight byte 0
Le etichette dovrebbero essere abbastanza esplicative riguardo a quale tasto si riferiscono. In questo esempio possiamo vedere che per il tasto Insert non è associato alcun codice (0), mentre al tasto Home (Inizio) è associata la sequenza $1B, “[H”. Pertanto ogniqualvolta premiamo il tasto Insert nulla viene trasmesso al computer, mentre quando premiamo il tasto Home la sequenza indicata accanto all’etichetta viene trasmessa al computer e, se il programma in funzione è in grado di riconoscerla e gestirla, otterremo un effetto. Lo stesso discorso si applica ovviamente a tutte le altre etichette e i corrispondenti tasti.
Se vogliamo cambiare i codici che vengono inviati premendo un particolare tasto basta trovare la corrispondente etichetta e modificare la sequenza dopo l’istruzione byte secondo le nostre esigenze. Ricordatevi di terminare le sequenze con il codice 0 che, come nel linguaggio C, indica la fine della “stringa” di codici.
Supponiamo per esempio di voler inviare la parola “INS” quando si preme appunto il tasto Insert. Troviamo l’etichetta strKeyInsert e cambiamo la sequenza dopo l’istruzione byte come segue.
strKeyInsert byte "INS", 0
Ora, dopo aver compilato il sorgente e scritto il codice binario sulla EEPROM, ogni volta che premiamo il tasto Insert vedremo comparire sullo schermo la parola INS.
Possiamo anche scrivere le sequenze utilizzando il codice decimale o esadecimale di ogni singolo byte da inviare separandoli con una virgola.
strKeyInsert byte "INS", 13, 0 ' aggiunge il codice 13 del ritorno a capo strKeyInsert byte $49, $4E, $53, $0D, 0 ' equivalente al precedente ma in esadecimale
Ricordate che le sequenze di codici speciali devono essere interpretate dal programma che sta “girando” sul computer, se queste non sono riconosciute non otterranno il risultato desiderato e in alcuni casi potrebbero causare effetti indesiderati.
Tavolozza dei Colori
Il driver VGA è predisposto per visualizzare i caratteri e lo sfondo con un massimo di 16 colori, da una tavolozza di 64, utilizzando una mappatura simile a quella delle prime schede VGA, con un massimo di 16 colori per il primo piano e 8 colori per lo sfondo. La tavolozza è definita nel file waitvid.80×25.driver.spin tramite il blocco di righe dalla 70 alla 85.
long $82020282, $22020222, $A20202A2, $0A02020A, $8A02028A, $2A02022A, $AA0202AA long $02828202, $82828282, $22828222, $A28282A2, $0A82820A, $8A82828A, $2A82822A, $AA8282AA long $02222202, $82222282, $22222222, $A22222A2, $0A22220A, $8A22228A, $2A22222A, $AA2222AA long $02A2A202, $82A2A282, $22A2A222, $A2A2A2A2, $0AA2A20A, $8AA2A28A, $2AA2A22A, $AAA2A2AA long $020A0A02, $820A0A82, $220A0A22, $A20A0AA2, $0A0A0A0A, $8A0A0A8A, $2A0A0A2A, $AA0A0AAA long $028A8A02, $828A8A82, $228A8A22, $A28A8AA2, $0A8A8A0A, $8A8A8A8A, $2A8A8A2A, $AA8A8AAA long $022A2A02, $822A2A82, $222A2A22, $A22A2AA2, $0A2A2A0A, $8A2A2A8A, $2A2A2A2A, $AA2A2AAA long $02AAAA02, $82AAAA82, $22AAAA22, $A2AAAAA2, $0AAAAA0A, $8AAAAA8A, $2AAAAA2A, $AAAAAAAA long $02565602, $82565682, $22565622, $A25656A2, $0A56560A, $8A56568A, $2A56562A, $AA5656AA long $02C2C202, $82C2C282, $22C2C222, $A2C2C2A2, $0AC2C20A, $8AC2C28A, $2AC2C22A, $AAC2C2AA long $02323202, $82323282, $22323222, $A23232A2, $0A32320A, $8A32328A, $2A32322A, $AA3232AA long $02F6F602, $82F6F682, $22F6F622, $A2F6F6A2, $0AF6F60A, $8AF6F68A, $2AF6F62A, $AAF6F6AA long $020E0E02, $820E0E82, $220E0E22, $A20E0EA2, $0A0E0E0A, $8A0E0E8A, $2A0E0E2A, $AA0E0EAA long $02CECE02, $82CECE82, $22CECE22, $A2CECEA2, $0ACECE0A, $8ACECE8A, $2ACECE2A, $AACECEAA long $023E3E02, $823E3E82, $223E3E22, $A23E3EA2, $0A3E3E0A, $8A3E3E8A, $2A3E3E2A, $AA3E3EAA long $02FEFE02, $82FEFE82, $22FEFE22, $A2FEFEA2, $0AFEFE0A, $8AFEFE8A, $2AFEFE2A, $AAFEFEAA
A prima vista può sembrare un ammasso di dati senza senso ma in realtà è molto semplice decifrarne il significato. Ogni riga rappresenta un colore di primo piano mentre ogni colonna rappresenta un colore di sfondo, abbiamo quindi una griglia di 16 righe e 8 colonne. Ogni cella è un valore esadecimale che rappresenta il colore RGB da utilizzare per lo sfondo e il primo piano in modalità normale o quando il carattere deve lampeggiare.
Prendiamo per esempio il colore bianco su sfondo blu e vediamo come viene definito nella tavolozza. Il colore bianco di primo piano si trova alla riga numero 16 mentre il colore blu di sfondo si trova alla colonna 5, quindi come faremmo con la “battaglia navale” scorriamo la lista dall’alto in basso fino alla riga 16, quindi da sinistra verso destra fino alla colonna 5 e otteniamo il codice esadecimale $0AFEFE0A. Ogni gruppo di 2 cifre esadecimali rappresenta un byte e un colore RGB secondo il seguente schema.
| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | r r | g g | b b | 1 0 | r r | g g | b b | 1 0 | r r | g g | b b | 1 0 | r r | g g | b b | 1 0 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | 0 0 | 0 0 | 1 0 | 1 0 | 1 1 | 1 1 | 1 1 | 1 0 | 1 1 | 1 1 | 1 1 | 1 0 | 0 0 | 0 0 | 1 0 | 1 0 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | 0A (blu) | FE (bianco) | FE (bianco) | 0A (blu) |
Da sinistra a destra, il primo byte indica il colore di primo piano da utilizzare per il lampeggio, il secondo byte il colore di sfondo sempre durante il lampeggio, il terzo byte il colore di primo piano in modalità normale e il quarto byte il colore di sfondo sempre in modalità normale.
I bit 7-6 rappresentano la componente di colore rosso, i bit 5-4 la componente verde e i bit 3-2 la componente blu. I bit 1-0 devono essere mantenuti ai valori indicati 1 e 0 rispettivamente. Poichè ogni componente è rappresentata da 2 bit abbiamo un massimo di 4 livelli di intensità (00, 01, 10 e 11) quindi 4 * 4 * 4 = 64 combinazioni possibili che corrispondono ad altrettante tonalità di colore sullo schermo. Ad esempio $02 corrisponde al nero, $C2 corrisponde al rosso, $32 corrisponde al verde, $0E corrisponde al blu, $FE corrisponde al bianco, e così via.
Se volessimo cambiare il colore di primo piano e farlo diventare un giallo dobbiamo impostare le componenti rosso e verde all’intensità massima e la componente blu a zero, nei due byte centrali.
| 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | 7 6 5 4 3 2 1 0 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | r r | g g | b b | 1 0 | r r | g g | b b | 1 0 | r r | g g | b b | 1 0 | r r | g g | b b | 1 0 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | 0 0 | 0 0 | 1 0 | 1 0 | 1 1 | 1 1 | 0 0 | 1 0 | 1 1 | 1 1 | 0 0 | 1 0 | 0 0 | 0 0 | 1 0 | 1 0 | +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+ | 0A (blu) | F2 (giallo) | F2 (giallo) | 0A (blu) |
Quindi sostituendo il codice $0AFEFE0A con $0AF2F20A alla riga 16 e colonna 5 otteniamo il colore giallo su sfondo blu al posto del bianco.
Prova ad eseguire questa riga con l’interprete BASIC prima e dopo la modifica.
PRINT CHR$(27);"[1;37;44m";"WHITE ON BLUE;CHR$(27);"[0m"
Ora potete divertirvi a creare la tavolozza di colori che più vi soddisfa.