Dari Bawah ke Atas: Bagaimana Saya Membangun Papan Ketik Impian Pengembang

Diterbitkan: 2022-03-11

Bekerja suatu hari di bulan Agustus 2007, saya menyadari bahwa keyboard PC biasa saya tidak melayani saya sebanyak mungkin. Saya harus menggerakkan tangan saya di antara berbagai blok keyboard saya secara berlebihan, ratusan bahkan ribuan kali per hari, dan tangan saya saling berdekatan dengan tidak nyaman. Pasti ada cara yang lebih baik, pikirku.

Kesadaran ini diikuti oleh perasaan gembira yang luar biasa saat saya berpikir untuk menyesuaikan keyboard terbaik untuk pengembang - dan kemudian, kesadaran bahwa, sebagai pengembang perangkat lunak tertanam lepas, saya sama sekali tidak tahu apa-apa tentang perangkat keras.

Pada saat itu, saya cukup sibuk dengan proyek lain, tetapi tidak sehari pun saya tidak berpikir untuk membuat keyboard hacker. Segera saya mulai mendedikasikan waktu luang saya untuk mengerjakan proyek tersebut. Saya berhasil mempelajari serangkaian keterampilan baru, membujuk teman saya, Andras Volgyi, insinyur mesin yang luar biasa, untuk bergabung dalam proyek, mengumpulkan beberapa orang penting, dan mencurahkan cukup waktu untuk membuat prototipe yang berfungsi. Saat ini, Ultimate Hacking Keyboard adalah kenyataan. Kami membuat kemajuan setiap hari, dan peluncuran kampanye crowdfunding kami sudah dekat.

Saya mulai dengan memikirkan cara mengubah tata letak keyboard, dan selesai dengan ini!

Mulai dari latar belakang perangkat lunak, tidak tahu apa-apa tentang elektronik, hingga merancang dan membangun perangkat keras yang kuat dan dapat dipasarkan, adalah pengalaman yang menarik dan mempesona. Pada artikel ini, saya akan menjelaskan desain bagaimana karya elektronik ini bekerja. Pemahaman dasar diagram sirkuit elektronik dapat membantu Anda mengikuti.

Bagaimana cara membuat papan ketik?

Setelah mendedikasikan ribuan jam hidup saya untuk topik ini, merupakan tantangan berat bagi saya untuk memberikan jawaban singkat, tetapi ada cara yang menarik untuk menjawab pertanyaan ini. Bagaimana jika kita mulai dengan sesuatu yang sederhana, seperti papan Arduino, dan secara bertahap membangunnya menjadi Keyboard Peretasan Utama? Seharusnya tidak hanya lebih mudah dicerna tetapi juga sangat mendidik. Oleh karena itu, biarkan perjalanan tutorial keyboard kami dimulai!

Langkah Satu: Papan Ketik Tanpa Tombol

Pertama, mari kita buat keyboard USB yang memancarkan karakter x sekali per detik. Papan pengembangan Mikro Arduino adalah kandidat yang ideal untuk tujuan ini, karena ia memiliki fitur mikrokontroler ATmega32U4 - mikrokontroler AVR dan prosesor yang sama yang merupakan otak dari UHK.

Papan Mikro Arduino adalah dasar untuk membangun keyboard saya untuk pengembang.

Untuk mikrokontroler AVR berkemampuan USB, Lightweight USB Framework for AVRs (LUFA) adalah perpustakaan pilihan. Ini memungkinkan prosesor ini menjadi otak dari printer, perangkat MIDI, keyboard, atau hampir semua jenis perangkat USB lainnya.

Saat menghubungkan perangkat ke port USB, perangkat harus mentransfer beberapa struktur data khusus yang disebut deskriptor USB. Deskriptor ini memberi tahu komputer host jenis dan properti perangkat yang terhubung, dan diwakili oleh struktur pohon. Untuk membuat masalah menjadi lebih kompleks, perangkat dapat mengimplementasikan tidak hanya satu tetapi beberapa fungsi. Mari kita lihat struktur deskriptor dari UHK:

  • Deskripsi perangkat
    • Deskriptor konfigurasi
      • Deskriptor antarmuka 0: GenericHID
        • Deskriptor titik akhir
      • Deskriptor antarmuka 1: Keyboard
        • Deskriptor titik akhir
      • Deskriptor antarmuka 2: Mouse
        • Deskriptor titik akhir

