À partir de zéro : comment j'ai construit le clavier de rêve du développeur

Publié: 2022-03-11

Travaillant un jour d'août 2007, je n'ai pas pu m'empêcher de réaliser que mon clavier de PC habituel ne me servait pas autant que possible. Je devais déplacer excessivement mes mains entre les différents blocs de mon clavier, des centaines voire des milliers de fois par jour, et mes mains étaient inconfortablement proches les unes des autres. Il doit y avoir un meilleur moyen, pensai-je.

Cette prise de conscience a été suivie d'un sentiment d'excitation accablant alors que je pensais à personnaliser le meilleur clavier pour les développeurs - et plus tard, la réalisation qu'en tant que développeur de logiciels embarqués indépendant, j'étais désespérément ignorant du matériel.

A l'époque, j'étais pas mal occupé avec d'autres projets, mais pas un jour ne passait sans que je ne pense à construire le clavier hacker. Bientôt, j'ai commencé à consacrer mon temps libre à travailler sur le projet. J'ai réussi à acquérir un tout nouvel ensemble de compétences, à persuader un de mes amis, Andras Volgyi, ingénieur en mécanique extraordinaire, de se joindre au projet, de rassembler des personnes clés et de consacrer suffisamment de temps à la création de prototypes fonctionnels. De nos jours, l'Ultimate Hacking Keyboard est une réalité. Nous progressons quotidiennement et le lancement de notre campagne de financement participatif est à portée de main.

J'ai commencé par réfléchir à la façon de changer la disposition du clavier, et j'ai fini avec ça !

Passer d'une formation en logiciel, ne connaissant rien à l'électronique, à la conception et à la construction d'un dispositif matériel puissant et commercialisable, est une expérience intéressante et fascinante. Dans cet article, je vais décrire la conception du fonctionnement de ce chef-d'œuvre électronique. Une compréhension de base des schémas de circuits électroniques peut vous aider à suivre.

Comment fabrique-t-on un clavier ?

Après avoir consacré des milliers d'heures de ma vie à ce sujet, c'est un défi de taille pour moi de donner une réponse courte, mais il existe une façon intéressante de répondre à cette question. Et si nous commencions avec quelque chose de simple, comme une carte Arduino, et que nous le développions progressivement pour devenir le Ultimate Hacking Keyboard ? Il doit non seulement être plus digeste mais extrêmement pédagogique. Par conséquent, laissez notre voyage de didacticiel clavier commencer!

Première étape : un clavier sans touches

Tout d'abord, créons un clavier USB qui émet le caractère x une fois par seconde. La carte de développement Arduino Micro est un candidat idéal à cet effet, car elle comprend le microcontrôleur ATmega32U4 - un microcontrôleur AVR et le même processeur qui est le cerveau de l'UHK.

La carte Arduino Micro a servi de base à la construction de mon clavier pour les développeurs.

En ce qui concerne les microcontrôleurs AVR compatibles USB, le LUFA (Lightweight USB Framework for AVRs) est la bibliothèque de choix. Il permet à ces processeurs de devenir le cerveau des imprimantes, des périphériques MIDI, des claviers ou de presque tout autre type de périphérique USB.

Lorsque vous branchez un appareil sur le port USB, l'appareil doit transférer certaines structures de données spéciales appelées descripteurs USB. Ces descripteurs indiquent à l'ordinateur hôte le type et les propriétés du périphérique connecté et sont représentés par une structure arborescente. Pour rendre les choses encore plus complexes, un appareil peut implémenter non seulement une mais plusieurs fonctions. Voyons la structure des descripteurs de l'UHK :

  • Descripteur d'appareil
    • Descripteur de configuration
      • Descripteur d'interface 0 : GenericHID
        • Descripteur de point final
      • Descripteur d'interface 1 : Clavier
        • Descripteur de point final
      • Descripteur d'interface 2 : Souris
        • Descripteur de point final

