Da zero: come ho costruito la tastiera dei sogni dello sviluppatore

Pubblicato: 2022-03-11

Lavorando un giorno nell'agosto del 2007, non ho potuto fare a meno di rendermi conto che la mia normale tastiera per PC non mi serviva il più possibile. Ho dovuto muovere le mani tra i vari blocchi della tastiera in modo eccessivo, centinaia se non migliaia di volte al giorno, e le mie mani erano scomodamente vicine l'una all'altra. Dev'esserci un modo migliore, pensai.

Questa realizzazione è stata seguita da una travolgente sensazione di eccitazione mentre pensavo di personalizzare la migliore tastiera per gli sviluppatori - e più tardi, la consapevolezza che, come sviluppatore di software embedded freelance, ero irrimediabilmente all'oscuro dell'hardware.

All'epoca ero piuttosto impegnato con altri progetti, ma non passava giorno in cui non pensassi di costruire la tastiera hacker. Presto ho iniziato a dedicare il mio tempo libero a lavorare al progetto. Sono riuscito ad apprendere un insieme di abilità completamente nuovo, a persuadere un mio amico, Andras Volgyi, straordinario ingegnere meccanico, a partecipare al progetto, a riunire alcune persone chiave e a dedicare abbastanza tempo alla creazione di prototipi funzionanti. Al giorno d'oggi, la Ultimate Hacking Keyboard è una realtà. Stiamo facendo progressi quotidiani e il lancio della nostra campagna di crowdfunding è a portata di mano.

Ho iniziato pensando a come modificare il layout della tastiera e ho finito con questo!

Passare da un background software, senza sapere nulla di elettronica, alla progettazione e costruzione di un dispositivo hardware potente e commerciabile, è un'esperienza interessante e affascinante. In questo articolo, descriverò il design di come funziona questo capolavoro elettronico. Una conoscenza di base degli schemi dei circuiti elettronici può aiutarti a seguire.

Come si costruisce una tastiera?

Dopo aver dedicato migliaia di ore della mia vita a questo argomento, è una sfida impegnativa per me dare una risposta breve, ma c'è un modo interessante per rispondere a questa domanda. E se iniziassimo con qualcosa di semplice, come una scheda Arduino, e lo costruissimo gradualmente per diventare la Ultimate Hacking Keyboard? Non dovrebbe essere solo più digeribile ma estremamente educativo. Pertanto, che il nostro viaggio nel tutorial della tastiera abbia inizio!

Fase uno: una tastiera senza tasti

Per prima cosa, creiamo una tastiera USB che emetta il carattere x una volta al secondo. La scheda di sviluppo Arduino Micro è un candidato ideale per questo scopo, perché è dotata del microcontrollore ATmega32U4, un microcrontroller AVR e lo stesso processore che è il cervello dell'UHK.

La scheda Arduino Micro è stata la base per costruire la mia tastiera per gli sviluppatori.

Quando si tratta di microcontrollori AVR compatibili con USB, il Lightweight USB Framework for AVRs (LUFA) è la libreria preferita. Consente a questi processori di diventare il cervello di stampanti, dispositivi MIDI, tastiere o quasi qualsiasi altro tipo di dispositivo USB.

Quando si collega un dispositivo alla porta USB, il dispositivo deve trasferire alcune strutture di dati speciali chiamate descrittori USB. Questi descrittori comunicano al computer host il tipo e le proprietà del dispositivo connesso e sono rappresentati da una struttura ad albero. Per rendere le cose ancora più complesse, un dispositivo può implementare non solo una ma più funzioni. Vediamo la struttura dei descrittori dell'UHK:

  • Descrittore del dispositivo
    • Descrittore di configurazione
      • Descrittore di interfaccia 0: GenericHID
        • Descrittore dell'endpoint
      • Descrittore di interfaccia 1: Tastiera
        • Descrittore dell'endpoint
      • Descrittore di interfaccia 2: Mouse
        • Descrittore dell'endpoint