Sebagian besar keyboard standar hanya menampilkan deskriptor antarmuka keyboard tunggal, yang masuk akal. Namun, sebagai keyboard pemrograman khusus, UHK juga menampilkan deskriptor antarmuka mouse, karena pengguna dapat memprogram tombol arbitrer keyboard untuk mengontrol penunjuk mouse sehingga keyboard dapat digunakan sebagai mouse. Antarmuka GenericHID berfungsi sebagai saluran komunikasi, untuk bertukar informasi konfigurasi untuk semua fitur khusus keyboard. Anda dapat melihat implementasi lengkap perangkat dan deskriptor konfigurasi UHK di LUFA di sini.

Sekarang setelah kita membuat deskriptor, saatnya mengirim karakter x setiap detik.

 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 adalah protokol polling, yang berarti bahwa komputer host menanyakan perangkat secara berkala (biasanya 125 kali per detik) untuk mengetahui apakah ada data baru untuk dikirim. Callback yang relevan adalah fungsi CALLBACK_HID_Device_CreateHIDReport() , yang dalam hal ini mengirimkan scancode karakter x ke host setiap kali variabel isSecondElapsed berisi 1 . isSecondElapsed disetel ke 1 dari loop utama per detik, dan disetel ke 0 dari panggilan balik.

Langkah Kedua: Papan Ketik Empat Tombol

Pada titik ini keyboard kami tidak terlalu berguna. Alangkah baiknya jika kita benar-benar bisa mengetik di atasnya. Tetapi untuk itu kita membutuhkan tombol, dan tombol-tombol tersebut harus disusun menjadi matriks keyboard. Keyboard 104 tombol berukuran penuh dapat memiliki 18 baris dan 6 kolom, tetapi kami hanya akan memiliki matriks keyboard 2x2 sederhana untuk memulai. Ini skemanya:

Untuk menyesuaikan keyboard peretas, Anda harus mempertimbangkan matriks kunci dengan cermat.

Dan inilah tampilannya di papan tempat memotong roti:

Mengonfigurasi papan tempat memotong roti adalah langkah penting dalam membangun papan ketik untuk pengembang.

Dengan asumsi bahwa ROW1 terhubung ke PINA0 , ROW2 ke PINA1 , COL1 ke PORTB0 dan COL2 ke PORTB1 , seperti inilah tampilan kode pemindaian:

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

Kode memindai satu kolom pada satu waktu dan di dalam kolom itu membaca status masing-masing sakelar kunci. Status sakelar kunci kemudian disimpan ke dalam array. Dalam fungsi CALLBACK_HID_Device_CreateHIDReport() kami sebelumnya, kode pindaian yang relevan kemudian akan dikirim berdasarkan status larik tersebut.

Langkah Tiga: Keyboard dengan Dua Bagian

Sejauh ini, kami telah membuat awal dari keyboard normal. Namun dalam tutorial keyboard ini kami bertujuan untuk ergonomis tingkat lanjut, dan mengingat bahwa orang memiliki dua tangan, sebaiknya tambahkan separuh keyboard lain ke dalam campuran.

Setengah lainnya akan menampilkan matriks keyboard lain, bekerja dengan cara yang sama seperti yang sebelumnya. Hal baru yang menarik adalah komunikasi antara bagian keyboard. Tiga protokol paling populer untuk menghubungkan perangkat elektronik adalah SPI, I 2 C dan UART. Untuk tujuan praktis kami akan menggunakan UART dalam kasus ini.

Untuk menjadi keyboard pemrograman yang baik, harus ada komunikasi yang baik antara kedua bagian.

Komunikasi dua arah mengalir melalui RX ke kanan dan melalui TX ke kiri sesuai dengan diagram di atas. VCC dan GND diperlukan untuk mentransfer daya. UART membutuhkan peer untuk menggunakan baud rate, jumlah bit data, dan jumlah stop bit yang sama. Setelah transceiver UART dari kedua rekan diatur, komunikasi dapat mulai mengalir.

Untuk saat ini, separuh keyboard kiri mengirimkan pesan satu byte ke separuh keyboard kanan melalui UART, yang mewakili peristiwa penekanan tombol atau pelepasan tombol. Separuh keyboard kanan memproses pesan-pesan ini dan memanipulasi status array matriks keyboard lengkap di memori yang sesuai. Beginilah cara keyboard kiri setengah mengirim pesan:

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

