diff --git a/content-org/blog.org b/content-org/blog.org index 18f5304..4fead21 100644 --- a/content-org/blog.org +++ b/content-org/blog.org @@ -4782,6 +4782,350 @@ So I decided to make the whole API as accessible as possible from the command li All I got to say in conclusion is that it was a lot of fun working on [[https://gitea.project42.io/Elia/cmw][cmw]] and I learned a lot. I'm not going to publish the package on [[https://pypi.org/][PyPI]] because seriously, what's the point. But if you are interested in making changes to the repository, make an MR. +*** DONE QMK Firmware :qmk:firmware:mechanical_keyboard:qmk_firmware: +:PROPERTIES: +:EXPORT_HUGO_LASTMOD: 2021-09-23 +:EXPORT_DATE: 2021-09-23 +:EXPORT_FILE_NAME: qmk-firmware +:CUSTOM_ID: qmk-firmware +:END: + +Over the years, I have owned a few mechanical keyboards. I'm quite fond of them. +I've also built my own keyboard from scratch years ago. Hot-swappable back then +was still in its easy stages and the sockets weren't that good. Alas, we're in +2021 and I've recently purchased the *Keychron Q1* keyboard. + +I've chosen this keyboard for many reasons, but the one you most care about is +the topic that brought you here. It's a *QMK Firmware* compatible keyboards. Do +you know what that means ? + +That means that we're going to be digging into ~qmk_firmware~. Tag along ! + +#+hugo: more + +**** Quantum Mechanical Keyboard Firmware + +The [[https://github.com/qmk/qmk_firmware][*QMK Firmware*]] is + +#+begin_quote +a keyboard firmware based on the tmk_keyboard firmware with some useful features +for Atmel AVR and ARM controllers, and more specifically, the OLKB product line, +the ErgoDox EZ keyboard, and the Clueboard product line. +#+end_quote + +It goes beyond saying, the *QMK Firmware* is open sourced. So let's hack it. + +**** Building QMK Firmware + +The first step to flashing your keyboard starts here. We need to get the source +code of ~qmk_firmware~ from Github. + +#+begin_src shell +$ git clone https://github.com/qmk/qmk_firmware.git +# Wait a while... +# Yup, I know ! +# Okay finally... +Cloning into 'qmk_firmware'... +remote: Enumerating objects: 295442, done. +remote: Counting objects: 100% (34/34), done. +remote: Compressing objects: 100% (27/27), done. +remote: Total 295442 (delta 13), reused 17 (delta 5), pack-reused 295408 +Receiving objects: 100% (295442/295442), 178.92 MiB | 7.10 MiB/s, done. +Resolving deltas: 100% (178414/178414), done. +Updating files: 100% (27916/27916), done. + +$ cd qmk_firmware +#+end_src + +Once the repository is clone, we can start with installing the dependencies to +build ~qmk~. + +I'm not a big fan of auto-installers or installers scripts +(=util/install/arch.sh=), and here's why. + +#+begin_src bash +python3 -m pip install --user -r $QMK_FIRMWARE_DIR/requirements.txt +#+end_src + +This is how the installer of the ~qmk_firmware~ concludes the round. I would +hate to use pip to install willy nilly like that. + +Otherwise, I don't have objections to what it does on ~arch~ at least. + +It does the following, I see no reason not to follow it. + +#+begin_src shell +$ sudo pacman -S \ + base-devel clang diffutils gcc git unzip wget zip python-pip \ + avr-binutils arm-none-eabi-binutils arm-none-eabi-gcc \ + arm-none-eabi-newlib avrdude dfu-programmer dfu-util +$ sudo pacman -U https://archive.archlinux.org/packages/a/avr-gcc/avr-gcc-8.3.0-1-x86_64.pkg.tar.xz +$ sudo pacman -S avr-libc # Must be installed after the above, or it will bring in the latest avr-gcc instead +$ sudo pacman -S hidapi # This will fail if the community repo isn't enabled +#+end_src + +Now that all the dependencies required by the system are installed, let's +install the ~python~ dependencies. + +#+begin_src shell +$ git checkout 0.14.9 # Checkout the latest version +$ vf new qmk_firmware # Create a new python virtualenv and activate it +$ pip install -r requirements.txt # Install python requirements +$ pip install qmk +$ make git-submodule +#+end_src + +Finally, we can build our keyboard firmware. + +#+begin_src bash +$ qmk compile -kb keychron/q1/rev_0100 -km default +Ψ Compiling keymap with make --jobs=1 keychron/q1/rev_0100:default [31/494] + + +QMK Firmware 0.14.16 +Making keychron/q1/rev_0100 with keymap default + +avr-gcc (GCC) 11.2.0 +Copyright (C) 2021 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +Compiling: keyboards/keychron/q1/q1.c [OK] +Compiling: keyboards/keychron/q1/rev_0100/rev_0100.c [OK] +Compiling: keyboards/keychron/q1/rev_0100/keymaps/default/keymap.c [OK] +Compiling: quantum/quantum.c [OK] +Compiling: quantum/send_string.c [OK] +Compiling: quantum/bitwise.c [OK] +Compiling: quantum/led.c [OK] +Compiling: quantum/action.c [OK] +Compiling: quantum/action_layer.c [OK] +Compiling: quantum/action_macro.c [OK] +Compiling: quantum/action_tapping.c [OK] +Compiling: quantum/action_util.c [OK] +Compiling: quantum/eeconfig.c [OK] +Compiling: quantum/keyboard.c [OK] +Compiling: quantum/keymap_common.c [OK] +Compiling: quantum/keycode_config.c [OK] +Compiling: quantum/logging/debug.c [OK] +Compiling: quantum/logging/sendchar.c [OK] +Compiling: quantum/bootmagic/bootmagic_lite.c [OK] +Compiling: quantum/bootmagic/magic.c [OK] +Compiling: quantum/matrix_common.c [OK] +Compiling: quantum/matrix.c [OK] +Compiling: quantum/debounce/sym_defer_g.c [OK] +Compiling: quantum/main.c [OK] +Compiling: quantum/color.c [OK] +Compiling: quantum/rgb_matrix/rgb_matrix.c [OK] +Compiling: quantum/rgb_matrix/rgb_matrix_drivers.c [OK] +Compiling: lib/lib8tion/lib8tion.c [OK] +Compiling: drivers/led/issi/is31fl3733.c [OK] +Compiling: quantum/process_keycode/process_rgb.c [OK] +Compiling: quantum/led_tables.c [OK] +Compiling: quantum/dip_switch.c [OK] +Compiling: quantum/process_keycode/process_space_cadet.c [OK] +Compiling: quantum/process_keycode/process_magic.c [OK] +Compiling: quantum/process_keycode/process_grave_esc.c [OK] +Compiling: platforms/avr/drivers/i2c_master.c [OK] +Archiving: .build/obj_keychron_q1_rev_0100_default/i2c_master.o [OK] +Compiling: tmk_core/common/host.c [OK] +Compiling: tmk_core/common/report.c [OK] +Compiling: tmk_core/common/sync_timer.c [OK] +Compiling: tmk_core/common/usb_util.c [OK] +Compiling: tmk_core/common/avr/platform.c [OK] +Compiling: tmk_core/common/avr/suspend.c [OK] +Compiling: tmk_core/common/avr/timer.c [OK] +Compiling: tmk_core/common/avr/bootloader.c [OK] +Assembling: tmk_core/common/avr/xprintf.S [OK] +Compiling: tmk_core/common/avr/printf.c [OK] +Compiling: tmk_core/protocol/lufa/lufa.c [OK] +Compiling: tmk_core/protocol/usb_descriptor.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Device_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/EndpointStream_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Endpoint_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Host_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/PipeStream_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Pipe_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/USBController_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/USBInterrupt_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/ConfigDescriptors.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/DeviceStandardReq.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/Events.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/HostStandardReq.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/USBTask.c [OK] +Compiling: tmk_core/protocol/lufa/usb_util.c [OK] +Linking: .build/keychron_q1_rev_0100_default.elf [OK] +Creating load file for flashing: .build/keychron_q1_rev_0100_default.hex [OK] +Copying keychron_q1_rev_0100_default.hex to qmk_firmware folder [OK] +Checking file size of keychron_q1_rev_0100_default.hex [OK] + * The firmware size is fine - 23302/28672 (81%, 5370 bytes free) + +#+end_src + +Look at tha, easy as pie ! You got yourself a compiled firmware. + +Before we move on, let's look at the command again and figure out what the hell +I did, just in case you're running a different keyboard. + +If you look into the =keyboards/=, you'll be able to find a big list of +keyboards supported. The =keychron/q1/rev_0100= is simply a directory in there +that matches my keyboard. Inside that directory, we can find the =keymaps/= +directory. This is where all the keymaps live. We chose the ~default~ keymap +which is a directory in there as well. + +**** Remapping the keyboard + +At this stage, we were able to succesfully compile the keyboard firmware. But +the whole point of this is to modify the layout of the keyboard so let's go +right ahead. + +There are commands suggested on the ~QMK~ docs but I didn't go that far, I +simply copied the =default= directory and went down to business. For the sake of +this blog post, I'll assume I called the directory =functions=. + +The =keymap.c= file looks as follows. + +#+begin_src c +#include QMK_KEYBOARD_H + +enum layers{ + MAC_BASE, + MAC_FN, + WIN_BASE, + WIN_FN +}; + +#define KC_TASK LGUI(KC_TAB) +#define KC_FLXP LGUI(KC_E) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[MAC_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_BRID, KC_BRIU, KC_F3, KC_F4, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_INS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, KC_RGUI, MO(MAC_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[MAC_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), + +[WIN_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_INS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(WIN_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[WIN_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_BRID, KC_BRIU, KC_TASK, KC_FLXP, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS) + +}; +#+end_src + +If you read this you will understand that the keyboard originally comes with 4 +layers. Two for windows and two for Mac. The ~0~ and ~1~ layers are toggled +using a physical switch. The rest are toggled with the ~Fn~ key. + +Now let's change the Mac layout to have the ~Function~ keys to be on the main +layer while the media keys to be toggled with the ~Fn~ key. The final version +should look like the following. + +#+begin_src c +#include QMK_KEYBOARD_H + +enum layers{ + MAC_BASE, + MAC_FN, + WIN_BASE, + WIN_FN +}; + +#define KC_TASK LGUI(KC_TAB) +#define KC_FLXP LGUI(KC_E) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[MAC_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, KC_TRNS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, KC_RGUI, MO(MAC_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[MAC_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_BRID, KC_BRIU, KC_F3, KC_F4, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_INS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), + +[WIN_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_INS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(WIN_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[WIN_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_BRID, KC_BRIU, KC_TASK, KC_FLXP, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS) + +}; +#+end_src + +Now that that's done, we need to compile to check that we didn't forget +anything. + +#+begin_src shell +$ qmk compile -kb keychron/q1/rev_0100 -km functions +#+end_src + +We seem to have successfully compiled our now keyboard layout. + +**** Flashing your keyboard + +If you're reached this stage, you'll need to locate the ~reset~ button on your +keyboard. Once located, follow your keyboard's manual on how to *reset* the +board and getting ready it for flashing. + +Once the keyboard is ready to be flashed, you basically change one thing in your +previous command. + +#+begin_src shell +$ qmk flash -kb keychron/q1/rev_0100 -km functions +#+end_src + +If this step succeeds, your keyboard should be ready to use in the newly +configured layout. Check it out ! + +**** Conclusion + +It's pretty awesome to see keyboards like these hit the market. Whether you're +fan of the mechanical switches they come with or not, one thing is certain. You +cannot deny the fact that they are very customisable. If you don't like +something with your keyboard, simply change it. The beauty of it all is that the +firmware is open sourced. The community delivers, yet again ! + ** Monitoring :@monitoring: *** DONE Simple cron monitoring with HealthChecks :healthchecks:cron: :PROPERTIES: diff --git a/content/posts/qmk-firmware.md b/content/posts/qmk-firmware.md new file mode 100644 index 0000000..b37280c --- /dev/null +++ b/content/posts/qmk-firmware.md @@ -0,0 +1,347 @@ ++++ +title = "QMK Firmware" +author = ["Elia el Lazkani"] +date = 2021-09-23 +lastmod = 2021-09-23 +tags = ["qmk", "firmware", "mechanical-keyboard", "qmk-firmware"] +categories = ["misc"] +draft = false ++++ + +Over the years, I have owned a few mechanical keyboards. I'm quite fond of them. +I've also built my own keyboard from scratch years ago. Hot-swappable back then +was still in its easy stages and the sockets weren't that good. Alas, we're in +2021 and I've recently purchased the **Keychron Q1** keyboard. + +I've chosen this keyboard for many reasons, but the one you most care about is +the topic that brought you here. It's a **QMK Firmware** compatible keyboards. Do +you know what that means ? + +That means that we're going to be digging into `qmk_firmware`. Tag along ! + + + + +## Quantum Mechanical Keyboard Firmware {#quantum-mechanical-keyboard-firmware} + +The [**QMK Firmware**](https://github.com/qmk/qmk%5Ffirmware) is + +> a keyboard firmware based on the tmk\_keyboard firmware with some useful features +> for Atmel AVR and ARM controllers, and more specifically, the OLKB product line, +> the ErgoDox EZ keyboard, and the Clueboard product line. + +It goes beyond saying, the **QMK Firmware** is open sourced. So let's hack it. + + +## Building QMK Firmware {#building-qmk-firmware} + +The first step to flashing your keyboard starts here. We need to get the source +code of `qmk_firmware` from Github. + +```shell +$ git clone https://github.com/qmk/qmk_firmware.git +# Wait a while... +# Yup, I know ! +# Okay finally... +Cloning into 'qmk_firmware'... +remote: Enumerating objects: 295442, done. +remote: Counting objects: 100% (34/34), done. +remote: Compressing objects: 100% (27/27), done. +remote: Total 295442 (delta 13), reused 17 (delta 5), pack-reused 295408 +Receiving objects: 100% (295442/295442), 178.92 MiB | 7.10 MiB/s, done. +Resolving deltas: 100% (178414/178414), done. +Updating files: 100% (27916/27916), done. + +$ cd qmk_firmware +``` + +Once the repository is clone, we can start with installing the dependencies to +build `qmk`. + +I'm not a big fan of auto-installers or installers scripts +(`util/install/arch.sh`), and here's why. + +```bash +python3 -m pip install --user -r $QMK_FIRMWARE_DIR/requirements.txt +``` + +This is how the installer of the `qmk_firmware` concludes the round. I would +hate to use pip to install willy nilly like that. + +Otherwise, I don't have objections to what it does on `arch` at least. + +It does the following, I see no reason not to follow it. + +```shell +$ sudo pacman -S \ + base-devel clang diffutils gcc git unzip wget zip python-pip \ + avr-binutils arm-none-eabi-binutils arm-none-eabi-gcc \ + arm-none-eabi-newlib avrdude dfu-programmer dfu-util +$ sudo pacman -U https://archive.archlinux.org/packages/a/avr-gcc/avr-gcc-8.3.0-1-x86_64.pkg.tar.xz +$ sudo pacman -S avr-libc # Must be installed after the above, or it will bring in the latest avr-gcc instead +$ sudo pacman -S hidapi # This will fail if the community repo isn't enabled +``` + +Now that all the dependencies required by the system are installed, let's +install the `python` dependencies. + +```shell +$ git checkout 0.14.9 # Checkout the latest version +$ vf new qmk_firmware # Create a new python virtualenv and activate it +$ pip install -r requirements.txt # Install python requirements +$ pip install qmk +$ make git-submodule +``` + +Finally, we can build our keyboard firmware. + +```bash +$ qmk compile -kb keychron/q1/rev_0100 -km default +Ψ Compiling keymap with make --jobs=1 keychron/q1/rev_0100:default [31/494] + + +QMK Firmware 0.14.16 +Making keychron/q1/rev_0100 with keymap default + +avr-gcc (GCC) 11.2.0 +Copyright (C) 2021 Free Software Foundation, Inc. +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +Compiling: keyboards/keychron/q1/q1.c [OK] +Compiling: keyboards/keychron/q1/rev_0100/rev_0100.c [OK] +Compiling: keyboards/keychron/q1/rev_0100/keymaps/default/keymap.c [OK] +Compiling: quantum/quantum.c [OK] +Compiling: quantum/send_string.c [OK] +Compiling: quantum/bitwise.c [OK] +Compiling: quantum/led.c [OK] +Compiling: quantum/action.c [OK] +Compiling: quantum/action_layer.c [OK] +Compiling: quantum/action_macro.c [OK] +Compiling: quantum/action_tapping.c [OK] +Compiling: quantum/action_util.c [OK] +Compiling: quantum/eeconfig.c [OK] +Compiling: quantum/keyboard.c [OK] +Compiling: quantum/keymap_common.c [OK] +Compiling: quantum/keycode_config.c [OK] +Compiling: quantum/logging/debug.c [OK] +Compiling: quantum/logging/sendchar.c [OK] +Compiling: quantum/bootmagic/bootmagic_lite.c [OK] +Compiling: quantum/bootmagic/magic.c [OK] +Compiling: quantum/matrix_common.c [OK] +Compiling: quantum/matrix.c [OK] +Compiling: quantum/debounce/sym_defer_g.c [OK] +Compiling: quantum/main.c [OK] +Compiling: quantum/color.c [OK] +Compiling: quantum/rgb_matrix/rgb_matrix.c [OK] +Compiling: quantum/rgb_matrix/rgb_matrix_drivers.c [OK] +Compiling: lib/lib8tion/lib8tion.c [OK] +Compiling: drivers/led/issi/is31fl3733.c [OK] +Compiling: quantum/process_keycode/process_rgb.c [OK] +Compiling: quantum/led_tables.c [OK] +Compiling: quantum/dip_switch.c [OK] +Compiling: quantum/process_keycode/process_space_cadet.c [OK] +Compiling: quantum/process_keycode/process_magic.c [OK] +Compiling: quantum/process_keycode/process_grave_esc.c [OK] +Compiling: platforms/avr/drivers/i2c_master.c [OK] +Archiving: .build/obj_keychron_q1_rev_0100_default/i2c_master.o [OK] +Compiling: tmk_core/common/host.c [OK] +Compiling: tmk_core/common/report.c [OK] +Compiling: tmk_core/common/sync_timer.c [OK] +Compiling: tmk_core/common/usb_util.c [OK] +Compiling: tmk_core/common/avr/platform.c [OK] +Compiling: tmk_core/common/avr/suspend.c [OK] +Compiling: tmk_core/common/avr/timer.c [OK] +Compiling: tmk_core/common/avr/bootloader.c [OK] +Assembling: tmk_core/common/avr/xprintf.S [OK] +Compiling: tmk_core/common/avr/printf.c [OK] +Compiling: tmk_core/protocol/lufa/lufa.c [OK] +Compiling: tmk_core/protocol/usb_descriptor.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Class/Common/HIDParser.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Device_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/EndpointStream_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Endpoint_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Host_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/PipeStream_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/Pipe_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/USBController_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/AVR8/USBInterrupt_AVR8.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/ConfigDescriptors.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/DeviceStandardReq.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/Events.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/HostStandardReq.c [OK] +Compiling: lib/lufa/LUFA/Drivers/USB/Core/USBTask.c [OK] +Compiling: tmk_core/protocol/lufa/usb_util.c [OK] +Linking: .build/keychron_q1_rev_0100_default.elf [OK] +Creating load file for flashing: .build/keychron_q1_rev_0100_default.hex [OK] +Copying keychron_q1_rev_0100_default.hex to qmk_firmware folder [OK] +Checking file size of keychron_q1_rev_0100_default.hex [OK] + * The firmware size is fine - 23302/28672 (81%, 5370 bytes free) +``` + +Look at tha, easy as pie ! You got yourself a compiled firmware. + +Before we move on, let's look at the command again and figure out what the hell +I did, just in case you're running a different keyboard. + +If you look into the `keyboards/`, you'll be able to find a big list of +keyboards supported. The `keychron/q1/rev_0100` is simply a directory in there +that matches my keyboard. Inside that directory, we can find the `keymaps/` +directory. This is where all the keymaps live. We chose the `default` keymap +which is a directory in there as well. + + +## Remapping the keyboard {#remapping-the-keyboard} + +At this stage, we were able to succesfully compile the keyboard firmware. But +the whole point of this is to modify the layout of the keyboard so let's go +right ahead. + +There are commands suggested on the `QMK` docs but I didn't go that far, I +simply copied the `default` directory and went down to business. For the sake of +this blog post, I'll assume I called the directory `functions`. + +The `keymap.c` file looks as follows. + +```c +#include QMK_KEYBOARD_H + +enum layers{ + MAC_BASE, + MAC_FN, + WIN_BASE, + WIN_FN +}; + +#define KC_TASK LGUI(KC_TAB) +#define KC_FLXP LGUI(KC_E) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[MAC_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_BRID, KC_BRIU, KC_F3, KC_F4, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_INS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, KC_RGUI, MO(MAC_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[MAC_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), + +[WIN_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_INS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(WIN_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[WIN_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_BRID, KC_BRIU, KC_TASK, KC_FLXP, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS) + +}; +``` + +If you read this you will understand that the keyboard originally comes with 4 +layers. Two for windows and two for Mac. The `0` and `1` layers are toggled +using a physical switch. The rest are toggled with the `Fn` key. + +Now let's change the Mac layout to have the `Function` keys to be on the main +layer while the media keys to be toggled with the `Fn` key. The final version +should look like the following. + +```c +#include QMK_KEYBOARD_H + +enum layers{ + MAC_BASE, + MAC_FN, + WIN_BASE, + WIN_FN +}; + +#define KC_TASK LGUI(KC_TAB) +#define KC_FLXP LGUI(KC_E) + +const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { + +[MAC_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS, KC_TRNS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LALT, KC_LGUI, KC_SPC, KC_RGUI, MO(MAC_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[MAC_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_BRID, KC_BRIU, KC_F3, KC_F4, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_DEL, KC_INS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), + +[WIN_BASE] = LAYOUT_ansi_82( + KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, KC_INS, + KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_PGUP, + KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGDN, + KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, + KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, + KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(WIN_FN),KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), + +[WIN_FN] = LAYOUT_ansi_82( + KC_TRNS, KC_BRID, KC_BRIU, KC_TASK, KC_FLXP, RGB_VAD, RGB_VAI, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + RGB_TOG, RGB_MOD, RGB_VAI, RGB_HUI, RGB_SAI, RGB_SPI, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, RGB_RMOD, RGB_VAD, RGB_HUD, RGB_SAD, RGB_SPD, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, + KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS) + +}; +``` + +Now that that's done, we need to compile to check that we didn't forget +anything. + +```shell +$ qmk compile -kb keychron/q1/rev_0100 -km functions +``` + +We seem to have successfully compiled our now keyboard layout. + + +## Flashing your keyboard {#flashing-your-keyboard} + +If you're reached this stage, you'll need to locate the `reset` button on your +keyboard. Once located, follow your keyboard's manual on how to **reset** the +board and getting ready it for flashing. + +Once the keyboard is ready to be flashed, you basically change one thing in your +previous command. + +```shell +$ qmk flash -kb keychron/q1/rev_0100 -km functions +``` + +If this step succeeds, your keyboard should be ready to use in the newly +configured layout. Check it out ! + + +## Conclusion {#conclusion} + +It's pretty awesome to see keyboards like these hit the market. Whether you're +fan of the mechanical switches they come with or not, one thing is certain. You +cannot deny the fact that they are very customisable. If you don't like +something with your keyboard, simply change it. The beauty of it all is that the +firmware is open sourced. The community delivers, yet again !