La maggior parte delle tastiere standard espone un solo descrittore dell'interfaccia della tastiera, il che ha senso. Tuttavia, come tastiera di programmazione personalizzata, l'UHK espone anche un descrittore dell'interfaccia del mouse, poiché l'utente può programmare tasti arbitrari della tastiera per controllare il puntatore del mouse in modo che la tastiera possa essere utilizzata come mouse. L'interfaccia GenericHID funge da canale di comunicazione, per lo scambio di informazioni di configurazione per tutte le funzioni speciali della tastiera. Puoi vedere l'implementazione completa del dispositivo e dei descrittori di configurazione dell'UHK in LUFA qui.

Ora che abbiamo creato i descrittori, è il momento di inviare il carattere x ogni secondo.

 uint8_t isSecondElapsed = 0; int main(void) { while (1) { _delay_us(1000); isSecondElapsed = 1; } } bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo, uint8_t* const ReportID, const uint8_t ReportType, void* ReportData, uint16_t* const ReportSize) { USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData; if (isSecondElapsed) { KeyboardReport->KeyCode[0] = HID_KEYBOARD_SC_X; isSecondElapsed = 0; } *ReportSize = sizeof(USB_KeyboardReport_Data_t); return false; }

USB è un protocollo di polling, il che significa che il computer host interroga il dispositivo a intervalli regolari (di solito 125 volte al secondo) per scoprire se ci sono nuovi dati da inviare. Il callback rilevante è la funzione CALLBACK_HID_Device_CreateHIDReport() , che in questo caso invia lo scancode del carattere x all'host ogni volta che la variabile isSecondElapsed contiene 1 . isSecondElapsed viene impostato su 1 dal ciclo principale al secondo e impostato su 0 dalla richiamata.

Fase due: una tastiera a quattro tasti

A questo punto la nostra tastiera non è poi così utile. Sarebbe bello se potessimo effettivamente digitarlo. Ma per questo abbiamo bisogno di chiavi, e le chiavi devono essere organizzate in una matrice di tastiera. Una tastiera a 104 tasti di dimensioni standard potrebbe avere 18 righe e 6 colonne, ma avremo semplicemente un'umile matrice di tastiera 2x2 per l'avvio. Questo è lo schema:

Per personalizzare una tastiera hacker, devi considerare attentamente la matrice dei tasti.

Ed ecco come appare su una breadboard:

La configurazione della breadboard è un passaggio fondamentale nella creazione di una tastiera per gli sviluppatori.

Supponendo che ROW1 sia connesso a PINA0 , ROW2 a PINA1 , PORTB0 COL1 COL2 a PORTB1 , ecco come appare il codice di scansione:

 /* A single pin of the microcontroller to which a row or column is connected. */ typedef struct { volatile uint8_t *Direction; volatile uint8_t *Name; uint8_t Number; } Pin_t; /* This part of the key matrix is stored in the Flash to save SRAM space. */ typedef struct { const uint8_t ColNum; const uint8_t RowNum; const Pin_t *ColPorts; const Pin_t *RowPins; } KeyMatrixInfo_t; /* This Part of the key matrix is stored in the SRAM. */ typedef struct { const __flash KeyMatrixInfo_t *Info; uint8_t *Matrix; } KeyMatrix_t; const __flash KeyMatrixInfo_t KeyMatrix = { .ColNum = 2, .RowNum = 2, .RowPins = (Pin_t[]) { { .Direction=&DDRA, .Name=&PINA, .Number=PINA0 }, { .Direction=&DDRA, .Name=&PINA, .Number=PINA1 } }, .ColPorts = (Pin_t[]) { { .Direction=&DDRB, .Name=&PORTB, .Number=PORTB0 }, { .Direction=&DDRB, .Name=&PORTB, .Number=PORTB1 }, } }; void KeyMatrix_Scan(KeyMatrix_t *KeyMatrix) { for (uint8_t Col=0; Col<KeyMatrix->Info->ColNum; Col++) { const Pin_t *ColPort = KeyMatrix->Info->ColPorts + Col; for (uint8_t Row=0; Row<KeyMatrix->Info->RowNum; Row++) { const Pin_t *RowPin = KeyMatrix->Info->RowPins + Row; uint8_t IsKeyPressed = *RowPin->Name & 1<<RowPin->Number; KeyMatrix_SetElement(KeyMatrix, Row, Col, IsKeyPressed); } } }