Kode untuk separuh keyboard kanan untuk menerima pesan terlihat seperti ini:

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

Penangan interupsi KeyboardRxCallback() dipicu setiap kali byte diterima melalui UART. Mengingat bahwa penangan interupsi harus dieksekusi secepat mungkin, pesan yang diterima dimasukkan ke dalam buffer cincin untuk diproses nanti. Buffer cincin akhirnya diproses dari dalam loop utama dan matriks keyboard akan diperbarui berdasarkan pesan.

Di atas adalah cara paling sederhana untuk mewujudkannya, tetapi protokol terakhir akan sedikit lebih kompleks. Pesan multi-byte harus ditangani, dan pesan individual harus diperiksa integritasnya dengan menggunakan checksum CRC-CCITT.

Pada titik ini, prototipe papan tempat memotong roti kami terlihat cukup mengesankan:

Prototipe papan tempat memotong roti mulai mengambil bentuk keyboard khusus untuk pengembang.

Langkah Empat: Temui Tampilan LED

Salah satu tujuan kami dengan UHK adalah memungkinkan pengguna untuk menentukan beberapa peta keyboard khusus aplikasi untuk lebih meningkatkan produktivitas. Pengguna memerlukan beberapa cara untuk menyadari keymap yang sebenarnya sedang digunakan, sehingga tampilan LED terintegrasi dibangun ke dalam keyboard. Berikut adalah tampilan prototipe dengan semua LED menyala:

Tampilan LED sangat penting untuk membangun keyboard terbaik bagi pengembang dalam tutorial ini.

Tampilan LED diimplementasikan oleh matriks LED 8x6:

Keyboard peretas tidak akan lengkap tanpa matriks LED 8x6.

Setiap dua baris simbol LED berwarna merah mewakili segmen dari salah satu tampilan LED 14 segmen. Simbol LED putih mewakili tiga indikator status tambahan.

Untuk menggerakkan arus melalui LED dan menyalakannya, kolom yang sesuai diatur ke tegangan tinggi, dan baris yang sesuai ke tegangan rendah. Konsekuensi menarik dari sistem ini adalah, pada saat tertentu, hanya satu kolom yang dapat diaktifkan (semua LED pada kolom yang seharusnya menyala memiliki baris yang sesuai disetel ke tegangan rendah), sedangkan kolom lainnya dinonaktifkan. . Orang mungkin berpikir bahwa sistem ini tidak dapat bekerja untuk menggunakan set lengkap LED, tetapi pada kenyataannya kolom dan baris diperbarui begitu cepat sehingga tidak ada kedipan yang dapat dilihat oleh mata manusia.

Matriks LED digerakkan oleh dua sirkuit terpadu (IC), satu menggerakkan barisnya dan yang lain menggerakkan kolomnya. IC sumber yang menggerakkan kolom adalah driver LED PCA9634 I2C:

Dua sirkuit terintegrasi menggerakkan matriks LED pada Ultimate Hacker Keyboard.

IC wastafel matriks LED yang menggerakkan baris adalah register geser daya TPIC6C595:

IC yang menggerakkan deretan LED terlihat seperti ini.

Mari kita lihat kode yang relevan:

 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() dipanggil setiap milidetik, memperbarui baris matriks LED. Array LedStates menyimpan status masing-masing LED, diperbarui melalui UART berdasarkan pesan yang berasal dari separuh keyboard kanan, dengan cara yang hampir sama seperti dalam kasus acara penekanan tombol/pelepasan tombol.

Gambar besar

Sekarang kami telah secara bertahap membangun semua komponen yang diperlukan untuk keyboard peretas khusus kami, dan inilah saatnya untuk melihat gambaran besarnya. Bagian dalam keyboard seperti jaringan komputer mini: banyak node yang saling berhubungan. Perbedaannya adalah bahwa jarak antara node diukur bukan dalam meter atau kilometer, tetapi dalam sentimeter, dan node bukanlah komputer yang lengkap, tetapi sirkuit terpadu kecil.

Bagian dalam keyboard tutorial kami terdiri dari node yang saling berhubungan.

Banyak yang telah dikatakan sejauh ini tentang detail sisi perangkat dari keyboard pengembang, tetapi tidak begitu banyak tentang UHK Agent, perangkat lunak sisi host. Alasannya adalah, tidak seperti perangkat keras dan firmware, saat ini Agen masih sangat sederhana. Namun, arsitektur tingkat tinggi Agen diputuskan, yang ingin saya bagikan.