La plupart des claviers standard n'exposent qu'un seul descripteur d'interface clavier, ce qui est logique. Cependant, en tant que clavier de programmation personnalisé, l'UHK expose également un descripteur d'interface de souris, car l'utilisateur peut programmer des touches arbitraires du clavier pour contrôler le pointeur de la souris afin que le clavier puisse être utilisé comme une souris. L'interface GenericHID sert de canal de communication, pour échanger des informations de configuration pour toutes les fonctionnalités spéciales du clavier. Vous pouvez voir la mise en œuvre complète des descripteurs de périphérique et de configuration de l'UHK dans LUFA ici.

Maintenant que nous avons créé les descripteurs, il est temps d'envoyer le caractère x à chaque seconde.

 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; }

L'USB est un protocole interrogé, ce qui signifie que l'ordinateur hôte interroge l'appareil à intervalles réguliers (généralement 125 fois par seconde) pour savoir s'il y a de nouvelles données à envoyer. Le rappel pertinent est la fonction CALLBACK_HID_Device_CreateHIDReport() , qui dans ce cas envoie le scancode du caractère x à l'hôte chaque fois que la variable isSecondElapsed contient 1 . isSecondElapsed est défini sur 1 à partir de la boucle principale sur une base par seconde et défini sur 0 à partir du rappel.

Deuxième étape : un clavier à quatre touches

À ce stade, notre clavier n'est pas très utile. Ce serait bien si nous pouvions taper dessus. Mais pour cela, nous avons besoin de touches, et les touches doivent être disposées dans une matrice de clavier. Un clavier complet de 104 touches pourrait avoir 18 lignes et 6 colonnes, mais nous aurons simplement une humble matrice de clavier 2x2 pour le démarrage. Voici le schéma :

Pour personnaliser un clavier pirate, vous devez examiner attentivement la matrice de touches.

Et voici à quoi cela ressemble sur une planche à pain:

La configuration de la planche à pain est une étape critique dans la construction d'un clavier pour les développeurs.

