Desde cero: cómo construí el teclado de ensueño del desarrollador

Publicado: 2022-03-11

Trabajando un día en agosto de 2007, no pude evitar darme cuenta de que el teclado de mi PC normal no me servía tanto como fuera posible. Tenía que mover las manos entre los distintos bloques de mi teclado en exceso, cientos, si no miles, de veces al día, y mis manos estaban incómodamente cerca una de la otra. Debe haber una mejor manera, pensé.

Esta comprensión fue seguida por una abrumadora sensación de entusiasmo cuando pensé en personalizar el mejor teclado para desarrolladores y, más tarde, me di cuenta de que, como desarrollador independiente de software integrado, no tenía ni idea de hardware.

En ese momento, estaba bastante ocupado con otros proyectos, pero no pasaba un día sin que pensara en construir el teclado hacker. Pronto comencé a dedicar mi tiempo libre a trabajar en el proyecto. Logré aprender un conjunto de habilidades completamente nuevo, persuadir a un amigo mío, Andras Volgyi, un ingeniero mecánico extraordinario, para que se uniera al proyecto, reunir a algunas personas clave y dedicar suficiente tiempo a crear prototipos funcionales. Hoy en día, el Ultimate Hacking Keyboard es una realidad. Avanzamos día a día y el lanzamiento de nuestra campaña de crowdfunding está a nuestro alcance.

¡Empecé pensando en cómo cambiar la distribución del teclado y terminé con esto!

Pasar de una experiencia de software, sin saber nada sobre electrónica, a diseñar y construir un dispositivo de hardware potente y comercializable es una experiencia interesante y fascinante. En este artículo, describiré el diseño de cómo funciona esta obra maestra electrónica. Una comprensión básica de los diagramas de circuitos electrónicos puede ayudarlo a seguir.

¿Cómo se hace un teclado?

Después de dedicar miles de horas de mi vida a este tema, es un gran desafío para mí dar una respuesta breve, pero hay una forma interesante de responder a esta pregunta. ¿Qué sucede si comenzamos con algo simple, como una placa Arduino, y lo construimos gradualmente hasta convertirlo en el teclado Ultimate Hacking? No solo debe ser más digerible sino extremadamente educativo. Por lo tanto, ¡que comience nuestro viaje de tutoriales de teclado!

Paso uno: un teclado sin teclas

Primero, hagamos un teclado USB que emita el carácter x una vez por segundo. La placa de desarrollo Arduino Micro es un candidato ideal para este propósito, ya que cuenta con el microcontrolador ATmega32U4, un microcontrolador AVR y el mismo procesador que es el cerebro del UHK.

La placa Arduino Micro fue la base para construir mi teclado para desarrolladores.

Cuando se trata de microcontroladores AVR con capacidad USB, el marco USB ligero para AVR (LUFA) es la biblioteca preferida. Permite que estos procesadores se conviertan en el cerebro de impresoras, dispositivos MIDI, teclados o casi cualquier otro tipo de dispositivo USB.

Al conectar un dispositivo al puerto USB, el dispositivo tiene que transferir algunas estructuras de datos especiales llamadas descriptores USB. Estos descriptores le dicen a la computadora host el tipo y las propiedades del dispositivo que se está conectando y están representados por una estructura de árbol. Para hacer las cosas aún más complejas, un dispositivo puede implementar no solo una sino múltiples funciones. Veamos la estructura de descriptores de la UHK:

  • descriptor de dispositivo
    • Descriptor de configuración
      • Descriptor de interfaz 0: GenericHID
        • Descriptor de punto final
      • Descriptor de interfaz 1: Teclado
        • Descriptor de punto final
      • Descriptor de interfaz 2: Ratón
        • Descriptor de punto final

La mayoría de los teclados estándar solo exponen un único descriptor de interfaz de teclado, lo cual tiene sentido. Sin embargo, como un teclado de programación personalizado, el UHK también expone un descriptor de interfaz de mouse, porque el usuario puede programar teclas arbitrarias del teclado para controlar el puntero del mouse para que el teclado pueda usarse como un mouse. La interfaz GenericHID sirve como un canal de comunicación para intercambiar información de configuración para todas las funciones especiales del teclado. Puede ver la implementación completa del dispositivo y los descriptores de configuración de UHK en LUFA aquí.

Ahora que hemos creado los descriptores, es hora de enviar el carácter x en cada segundo.

 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 es un protocolo sondeado, lo que significa que la computadora host consulta el dispositivo en un intervalo regular (generalmente 125 veces por segundo) para averiguar si hay datos nuevos para enviar. La devolución de llamada relevante es la función CALLBACK_HID_Device_CreateHIDReport() , que en este caso envía el código de escaneo del carácter x al host siempre que la variable isSecondElapsed contenga 1 . isSecondElapsed se establece en 1 desde el bucle principal por segundo y se establece en 0 desde la devolución de llamada.

Paso dos: un teclado de cuatro teclas