Il codice esegue la scansione di una colonna alla volta e all'interno di quella colonna legge gli stati dei singoli interruttori a chiave. Lo stato degli interruttori a chiave viene quindi salvato in un array. All'interno della nostra precedente funzione CALLBACK_HID_Device_CreateHIDReport() , i codici di scansione pertinenti verranno quindi inviati in base allo stato di quell'array.

Fase tre: una tastiera con due metà

Finora, abbiamo creato l'inizio di una tastiera normale. Ma in questo tutorial sulla tastiera puntiamo a un'ergonomia avanzata e, dato che le persone hanno due mani, è meglio aggiungere un'altra metà della tastiera al mix.

L'altra metà sarà caratterizzata da un'altra matrice di tastiera, che funzionerà allo stesso modo della precedente. La novità eccitante è la comunicazione tra le metà della tastiera. I tre protocolli più diffusi per l'interconnessione dei dispositivi elettronici sono SPI, I 2 C e UART. Per scopi pratici utilizzeremo UART in questo caso.

Per essere una buona tastiera di programmazione, deve esserci una comunicazione stellare tra le due metà.

La comunicazione bidirezionale scorre attraverso RX verso destra e attraverso TX verso sinistra secondo il diagramma sopra. VCC e GND sono necessari per trasferire potenza. UART ha bisogno che i peer utilizzino la stessa velocità di trasmissione, numero di bit di dati e numero di bit di stop. Una volta impostato il ricetrasmettitore UART di entrambi i peer, la comunicazione può iniziare a fluire.

Per ora, la metà sinistra della tastiera invia messaggi di un byte alla metà destra della tastiera tramite UART, rappresentando eventi di pressione o rilascio di tasti. La metà destra della tastiera elabora questi messaggi e manipola di conseguenza lo stato dell'intera matrice della tastiera in memoria. Ecco come la metà sinistra della tastiera invia i messaggi:

 USART_SendByte(IsKeyPressed<<7 | Row*COLS_NUM + Col);

Il codice per la metà destra della tastiera per ricevere il messaggio è simile al seguente:

 void KeyboardRxCallback(void) { uint8_t Event = USART_ReceiveByte(); if (!MessageBuffer_IsFull(&KeyStateBuffer)) { MessageBuffer_Insert(&KeyStateBuffer, Event); } }

Il gestore di interrupt KeyboardRxCallback() viene attivato ogni volta che un byte viene ricevuto tramite UART. Dato che i gestori di interrupt devono essere eseguiti il ​​più rapidamente possibile, il messaggio ricevuto viene inserito in un buffer ad anello per l'elaborazione successiva. Il buffer dell'anello alla fine viene elaborato dall'interno del ciclo principale e la matrice della tastiera verrà aggiornata in base al messaggio.

Quanto sopra è il modo più semplice per farlo accadere, ma il protocollo finale sarà un po' più complesso. I messaggi multibyte dovranno essere gestiti e l'integrità dei singoli messaggi dovrà essere verificata utilizzando i checksum CRC-CCITT.

A questo punto, il nostro prototipo di breadboard sembra piuttosto impressionante:

Il prototipo della breadboard sta iniziando a prendere la forma di una tastiera personalizzata per gli sviluppatori.

Fase quattro: incontra il display a LED

Uno dei nostri obiettivi con l'UHK era consentire all'utente di definire più mappe della tastiera specifiche dell'applicazione per aumentare ulteriormente la produttività. L'utente ha bisogno di un modo per essere a conoscenza dell'effettiva mappa dei tasti utilizzata, quindi un display LED integrato è integrato nella tastiera. Ecco un prototipo di display con tutti i LED accesi:

Il display a LED è fondamentale per creare la migliore tastiera per gli sviluppatori in questo tutorial.

Il display LED è implementato da una matrice LED 8x6:

Le tastiere degli hacker non sarebbero complete senza una matrice LED 8x6.

Ogni due file di simboli LED di colore rosso rappresentano i segmenti di uno dei display LED a 14 segmenti. I simboli LED bianchi rappresentano i tre indicatori di stato aggiuntivi.

Per guidare la corrente attraverso un LED e accenderlo, la colonna corrispondente è impostata su alta tensione e la riga corrispondente su bassa tensione. Un'interessante conseguenza di questo sistema è che, in un dato momento, può essere abilitata una sola colonna (tutti i led di quella colonna che dovrebbero essere accesi hanno le righe corrispondenti impostate in bassa tensione), mentre le altre colonne sono disabilitate . Si potrebbe pensare che questo sistema non possa funzionare per utilizzare l'intero set di LED, ma in realtà le colonne e le righe vengono aggiornate così rapidamente che l'occhio umano non vede lo sfarfallio.

La matrice LED è pilotata da due circuiti integrati (CI), uno che guida le sue righe e l'altro che guida le sue colonne. Il circuito integrato di origine che pilota le colonne è il driver LED PCA9634 I2C:

Due circuiti integrati pilotano la matrice LED sulla tastiera Ultimate Hacker.

L'IC sink a matrice di LED che guida le righe è il registro power shift TPIC6C595:

L'IC che guida le file di LED si presenta così.

Vediamo il codice relativo:

 uint8_t LedStates[LED_MATRIX_ROWS_NUM]; void LedMatrix_UpdateNextRow(bool IsKeyboardColEnabled) { TPIC6C595_Transmit(LedStates[ActiveLedMatrixRow]); PCA9634_Transmit(1 << ActiveLedMatrixRow); if (++ActiveLedMatrixRow == LED_MATRIX_ROWS_NUM) { ActiveLedMatrixRow = 0; } }

LedMatrix_UpdateNextRow() viene chiamato circa ogni millisecondo, aggiornando una riga della matrice LED. L'array LedStates memorizza lo stato dei singoli LED, viene aggiornato tramite UART in base ai messaggi originati dalla metà destra della tastiera, più o meno allo stesso modo del caso dell'evento pressione/rilascio tasto.

La grande immagine

Ormai abbiamo gradualmente costruito tutti i componenti necessari per la nostra tastiera hacker personalizzata ed è tempo di vedere il quadro generale. L'interno della tastiera è come una mini rete di computer: tanti nodi interconnessi. La differenza è che la distanza tra i nodi non si misura in metri o chilometri, ma in centimetri, ei nodi non sono computer a tutti gli effetti, ma minuscoli circuiti integrati.

L'interno della nostra tastiera tutorial è costituito da nodi interconnessi.

Finora è stato detto molto sui dettagli lato dispositivo della tastiera dello sviluppatore, ma non tanto su UHK Agent, il software lato host. Il motivo è che, a differenza dell'hardware e del firmware, Agent è molto rudimentale a questo punto. Tuttavia, viene decisa l'architettura di alto livello di Agent, che vorrei condividere.

UHK Agent è l'applicazione di configurazione tramite la quale è possibile personalizzare la tastiera in base alle esigenze dell'utente. Nonostante sia un rich client, Agent utilizza tecnologie Web e viene eseguito sulla piattaforma node-webkit.