En supposant que ROW1 est connecté à PINA0 , ROW2 à PINA1 , COL1 à PORTB0 et COL2 à PORTB1 , voici à quoi ressemble le code de numérisation :

 /* 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); } } }

Le code analyse une colonne à la fois et dans cette colonne, il lit les états des interrupteurs à clé individuels. L'état des commutateurs à clé est ensuite enregistré dans un tableau. Dans notre précédente fonction CALLBACK_HID_Device_CreateHIDReport() , les codes de numérisation pertinents seront ensuite envoyés en fonction de l'état de ce tableau.

Troisième étape : un clavier à deux moitiés

Jusqu'à présent, nous avons créé les débuts d'un clavier normal. Mais dans ce didacticiel sur le clavier, nous visons une ergonomie avancée, et étant donné que les gens ont deux mains, nous ferions mieux d'ajouter une autre moitié de clavier au mélange.

L'autre moitié comportera une autre matrice de clavier, fonctionnant de la même manière que la précédente. La nouveauté passionnante est la communication entre les moitiés du clavier. Les trois protocoles les plus populaires pour interconnecter les appareils électroniques sont SPI, I 2 C et UART. Pour des raisons pratiques, nous utiliserons UART dans ce cas.

Pour être un bon clavier de programmation, il doit y avoir une communication stellaire entre les deux moitiés.

La communication bidirectionnelle passe par RX vers la droite et par TX vers la gauche selon le schéma ci-dessus. VCC et GND sont nécessaires pour transférer la puissance. L'UART a besoin que les pairs utilisent le même débit en bauds, le même nombre de bits de données et le même nombre de bits d'arrêt. Une fois que l'émetteur-récepteur UART des deux pairs est configuré, la communication peut commencer à circuler.

Pour l'instant, la moitié gauche du clavier envoie des messages d'un octet à la moitié droite du clavier via UART, représentant les événements d'appui ou de relâchement de touche. La moitié droite du clavier traite ces messages et manipule l'état de la matrice complète du clavier en mémoire en conséquence. Voici comment la moitié gauche du clavier envoie des messages :

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

Le code pour que la moitié droite du clavier reçoive le message ressemble à ceci :

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

Le gestionnaire d'interruption KeyboardRxCallback() est déclenché chaque fois qu'un octet est reçu via UART. Étant donné que les gestionnaires d'interruption doivent s'exécuter aussi rapidement que possible, le message reçu est placé dans un tampon en anneau pour un traitement ultérieur. Le tampon circulaire est finalement traité à partir de la boucle principale et la matrice du clavier sera mise à jour en fonction du message.

Ce qui précède est le moyen le plus simple d'y parvenir, mais le protocole final sera un peu plus complexe. Les messages multi-octets devront être traités et l'intégrité des messages individuels devra être vérifiée à l'aide de sommes de contrôle CRC-CCITT.

À ce stade, notre prototype de planche à pain semble assez impressionnant :

Le prototype de planche à pain commence à prendre la forme d'un clavier personnalisé pour les développeurs.

Quatrième étape : rencontrez l'écran LED

L'un de nos objectifs avec l'UHK était de permettre à l'utilisateur de définir plusieurs cartes de clavier spécifiques à l'application pour augmenter encore la productivité. L'utilisateur a besoin d'un moyen d'être conscient de la configuration de clavier réelle utilisée, donc un affichage LED intégré est intégré au clavier. Voici un prototype d'affichage avec toutes les LED allumées :

L'affichage LED est essentiel pour créer le meilleur clavier pour les développeurs dans ce didacticiel.

L'affichage LED est mis en œuvre par une matrice LED 8x6 :

Les claviers Hacker ne seraient pas complets sans une matrice LED 8x6.

Toutes les deux rangées de symboles LED de couleur rouge représentent les segments de l'un des affichages LED à 14 segments. Les symboles LED blancs représentent les trois indicateurs d'état supplémentaires.

Pour conduire le courant à travers une LED et l'allumer, la colonne correspondante est réglée sur haute tension et la rangée correspondante sur basse tension. Une conséquence intéressante de ce système est qu'à un moment donné, une seule colonne peut être activée (toutes les LED de cette colonne qui doivent être allumées ont leurs lignes correspondantes réglées sur basse tension), tandis que les autres colonnes sont désactivées. . On pourrait penser que ce système ne peut pas fonctionner pour utiliser l'ensemble complet de LED, mais en réalité, les colonnes et les lignes sont mises à jour si rapidement qu'aucun scintillement ne peut être vu par l'œil humain.

La matrice LED est pilotée par deux circuits intégrés (CI), l'un pilotant ses lignes et l'autre pilotant ses colonnes. Le circuit intégré source qui pilote les colonnes est le pilote de LED I2C PCA9634 :

Deux circuits intégrés pilotent la matrice LED sur le clavier Ultimate Hacker.

Le circuit intégré de dissipateur de matrice de LED qui pilote les lignes est le registre à décalage de puissance TPIC6C595 :

Le circuit intégré qui pilote les rangées de LED ressemble à ceci.

Voyons le code correspondant :

 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() est appelée environ toutes les millisecondes, mettant à jour une ligne de la matrice LED. Le tableau LedStates stocke l'état des LED individuelles, est mis à jour via UART en fonction des messages provenant de la moitié droite du clavier, à peu près de la même manière que dans le cas de l'événement d'appui/relâchement de touche.

La grande image

À présent, nous avons progressivement construit tous les composants nécessaires pour notre clavier de pirate personnalisé, et il est temps de voir la situation dans son ensemble. L'intérieur du clavier ressemble à un mini réseau informatique : de nombreux nœuds interconnectés. La différence est que la distance entre les nœuds n'est pas mesurée en mètres ou en kilomètres, mais en centimètres, et les nœuds ne sont pas des ordinateurs à part entière, mais de minuscules circuits intégrés.

L'intérieur de notre clavier didacticiel est composé de nœuds interconnectés.

Jusqu'à présent, beaucoup de choses ont été dites sur les détails côté périphérique du clavier du développeur, mais pas tellement sur UHK Agent, le logiciel côté hôte. La raison en est que, contrairement au matériel et au micrologiciel, Agent est très rudimentaire à ce stade. Cependant, l'architecture de haut niveau d'Agent est décidée, ce que j'aimerais partager.

UHK Agent est l'application de configuration via laquelle le clavier peut être personnalisé pour répondre aux besoins de l'utilisateur. Bien qu'il s'agisse d'un client riche, l'agent utilise des technologies Web et s'exécute au-dessus de la plate-forme node-webkit.

L'agent communique avec le clavier à l'aide de la bibliothèque node-usb en envoyant des demandes de contrôle USB spéciales et spécifiques à l'appareil et en traitant leurs résultats. Il utilise Express.js pour exposer une API REST destinée à être utilisée par des applications tierces. Il utilise également Angular.js pour fournir une interface utilisateur soignée.

 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 ); }

Chaque commande a un identifiant 8 bits et un ensemble d'arguments spécifiques à la commande. Actuellement, seule la commande re-enumerate est implémentée. Le sendReenumerateCommand() permet au périphérique de ré-énumérer en tant que chargeur de démarrage gauche ou chargeur de démarrage droit, pour mettre à niveau le micrologiciel ou en tant que périphérique clavier.

On n'a peut-être aucune idée des fonctionnalités avancées qui peuvent être réalisées par ce logiciel, alors j'en nommerai quelques-unes : l'agent pourra visualiser l'usure des clés individuelles et informer l'utilisateur de leur espérance de vie, afin que l'utilisateur puisse acheter quelques nouveaux interrupteurs à clé pour la réparation imminente. L'agent fournira également une interface utilisateur pour configurer les différentes cartes de touches et couches du clavier du pirate. La vitesse et l'accélération du pointeur de la souris peuvent également être définies, ainsi que de nombreuses autres fonctionnalités. Le ciel est la limite.

Création du prototype

Beaucoup de travail est consacré à la création de prototypes de clavier personnalisés. Tout d'abord, la conception mécanique doit être finalisée, ce qui est assez complexe en soi et implique des pièces en plastique conçues sur mesure, des plaques en acier inoxydable découpées au laser, des guides en acier fraisés avec précision et des aimants en néodyme qui maintiennent ensemble les deux moitiés du clavier. Tout est conçu en CAO avant le début de la fabrication.

Le dessin CAO aide à créer un clavier qui fonctionne bien pour les développeurs.

Voici à quoi ressemble l'étui clavier imprimé en 3D :

Nous avons commencé par imprimer en 3D le boîtier du clavier de programmation.

Sur la base de la conception mécanique et du schéma, la carte de circuit imprimé doit être conçue. Le PCB de droite ressemble à ceci dans KiCad :

La programmation d'un clavier commence par la conception d'une carte de circuit imprimé.

Ensuite, le PCB est fabriqué et les composants montés en surface doivent être soudés à la main :

La soudure des composants du clavier personnalisé garantit qu'il fonctionne correctement une fois qu'il est dans le boîtier.

Enfin, après avoir fabriqué toutes les pièces, y compris l'impression 3D, le polissage et la peinture des pièces en plastique et tout assemblé, nous nous retrouvons avec un prototype de clavier hacker fonctionnel comme celui-ci :

Conclusion

J'aime comparer les claviers des développeurs aux instruments des musiciens. Les claviers sont des objets assez intimes si on y pense. Après tout, nous les utilisons toute la journée pour créer le logiciel de demain, personnage par personnage.

Probablement à cause de ce qui précède, je considère le développement de l'Ultimate Hacking Keyboard comme un privilège, et malgré toutes les difficultés, le plus souvent, cela a été un voyage très excitant et une expérience d'apprentissage incroyablement intense.

C'est un vaste sujet, et je ne pouvais qu'effleurer la surface ici. J'espère que cet article a été très amusant et plein de matériel intéressant. Si vous avez des questions, n'hésitez pas à me le faire savoir dans les commentaires.

Enfin, vous êtes invités à visiter https://ultimatehackingkeyboard.com pour plus d'informations et à vous abonner pour être informé du lancement de notre campagne.