UHK Agent adalah aplikasi konfigurator yang dapat digunakan untuk menyesuaikan keyboard agar sesuai dengan kebutuhan pengguna. Meskipun menjadi klien kaya, Agen menggunakan teknologi web dan berjalan di atas platform node-webkit.

Agen berkomunikasi dengan keyboard menggunakan pustaka node-usb dengan mengirimkan permintaan kontrol USB khusus perangkat dan memproses hasilnya. Ia menggunakan Express.js untuk mengekspos REST API untuk dikonsumsi oleh aplikasi pihak ketiga. Itu juga menggunakan Angular.js untuk menyediakan antarmuka pengguna yang rapi.

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

Setiap perintah memiliki pengidentifikasi 8-bit dan satu set argumen khusus perintah. Saat ini, hanya perintah re-enumerate yang diterapkan. sendReenumerateCommand() membuat perangkat menghitung ulang sebagai bootloader kiri atau bootloader kanan, untuk memutakhirkan firmware, atau sebagai perangkat keyboard.

Seseorang mungkin tidak tahu tentang fitur-fitur canggih yang dapat dicapai oleh perangkat lunak ini, jadi saya akan menyebutkan beberapa: Agen akan dapat memvisualisasikan pemakaian masing-masing kunci dan memberi tahu pengguna tentang harapan hidup mereka, sehingga pengguna dapat beli beberapa sakelar kunci baru untuk perbaikan yang akan datang. Agen juga akan menyediakan antarmuka pengguna untuk mengonfigurasi berbagai peta tombol dan lapisan keyboard peretas. Kecepatan dan akselerasi penunjuk tetikus juga dapat diatur, bersama dengan banyak fitur uber lainnya. Langit adalah batasnya.

Membuat Prototipe

Banyak pekerjaan yang dilakukan untuk membuat prototipe keyboard yang disesuaikan. Pertama-tama, desain mekanis harus diselesaikan, yang cukup rumit dalam dirinya sendiri dan melibatkan bagian plastik yang dirancang khusus, pelat baja tahan karat yang dipotong laser, pemandu baja yang digiling dengan presisi, dan magnet neodymium yang menyatukan kedua bagian keyboard. Semuanya dirancang dalam CAD sebelum fabrikasi dimulai.

Gambar CAD membantu dalam membangun keyboard yang berfungsi dengan baik untuk pengembang.

Beginilah tampilan casing keyboard cetak 3D:

Kami mulai dengan mencetak 3D casing keyboard pemrograman.

Berdasarkan desain mekanik dan skema, papan sirkuit cetak harus dirancang. PCB sebelah kanan terlihat seperti ini di KiCad:

Pemrograman keyboard dimulai dengan merancang papan sirkuit tercetak.

Kemudian PCB dibuat dan komponen yang dipasang di permukaan harus disolder dengan tangan:

Menyolder komponen keyboard khusus memastikannya berfungsi dengan baik setelah dimasukkan ke dalam casing.

Akhirnya, setelah membuat semua bagian, termasuk pencetakan 3D, memoles dan mengecat bagian plastik dan merakit semuanya, kami berakhir dengan prototipe keyboard peretas yang berfungsi seperti ini:

Kesimpulan

Saya suka membandingkan keyboard pengembang dengan instrumen musisi. Keyboard adalah objek yang cukup intim jika Anda memikirkannya. Lagi pula, kami menggunakannya sepanjang hari untuk membuat perangkat lunak masa depan, karakter demi karakter.

Mungkin karena hal di atas, saya menganggap mengembangkan Ultimate Hacking Keyboard sebagai hak istimewa, dan terlepas dari semua kesulitannya, lebih sering daripada tidak itu merupakan perjalanan yang sangat mengasyikkan dan pengalaman belajar yang luar biasa intens.

Ini adalah topik yang luas, dan saya hanya bisa menggores permukaan di sini. Harapan saya adalah bahwa artikel ini sangat menyenangkan dan penuh dengan materi yang menarik. Jika Anda memiliki pertanyaan, beri tahu saya di komentar.

Terakhir, Anda dipersilakan untuk mengunjungi https://ultimatehackingkeyboard.com untuk info lebih lanjut, dan berlangganan di sana untuk mendapatkan pemberitahuan tentang peluncuran kampanye kami.