L'agente comunica con la tastiera utilizzando la libreria node-usb inviando speciali richieste di controllo USB specifiche del dispositivo ed elaborandone i risultati. Utilizza Express.js per esporre un'API REST per l'utilizzo da parte di applicazioni di terze parti. Utilizza anche Angular.js per fornire un'interfaccia utente ordinata.

 var enumerationModes = { 'keyboard' : 0, 'bootloader-right' : 1, 'bootloader-left' : 2 }; function sendReenumerateCommand(enumerationMode, callback) { var AGENT_COMMAND_REENUMERATE = 0; sendAgentCommand(AGENT_COMMAND_REENUMERATE, enumerationMode, callback); } function sendAgentCommand(command, arg, callback) { setReport(new Buffer([command, arg]), callback); } function setReport(message, callback) { device.controlTransfer( 0x21, // bmRequestType (constant for this control request) 0x09, // bmRequest (constant for this control request) 0, // wValue (MSB is report type, LSB is report number) interfaceNumber, // wIndex (interface number) message, // message to be sent callback ); }

Ogni comando ha un identificatore a 8 bit e una serie di argomenti specifici del comando. Attualmente è implementato solo il comando re-enumerate. sendReenumerateCommand() fa rienumerare il dispositivo come bootloader sinistro o bootloader destro, per l'aggiornamento del firmware, o come dispositivo tastiera.

Si potrebbe non avere idea delle funzionalità avanzate che possono essere raggiunte da questo software, quindi ne cito alcune: l'agente sarà in grado di visualizzare l'usura delle singole chiavi e notificare all'utente la sua aspettativa di vita, in modo che l'utente possa acquistare un paio di nuovi interruttori a chiave per la riparazione imminente. L'agente fornirà anche un'interfaccia utente per la configurazione delle varie mappe dei tasti e dei livelli della tastiera dell'hacker. È anche possibile impostare la velocità e l'accelerazione del puntatore del mouse, insieme a molte altre funzionalità di uber. Il cielo è il limite.

Creazione del prototipo

Molto lavoro è dedicato alla creazione di prototipi di tastiera personalizzati. Innanzitutto, deve essere finalizzato il progetto meccanico che, di per sé, è piuttosto complesso e prevede parti in plastica progettate su misura, piastre in acciaio inossidabile tagliate al laser, guide in acciaio fresate di precisione e magneti al neodimio che tengono insieme le due metà della tastiera. Tutto è progettato in CAD prima dell'inizio della fabbricazione.

Il disegno CAD aiuta a costruire una tastiera che funzioni bene per gli sviluppatori.

Ecco come appare la custodia della tastiera stampata in 3D:

Abbiamo iniziato stampando in 3D la custodia della tastiera di programmazione.

Sulla base del progetto meccanico e dello schema, il circuito stampato deve essere progettato. Il PCB di destra ha questo aspetto in KiCad:

La programmazione di una tastiera inizia con la progettazione di un circuito stampato.

Quindi il PCB viene fabbricato e i componenti a montaggio superficiale devono essere saldati a mano:

La saldatura dei componenti della tastiera personalizzata assicura che funzioni correttamente una volta inserita nella custodia.

Infine, dopo aver fabbricato tutte le parti, inclusa la stampa 3D, la lucidatura e la verniciatura delle parti in plastica e l'assemblaggio di tutto, ci ritroviamo con un prototipo di tastiera hacker funzionante come questo:

Conclusione

Mi piace confrontare le tastiere degli sviluppatori con gli strumenti dei musicisti. Le tastiere sono oggetti abbastanza intimi se ci pensi. Dopotutto, li usiamo tutto il giorno per creare il software di domani, personaggio per personaggio.

Probabilmente a causa di quanto sopra, considero lo sviluppo della Ultimate Hacking Keyboard un privilegio e, nonostante tutte le difficoltà, il più delle volte è stato un viaggio molto emozionante e un'esperienza di apprendimento incredibilmente intensa.

Questo è un argomento ampio e potrei solo scalfire la superficie qui. La mia speranza è che questo articolo sia stato molto divertente e pieno di materiale interessante. In caso di domande, fatemelo sapere nei commenti.

Infine, puoi visitare https://ultimatehackingkeyboard.com per ulteriori informazioni e iscriverti lì per essere informato sul lancio della nostra campagna.