A estas alturas nuestro teclado no es terriblemente útil. Sería bueno si pudiéramos escribir en él. Pero para eso necesitamos teclas, y las teclas deben organizarse en una matriz de teclado. Un teclado de 104 teclas de tamaño completo podría tener 18 filas y 6 columnas, pero simplemente tendremos una humilde matriz de teclado de 2x2 para comenzar. Este es el esquema:

Para personalizar un teclado hacker, debe considerar cuidadosamente la matriz de teclas.

Y así es como se ve en una protoboard:

La configuración de la placa de prueba es un paso crítico en la construcción de un teclado para desarrolladores.

Suponiendo que ROW1 está conectado a PINA0 , ROW2 a PINA1 , COL1 a PORTB0 y COL2 a PORTB1 , así es como se ve el código de escaneo:

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

El código escanea una columna a la vez y dentro de esa columna lee los estados de los interruptores de llave individuales. El estado de los interruptores de tecla se guarda en una matriz. Dentro de nuestra función CALLBACK_HID_Device_CreateHIDReport() anterior, los códigos de escaneo relevantes se enviarán según el estado de esa matriz.

Paso tres: un teclado con dos mitades

Hasta ahora, hemos creado los inicios de un teclado normal. Pero en este tutorial de teclado apuntamos a una ergonomía avanzada, y dado que las personas tienen dos manos, es mejor que agreguemos otra mitad de teclado a la mezcla.

La otra mitad contará con otra matriz de teclado, funcionando de la misma manera que la anterior. Lo nuevo y emocionante es la comunicación entre las mitades del teclado. Los tres protocolos más populares para interconectar dispositivos electrónicos son SPI, I 2 C y UART. A efectos prácticos utilizaremos UART en este caso.

Para ser un buen teclado de programación, tiene que haber una comunicación estelar entre ambas mitades.

La comunicación bidireccional fluye a través de RX hacia la derecha y a través de TX hacia la izquierda de acuerdo con el diagrama anterior. VCC y GND son necesarios para transferir energía. UART necesita que los pares usen la misma velocidad en baudios, número de bits de datos y número de bits de parada. Una vez que se configura el transceptor UART de ambos pares, la comunicación puede comenzar a fluir.

Por ahora, la mitad izquierda del teclado envía mensajes de un byte a la mitad derecha del teclado a través de UART, lo que representa eventos de pulsación o liberación de teclas. La mitad derecha del teclado procesa estos mensajes y manipula el estado de la matriz de matriz de teclado completo en la memoria en consecuencia. Así es como la mitad izquierda del teclado envía mensajes:

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

El código para que la mitad derecha del teclado reciba el mensaje se ve así:

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

El controlador de interrupciones KeyboardRxCallback() se activa cada vez que se recibe un byte a través de UART. Dado que los controladores de interrupciones deben ejecutarse lo más rápido posible, el mensaje recibido se coloca en un búfer de anillo para su posterior procesamiento. El búfer de anillo finalmente se procesa desde dentro del bucle principal y la matriz del teclado se actualizará según el mensaje.

Lo anterior es la forma más sencilla de hacer que esto suceda, pero el protocolo final será algo más complejo. Los mensajes de varios bytes deberán manejarse y los mensajes individuales deberán verificarse para verificar su integridad mediante el uso de sumas de verificación CRC-CCITT.

En este punto, nuestro prototipo de tablero se ve bastante impresionante:

El prototipo de placa de prueba está comenzando a tomar la forma de un teclado personalizado para desarrolladores.

Paso cuatro: conozca la pantalla LED

Uno de nuestros objetivos con UHK era permitir al usuario definir múltiples mapas de teclado específicos de la aplicación para aumentar aún más la productividad. El usuario necesita alguna forma de estar al tanto del mapa de teclas real que se está utilizando, por lo que se incorpora una pantalla LED integrada en el teclado. Aquí hay una pantalla prototipo con todos los LED encendidos:

La pantalla LED es fundamental para construir el mejor teclado para desarrolladores en este tutorial.

La pantalla LED se implementa mediante una matriz LED de 8x6:

Los teclados de hackers no estarían completos sin una matriz LED de 8x6.

Cada dos filas de símbolos LED de color rojo representa los segmentos de una de las pantallas LED de 14 segmentos. Los símbolos LED blancos representan los tres indicadores de estado adicionales.

Para conducir la corriente a través de un LED y encenderlo, la columna correspondiente se establece en alto voltaje y la fila correspondiente en bajo voltaje. Una consecuencia interesante de este sistema es que, en un momento dado, solo se puede habilitar una columna (todos los LED de esa columna que deben estar encendidos tienen sus filas correspondientes configuradas en bajo voltaje), mientras que el resto de las columnas están deshabilitadas. . Uno podría pensar que este sistema no puede funcionar para usar el conjunto completo de LED, pero en realidad las columnas y filas se actualizan tan rápido que el ojo humano no puede ver el parpadeo.

La matriz de LED está impulsada por dos circuitos integrados (IC), uno que controla sus filas y el otro que controla sus columnas. El IC fuente que impulsa las columnas es el controlador LED PCA9634 I2C:

Dos circuitos integrados impulsan la matriz de LED en el Ultimate Hacker Keyboard.

El IC disipador de matriz de LED que controla las filas es el registro de cambio de potencia TPIC6C595:

El IC que impulsa las filas de LED se ve así.

Veamos el código correspondiente:

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

Se llama a LedMatrix_UpdateNextRow() cada milisegundo, actualizando una fila de la matriz LED. La matriz LedStates almacena el estado de los LED individuales, se actualiza a través de UART en función de los mensajes originados en la mitad derecha del teclado, prácticamente de la misma manera que en el caso del evento de presionar/liberar tecla.

El panorama

A estas alturas, hemos construido gradualmente todos los componentes necesarios para nuestro teclado hacker personalizado, y es hora de ver el panorama general. El interior del teclado es como una mini red informática: muchos nodos interconectados. La diferencia es que la distancia entre los nodos no se mide en metros o kilómetros, sino en centímetros, y los nodos no son computadoras completas, sino pequeños circuitos integrados.

El interior de nuestro teclado tutorial se compone de nodos interconectados.

Mucho se ha dicho hasta ahora sobre los detalles del lado del dispositivo del teclado del desarrollador, pero no tanto sobre UHK Agent, el software del lado del host. La razón es que, a diferencia del hardware y el firmware, Agent es muy rudimentario en este punto. Sin embargo, se decide la arquitectura de alto nivel de Agent, que me gustaría compartir.

UHK Agent es la aplicación de configuración a través de la cual se puede personalizar el teclado para adaptarse a las necesidades del usuario. A pesar de ser un cliente enriquecido, Agent utiliza tecnologías web y se ejecuta sobre la plataforma node-webkit.

El agente se comunica con el teclado mediante la biblioteca node-usb mediante el envío de solicitudes especiales de control USB específicas del dispositivo y el procesamiento de sus resultados. Utiliza Express.js para exponer una API REST para el consumo de aplicaciones de terceros. También utiliza Angular.js para proporcionar una interfaz de usuario ordenada.

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

Cada comando tiene un identificador de 8 bits y un conjunto de argumentos específicos del comando. Actualmente, solo se implementa el comando volver a enumerar. sendReenumerateCommand() hace que el dispositivo vuelva a enumerarse como el cargador de arranque izquierdo o el cargador de arranque derecho, para actualizar el firmware o como un dispositivo de teclado.

Es posible que uno no tenga idea de las funciones avanzadas que puede lograr este software, así que nombraré algunas: Agent podrá visualizar el desgaste de las teclas individuales y notificar al usuario sobre su expectativa de vida, para que el usuario pueda compre un par de interruptores de llave nuevos para la reparación inminente. El agente también proporcionará una interfaz de usuario para configurar los distintos mapas de teclas y capas del teclado del hacker. La velocidad y la aceleración del puntero del mouse también se pueden configurar, junto con muchas otras características súper. El cielo es el límite.

Crear el prototipo

Se dedica mucho trabajo a la creación de prototipos de teclado personalizados. En primer lugar, se debe finalizar el diseño mecánico, que es bastante complejo en sí mismo e involucra piezas de plástico diseñadas a medida, placas de acero inoxidable cortadas con láser, guías de acero fresadas con precisión e imanes de neodimio que mantienen unidas las dos mitades del teclado. Todo está diseñado en CAD antes de que comience la fabricación.

El dibujo CAD ayuda a construir un teclado que funcione bien para los desarrolladores.

Así es como se ve la funda del teclado impreso en 3D:

Comenzamos imprimiendo en 3D la carcasa del teclado de programación.

Con base en el diseño mecánico y el esquema, se debe diseñar la placa de circuito impreso. El PCB de la derecha se ve así en KiCad:

La programación de un teclado comienza con el diseño de una placa de circuito impreso.

Luego se fabrica la PCB y los componentes montados en la superficie deben soldarse a mano:

Soldar los componentes del teclado personalizado garantiza que funcione correctamente una vez que esté en el estuche.

Finalmente, después de fabricar todas las piezas, incluida la impresión 3D, pulir y pintar las piezas de plástico y ensamblar todo, terminamos con un prototipo de teclado hacker que funciona como este:

Conclusión

Me gusta comparar los teclados de los desarrolladores con los instrumentos de los músicos. Los teclados son objetos bastante íntimos si lo piensas bien. Después de todo, los usamos todo el día para crear el software del mañana, personaje por personaje.

Probablemente debido a lo anterior, considero que desarrollar Ultimate Hacking Keyboard es un privilegio y, a pesar de todas las dificultades, la mayoría de las veces ha sido un viaje muy emocionante y una experiencia de aprendizaje increíblemente intensa.

Este es un tema amplio, y solo podría rascar la superficie aquí. Mi esperanza es que este artículo haya sido muy divertido y lleno de material interesante. Si tiene alguna pregunta, por favor hágamelo saber en los comentarios.

Por último, puede visitar https://ultimatehackingkeyboard.com para obtener más información y suscribirse allí para recibir notificaciones sobre el lanzamiento de nuestra campaña.