From c2d220fbdf2c9ae6957d080a47545aa28e3ec275 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Wed, 8 Nov 2023 22:05:53 +0000 Subject: [PATCH 01/13] refactor(hid): Use proper defines for HID values. * Add report ID defines and use them consistently. * Add defines for main item value flags to avoid magic constants. --- app/include/zmk/hid.h | 51 ++++++++++++++++++++++++++++++++----------- app/src/hid.c | 5 +++-- app/src/hog.c | 4 ++-- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index ab42adaa13e..da6bfa65a68 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -15,13 +15,43 @@ #define ZMK_HID_KEYBOARD_NKRO_MAX_USAGE HID_USAGE_KEY_KEYPAD_EQUAL -#define COLLECTION_REPORT 0x03 +// See https://www.usb.org/sites/default/files/hid1_11.pdf section 6.2.2.4 Main Items + +#define ZMK_HID_MAIN_VAL_DATA (0x00 << 0) +#define ZMK_HID_MAIN_VAL_CONST (0x01 << 0) + +#define ZMK_HID_MAIN_VAL_ARRAY (0x00 << 1) +#define ZMK_HID_MAIN_VAL_VAR (0x01 << 1) + +#define ZMK_HID_MAIN_VAL_ABS (0x00 << 2) +#define ZMK_HID_MAIN_VAL_REL (0x01 << 2) + +#define ZMK_HID_MAIN_VAL_NO_WRAP (0x00 << 3) +#define ZMK_HID_MAIN_VAL_WRAP (0x01 << 3) + +#define ZMK_HID_MAIN_VAL_LIN (0x00 << 4) +#define ZMK_HID_MAIN_VAL_NON_LIN (0x01 << 4) + +#define ZMK_HID_MAIN_VAL_PREFERRED (0x00 << 5) +#define ZMK_HID_MAIN_VAL_NO_PREFERRED (0x01 << 5) + +#define ZMK_HID_MAIN_VAL_NO_NULL (0x00 << 6) +#define ZMK_HID_MAIN_VAL_NULL (0x01 << 6) + +#define ZMK_HID_MAIN_VAL_NON_VOL (0x00 << 7) +#define ZMK_HID_MAIN_VAL_VOL (0x01 << 7) + +#define ZMK_HID_MAIN_VAL_BIT_FIELD (0x00 << 8) +#define ZMK_HID_MAIN_VAL_BUFFERED_BYTES (0x01 << 8) + +#define ZMK_HID_REPORT_ID_KEYBOARD 0x01 +#define ZMK_HID_REPORT_ID_CONSUMER 0x02 static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_GEN_DESKTOP), HID_USAGE(HID_USAGE_GD_KEYBOARD), HID_COLLECTION(HID_COLLECTION_APPLICATION), - HID_REPORT_ID(0x01), + HID_REPORT_ID(ZMK_HID_REPORT_ID_KEYBOARD), HID_USAGE_PAGE(HID_USAGE_KEY), HID_USAGE_MIN8(HID_USAGE_KEY_KEYBOARD_LEFTCONTROL), HID_USAGE_MAX8(HID_USAGE_KEY_KEYBOARD_RIGHT_GUI), @@ -30,14 +60,12 @@ static const uint8_t zmk_hid_report_desc[] = { HID_REPORT_SIZE(0x01), HID_REPORT_COUNT(0x08), - /* INPUT (Data,Var,Abs) */ - HID_INPUT(0x02), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), HID_USAGE_PAGE(HID_USAGE_KEY), HID_REPORT_SIZE(0x08), HID_REPORT_COUNT(0x01), - /* INPUT (Cnst,Var,Abs) */ - HID_INPUT(0x03), + HID_INPUT(ZMK_HID_MAIN_VAL_CONST | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), HID_USAGE_PAGE(HID_USAGE_KEY), @@ -48,8 +76,7 @@ static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_MAX8(ZMK_HID_KEYBOARD_NKRO_MAX_USAGE), HID_REPORT_SIZE(0x01), HID_REPORT_COUNT(ZMK_HID_KEYBOARD_NKRO_MAX_USAGE + 1), - /* INPUT (Data,Ary,Abs) */ - HID_INPUT(0x02), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_VAR | ZMK_HID_MAIN_VAL_ABS), #elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) HID_LOGICAL_MIN8(0x00), HID_LOGICAL_MAX16(0xFF, 0x00), @@ -57,8 +84,7 @@ static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_MAX8(0xFF), HID_REPORT_SIZE(0x08), HID_REPORT_COUNT(CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE), - /* INPUT (Data,Ary,Abs) */ - HID_INPUT(0x00), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS), #else #error "A proper HID report type must be selected" #endif @@ -67,7 +93,7 @@ static const uint8_t zmk_hid_report_desc[] = { HID_USAGE_PAGE(HID_USAGE_CONSUMER), HID_USAGE(HID_USAGE_CONSUMER_CONSUMER_CONTROL), HID_COLLECTION(HID_COLLECTION_APPLICATION), - HID_REPORT_ID(0x02), + HID_REPORT_ID(ZMK_HID_REPORT_ID_CONSUMER), HID_USAGE_PAGE(HID_USAGE_CONSUMER), #if IS_ENABLED(CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC) @@ -86,8 +112,7 @@ static const uint8_t zmk_hid_report_desc[] = { #error "A proper consumer HID report usage range must be selected" #endif HID_REPORT_COUNT(CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE), - /* INPUT (Data,Ary,Abs) */ - HID_INPUT(0x00), + HID_INPUT(ZMK_HID_MAIN_VAL_DATA | ZMK_HID_MAIN_VAL_ARRAY | ZMK_HID_MAIN_VAL_ABS), HID_END_COLLECTION, }; diff --git a/app/src/hid.c b/app/src/hid.c index 2a6b5d39da2..58e5824d2e4 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -12,9 +12,10 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include static struct zmk_hid_keyboard_report keyboard_report = { - .report_id = 1, .body = {.modifiers = 0, ._reserved = 0, .keys = {0}}}; + .report_id = ZMK_HID_REPORT_ID_KEYBOARD, .body = {.modifiers = 0, ._reserved = 0, .keys = {0}}}; -static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, .body = {.keys = {0}}}; +static struct zmk_hid_consumer_report consumer_report = {.report_id = ZMK_HID_REPORT_ID_CONSUMER, + .body = {.keys = {0}}}; // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. diff --git a/app/src/hog.c b/app/src/hog.c index 930714b092a..9ccfd9d2c0e 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -47,12 +47,12 @@ enum { }; static struct hids_report input = { - .id = 0x01, + .id = ZMK_HID_REPORT_ID_KEYBOARD, .type = HIDS_INPUT, }; static struct hids_report consumer_input = { - .id = 0x02, + .id = ZMK_HID_REPORT_ID_CONSUMER, .type = HIDS_INPUT, }; From 5b49bc10cd7251bb9a90c018410abfc557fa0e9c Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 3 Nov 2023 23:20:42 -0700 Subject: [PATCH 02/13] feat(blog): Show all posts on sidebar --- docs/docusaurus.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 701b5b997bb..20e6a75c90f 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -146,6 +146,7 @@ module.exports = { showReadingTime: true, // Please change this to your repo. editUrl: "https://github.com/zmkfirmware/zmk/edit/main/docs/", + blogSidebarCount: "ALL", }, theme: { customCss: [ From b80c0be0cedf42b58be2fc431b2a673ab9760c64 Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 3 Nov 2023 23:20:23 -0700 Subject: [PATCH 03/13] feat(blog): Add keymap editor post for spotlight series Co-authored-by: Nick Coutsos --- docs/blog/2023-11-09-keymap-editor.md | 109 ++++++++++++++++++ .../editor-screenshot-dark.png | Bin 0 -> 74997 bytes .../editor-screenshot-light.png | Bin 0 -> 75097 bytes 3 files changed, 109 insertions(+) create mode 100644 docs/blog/2023-11-09-keymap-editor.md create mode 100644 docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-dark.png create mode 100644 docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-light.png diff --git a/docs/blog/2023-11-09-keymap-editor.md b/docs/blog/2023-11-09-keymap-editor.md new file mode 100644 index 00000000000..1fe3b86772d --- /dev/null +++ b/docs/blog/2023-11-09-keymap-editor.md @@ -0,0 +1,109 @@ +--- +title: "Community Spotlight Series #1: Keymap Editor" +author: Cem Aksoylar +author_title: Documentation maintainer +author_url: https://github.com/caksoylar +author_image_url: https://avatars.githubusercontent.com/u/7876996 +tags: [keyboards, firmware, community] +--- + +import ThemedImage from '@theme/ThemedImage'; + + + +This blog post is the first in a series of posts where we highlight projects within the ZMK ecosystem that we think are cool and that the users might benefit from knowing about them. We are starting the series with a big one, [Keymap Editor] by [Nick Coutsos](https://github.com/nickcoutsos)! + +In the rest of the post we leave it to Nick himself to introduce the project, detail his goals and motivation in developing such a tool, and talk about the future of the project. Stay tuned for future installments in the series! + +## What is Keymap Editor? + +_[Keymap Editor]_ is a web based graphical editor for ZMK keymaps. It provides a visual way to manage the contents of your keymap and if nothing else offers two critical features: + +1. Automatic formatting of the keymap file, so that bindings arrays remain readable +2. Searchable behaviors, keycodes, commands, etc, so you won't have to remember if it's `LCTL` or `LCTRL` (I just had to double check myself and I guessed wrong, apparently) + +## What can Keymap Editor do? + +- Render [devicetree keymaps](/docs/features/keymaps) using pre-defined, auto-generated, or side-loadable keyboard layouts +- Integrate with a GitHub repo to streamline firmware builds, or FileSystem/Clipboard if you'd still rather build locally +- Edit [combos](/docs/features/combos), [behaviors](/docs/behaviors/key-press), [macros](/docs/behaviors/macros), [conditional layers](/docs/features/conditional-layers) and [rotary encoder bindings](/docs/behaviors/sensor-rotate) +- Manage references: moving a layer or renaming a behavior will look for references throughout your keymap and update them. + +But check back regularly, because I update pretty often. A recent significant achievement was enabling [parameterized macros](/docs/behaviors/macros#parameterized-macros) and tying it in with my existing parameter type resolution so, yeah, you can finally create that reusable macro combining bluetooth profile selection with RGB backlight colour. Or use it for an actual useful thing, even. _(See also: [Using Parameterized Macros in Keymap Editor](https://github.com/nickcoutsos/keymap-editor/wiki/Using-Parameterized-Macros-in-Keymap-Editor))_ + +My goals are, broadly: + +- **Treat code as a first-class entity:** as long as ZMK keymaps are described in devicetree code then an editor needs to produce readable devicetree code. +- **Flexibly support ZMK features:** use of any ZMK keymap feature should theoretically be achievable within the app. In some cases this can mean more initial setup _(See also: [my thoughts on implementing "autoshift"](https://github.com/nickcoutsos/keymap-editor/wiki/Autoshift-using-ZMK-behaviors))_ but having that foundation makes its easier to add shortcuts and niceties — something I do quite often now. +- **Don't get in the way of not-yet-supported features:** If a new ZMK feature is released and the app isn't able to add it natively, you can always edit your keymap file directly. While the app may not _recognize_ the new features, further changes through the app should not break your keymap. + +## History of Keymap Editor + +When I started writing Keymap Editor I had a handwired Dactyl variant running QMK. Manually editing keymap code was fine, but keeping things readable was important to me, and automating that was the best way to ensure consistency. Programmatically modifying source code was beyond me at the time so the first version persisted keymap data in JSON and spat out formatted versions of both the JSON and C keymaps. + +After switching to ZMK I added a few more features, I guess as a pandemic project, and then gradually migrated from generating a templated keymap file to manipulating devicetree syntax directly, and that has made a big difference in adding new ZMK features. + +## Why am I doing this? + +It started out as a useful tool for me. I shared it with the ZMK community and gained a little traction, and then apparently quite a bit of traction — turns out it's useful for a lot of people. + +I'm a software developer because I enjoy building things. Much of my day-to-day work isn't user facing, so seeing how helpful the keymap editor has been for people in the ZMK community is a big motivator to keep improving it. + +## Future plans + +### Runtime updates + +Streamlining the keymap update process is probably top of mind for most users, but that involves a really big _firmware_ feature, and I'm the wrong person to tackle it. + +That said, once there's a protocol I would _absolutely_ be down to integrate it as an additional keymap source. Being able to pull data directly from the keyboard should unlock a lot of possibilities and ease some of the constraints imposed by using devicetree code as a medium. + +### Simplifying behavior use + +I think a lot of people would like to see the concept of behaviors abstracted away for new users and to prompt them with + +- _"When the key is tapped..."_, +- _"When the key is held..."_, +- _"When the key is double-tapped..."_ and so on. + +Users who are less familiar with ZMK's behaviors and how they are composed may find these prompts to be more intuitive, and their answers could be mapped to an appropriate combination of behaviors managed internally by an editor. + +### Uh, what else? + +This has been long enough already, if you're looking for a feature I haven't mentioned don't assume I won't add it. Feel free to make feature requests on the GitHub repo, and I'd be happy to discuss it! + +## About Me And My Keebs + +I like computers and write software. Many in this field enjoy using mechanical +keyboards for their feel or aesthetics, but what piqued my interest was the +Dactyl keyboard. I think, ergonomics aside, I'm more interested in the DIY/maker +aspect than the collecting of keyboards and switches. + +So [I made a Dactyl](https://github.com/nickcoutsos/dactyl-flatpacked/), and +then [I made another Dactyl](https://github.com/nickcoutsos/dactyl-deskmount/) +and I made a third Dactyl that isn't interesting enough to photograph, but now +I'm using ZMK so I left room for 18650 cells. + +That last Dactyl (with MX browns and a cheap blank XDA keycap set) serves me +well the eight or so hours a day I'll spend at my desk, but I also spend a good +deal of time computing on my couch where I'll use... my Macbook's built-in +keyboard. + +In case that's not surprising enough I'll leave you with this: despite all of +the work and testing I've put into the keymap editor project, I've only updated +an actual keymap once in the last year. + +Thank you and good night. + +## More information + +- [Keymap Editor Wiki](https://github.com/nickcoutsos/keymap-editor/wiki) +- [Keymap Editor Discussions](https://github.com/nickcoutsos/keymap-editor/discussions) +- (YouTube video) [Ben Frain's overview of the Keymap Editor](https://www.youtube.com/watch?v=Vy7IoQAe3oU) + +[Keymap Editor]: http://nickcoutsos.github.io/keymap-editor diff --git a/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-dark.png b/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..166edf8ae806520abd95ab0eb7889e3b64fcc1c1 GIT binary patch literal 74997 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
~y{` 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

n{U;|*<63&-Enc$9Bc{ia~fEJN>9 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 literal 0 HcmV?d00001 diff --git a/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-light.png b/docs/blog/assets/2023-11-09-keymap-editor/editor-screenshot-light.png new file mode 100644 index 0000000000000000000000000000000000000000..cdaae5c799da8f63a5a4d1af865e63441c949049 GIT binary patch literal 75097 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 +knUbIx+ui8%&y{z+C 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 I^qph>14ln7O8@`> literal 0 HcmV?d00001 From 91aa3378f32f5688329a663fdaba4772e069d548 Mon Sep 17 00:00:00 2001 From: Chris Andreae Date: Tue, 14 Nov 2023 03:04:04 +0900 Subject: [PATCH 04/13] feat(usb): Add boot protocol support * USB boot protocol support * Use a single definition of a boot report, used for regular reports in non-6KRO, and for rollover in all branches. * Handle gaps in the zmk report when producing a boot report in HKRO mode. For .example, if it was 8KRO, it would be possible to have the state 0 0 0 0 0 0 0 17 (by pressing 8 keys, and letting go of the first 7). Copying the first 6 bytes would not show up the single pressed key. * Disable usb status change and callback on SOF events: SOF events were introduced by the boot protocol changes, and required internally by Zephyr's idle support, but are unused within ZMK itself. Ignore them in the usb status callback. --------- Co-authored-by: Andrew Childs --- app/Kconfig | 6 ++- app/include/zmk/hid.h | 28 +++++++++--- app/include/zmk/usb_hid.h | 6 ++- app/src/endpoints.c | 10 ++--- app/src/hid.c | 92 +++++++++++++++++++++++++++++++++++++++ app/src/usb.c | 14 ++++++ app/src/usb_hid.c | 88 ++++++++++++++++++++++++++++++++++++- 7 files changed, 229 insertions(+), 15 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index 0dd9316a2a7..798cb7855d5 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -103,6 +103,11 @@ config USB_NUMOF_EP_WRITE_RETRIES config USB_HID_POLL_INTERVAL_MS default 1 +config ZMK_USB_BOOT + bool "USB Boot Protocol Support" + default y + select USB_HID_BOOT_PROTOCOL + select USB_DEVICE_SOF #ZMK_USB endif @@ -575,4 +580,3 @@ osource "$(ZMK_CONFIG)/boards/shields/*/Kconfig.shield" source "Kconfig.zephyr" - diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index da6bfa65a68..afe9210199f 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -116,12 +116,24 @@ static const uint8_t zmk_hid_report_desc[] = { HID_END_COLLECTION, }; -// struct zmk_hid_boot_report -// { -// uint8_t modifiers; -// uint8_t _unused; -// uint8_t keys[6]; -// } __packed; +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + +#define HID_ERROR_ROLLOVER 0x1 +#define HID_BOOT_KEY_LEN 6 + +#if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO) && \ + CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE == HID_BOOT_KEY_LEN +typedef struct zmk_hid_keyboard_report_body zmk_hid_boot_report_t; +#else +struct zmk_hid_boot_report { + zmk_mod_flags_t modifiers; + uint8_t _reserved; + uint8_t keys[HID_BOOT_KEY_LEN]; +} __packed; + +typedef struct zmk_hid_boot_report zmk_hid_boot_report_t; +#endif +#endif struct zmk_hid_keyboard_report_body { zmk_mod_flags_t modifiers; @@ -179,3 +191,7 @@ bool zmk_hid_is_pressed(uint32_t usage); struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report(); struct zmk_hid_consumer_report *zmk_hid_get_consumer_report(); + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +zmk_hid_boot_report_t *zmk_hid_get_boot_report(); +#endif diff --git a/app/include/zmk/usb_hid.h b/app/include/zmk/usb_hid.h index 1748835eef2..777f2b48a03 100644 --- a/app/include/zmk/usb_hid.h +++ b/app/include/zmk/usb_hid.h @@ -6,4 +6,8 @@ #pragma once -int zmk_usb_hid_send_report(const uint8_t *report, size_t len); \ No newline at end of file +#include + +int zmk_usb_hid_send_keyboard_report(); +int zmk_usb_hid_send_consumer_report(); +void zmk_usb_hid_set_protocol(uint8_t protocol); diff --git a/app/src/endpoints.c b/app/src/endpoints.c index 138e790fe72..10357d4e02d 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -121,12 +121,10 @@ struct zmk_endpoint_instance zmk_endpoints_selected(void) { } static int send_keyboard_report(void) { - struct zmk_hid_keyboard_report *keyboard_report = zmk_hid_get_keyboard_report(); - switch (current_instance.transport) { #if IS_ENABLED(CONFIG_ZMK_USB) case ZMK_TRANSPORT_USB: { - int err = zmk_usb_hid_send_report((uint8_t *)keyboard_report, sizeof(*keyboard_report)); + int err = zmk_usb_hid_send_keyboard_report(); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); } @@ -136,6 +134,7 @@ static int send_keyboard_report(void) { #if IS_ENABLED(CONFIG_ZMK_BLE) case ZMK_TRANSPORT_BLE: { + struct zmk_hid_keyboard_report *keyboard_report = zmk_hid_get_keyboard_report(); int err = zmk_hog_send_keyboard_report(&keyboard_report->body); if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); @@ -150,12 +149,10 @@ static int send_keyboard_report(void) { } static int send_consumer_report(void) { - struct zmk_hid_consumer_report *consumer_report = zmk_hid_get_consumer_report(); - switch (current_instance.transport) { #if IS_ENABLED(CONFIG_ZMK_USB) case ZMK_TRANSPORT_USB: { - int err = zmk_usb_hid_send_report((uint8_t *)consumer_report, sizeof(*consumer_report)); + int err = zmk_usb_hid_send_consumer_report(); if (err) { LOG_ERR("FAILED TO SEND OVER USB: %d", err); } @@ -165,6 +162,7 @@ static int send_consumer_report(void) { #if IS_ENABLED(CONFIG_ZMK_BLE) case ZMK_TRANSPORT_BLE: { + struct zmk_hid_consumer_report *consumer_report = zmk_hid_get_consumer_report(); int err = zmk_hog_send_consumer_report(&consumer_report->body); if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); diff --git a/app/src/hid.c b/app/src/hid.c index 58e5824d2e4..689a2361e13 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -17,6 +17,13 @@ static struct zmk_hid_keyboard_report keyboard_report = { static struct zmk_hid_consumer_report consumer_report = {.report_id = ZMK_HID_REPORT_ID_CONSUMER, .body = {.keys = {0}}}; +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + +static zmk_hid_boot_report_t boot_report = {.modifiers = 0, ._reserved = 0, .keys = {0}}; +static uint8_t keys_held = 0; + +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + // Keep track of how often a modifier was pressed. // Only release the modifier if the count is 0. static int explicit_modifier_counts[8] = {0, 0, 0, 0, 0, 0, 0, 0}; @@ -85,15 +92,58 @@ int zmk_hid_unregister_mods(zmk_mod_flags_t modifiers) { return ret; } +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + +static zmk_hid_boot_report_t *boot_report_rollover(uint8_t modifiers) { + boot_report.modifiers = modifiers; + for (int i = 0; i < HID_BOOT_KEY_LEN; i++) { + boot_report.keys[i] = HID_ERROR_ROLLOVER; + } + return &boot_report; +} + +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + #if IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_NKRO) #define TOGGLE_KEYBOARD(code, val) WRITE_BIT(keyboard_report.body.keys[code / 8], code % 8, val) +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +zmk_hid_boot_report_t *zmk_hid_get_boot_report() { + if (keys_held > HID_BOOT_KEY_LEN) { + return boot_report_rollover(keyboard_report.body.modifiers); + } + + boot_report.modifiers = keyboard_report.body.modifiers; + memset(&boot_report.keys, 0, HID_BOOT_KEY_LEN); + int ix = 0; + uint8_t base_code = 0; + for (int i = 0; i < (ZMK_HID_KEYBOARD_NKRO_MAX_USAGE + 1) / 8; ++i) { + if (ix == keys_held) { + break; + } + if (!keyboard_report.body.keys[i]) { + continue; + } + base_code = i * 8; + for (int j = 0; j < 8; ++j) { + if (keyboard_report.body.keys[i] & BIT(j)) { + boot_report.keys[ix++] = base_code + j; + } + } + } + return &boot_report; +} +#endif + static inline int select_keyboard_usage(zmk_key_t usage) { if (usage > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE) { return -EINVAL; } TOGGLE_KEYBOARD(usage, 1); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + ++keys_held; +#endif return 0; } @@ -102,6 +152,9 @@ static inline int deselect_keyboard_usage(zmk_key_t usage) { return -EINVAL; } TOGGLE_KEYBOARD(usage, 0); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + --keys_held; +#endif return 0; } @@ -125,13 +178,52 @@ static inline bool check_keyboard_usage(zmk_key_t usage) { } \ } +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +zmk_hid_boot_report_t *zmk_hid_get_boot_report() { + if (keys_held > HID_BOOT_KEY_LEN) { + return boot_report_rollover(keyboard_report.body.modifiers); + } + +#if CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE != HID_BOOT_KEY_LEN + // Form a boot report from a report of different size. + + boot_report.modifiers = keyboard_report.body.modifiers; + + int out = 0; + for (int i = 0; i < CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE; i++) { + uint8_t key = keyboard_report.body.keys[i]; + if (key) { + boot_report.keys[out++] = key; + if (out == keys_held) { + break; + } + } + } + + while (out < HID_BOOT_KEY_LEN) { + boot_report.keys[out++] = 0; + } + + return &boot_report; +#else + return &keyboard_report.body; +#endif /* CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE != HID_BOOT_KEY_LEN */ +} +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + static inline int select_keyboard_usage(zmk_key_t usage) { TOGGLE_KEYBOARD(0U, usage); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + ++keys_held; +#endif return 0; } static inline int deselect_keyboard_usage(zmk_key_t usage) { TOGGLE_KEYBOARD(usage, 0U); +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + --keys_held; +#endif return 0; } diff --git a/app/src/usb.c b/app/src/usb.c index cf04ef46c8f..9d27900c3c6 100644 --- a/app/src/usb.c +++ b/app/src/usb.c @@ -15,6 +15,8 @@ #include #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static enum usb_dc_status_code usb_status = USB_DC_UNKNOWN; @@ -35,6 +37,7 @@ enum zmk_usb_conn_state zmk_usb_get_conn_state() { case USB_DC_CONFIGURED: case USB_DC_RESUME: case USB_DC_CLEAR_HALT: + case USB_DC_SOF: return ZMK_USB_CONN_HID; case USB_DC_DISCONNECTED: @@ -47,6 +50,17 @@ enum zmk_usb_conn_state zmk_usb_get_conn_state() { } void usb_status_cb(enum usb_dc_status_code status, const uint8_t *params) { + // Start-of-frame events are too frequent and noisy to notify, and they're + // not used within ZMK + if (status == USB_DC_SOF) { + return; + } + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + if (status == USB_DC_RESET) { + zmk_usb_hid_set_protocol(HID_PROTOCOL_REPORT); + } +#endif usb_status = status; k_work_submit(&usb_status_notifier_work); }; diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c index f46c70a0a92..c72bb36c9ef 100644 --- a/app/src/usb_hid.c +++ b/app/src/usb_hid.c @@ -23,11 +23,75 @@ static K_SEM_DEFINE(hid_sem, 1, 1); static void in_ready_cb(const struct device *dev) { k_sem_give(&hid_sem); } +#define HID_GET_REPORT_TYPE_MASK 0xff00 +#define HID_GET_REPORT_ID_MASK 0x00ff + +#define HID_REPORT_TYPE_INPUT 0x100 +#define HID_REPORT_TYPE_OUTPUT 0x200 +#define HID_REPORT_TYPE_FEATURE 0x300 + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) +static uint8_t hid_protocol = HID_PROTOCOL_REPORT; + +static void set_proto_cb(const struct device *dev, uint8_t protocol) { hid_protocol = protocol; } + +void zmk_usb_hid_set_protocol(uint8_t protocol) { hid_protocol = protocol; } +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + +static uint8_t *get_keyboard_report(size_t *len) { + if (hid_protocol == HID_PROTOCOL_REPORT) { + struct zmk_hid_keyboard_report *report = zmk_hid_get_keyboard_report(); + *len = sizeof(*report); + return (uint8_t *)report; + } +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + zmk_hid_boot_report_t *boot_report = zmk_hid_get_boot_report(); + *len = sizeof(*boot_report); + return (uint8_t *)boot_report; +#endif +} + +static int get_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len, + uint8_t **data) { + + /* + * 7.2.1 of the HID v1.11 spec is unclear about handling requests for reports that do not exist + * For requested reports that aren't input reports, return -ENOTSUP like the Zephyr subsys does + */ + if ((setup->wValue & HID_GET_REPORT_TYPE_MASK) != HID_REPORT_TYPE_INPUT) { + LOG_ERR("Unsupported report type %d requested", (setup->wValue & HID_GET_REPORT_TYPE_MASK) + << 8); + return -ENOTSUP; + } + + switch (setup->wValue & HID_GET_REPORT_ID_MASK) { + case ZMK_HID_REPORT_ID_KEYBOARD: { + *data = get_keyboard_report(len); + break; + } + case ZMK_HID_REPORT_ID_CONSUMER: { + struct zmk_hid_consumer_report *report = zmk_hid_get_consumer_report(); + *data = (uint8_t *)report; + *len = sizeof(*report); + break; + } + default: + LOG_ERR("Invalid report ID %d requested", setup->wValue & HID_GET_REPORT_ID_MASK); + return -EINVAL; + } + + return 0; +} + static const struct hid_ops ops = { +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + .protocol_change = set_proto_cb, +#endif .int_in_ready = in_ready_cb, + .get_report = get_report_cb, }; -int zmk_usb_hid_send_report(const uint8_t *report, size_t len) { +static int zmk_usb_hid_send_report(const uint8_t *report, size_t len) { switch (zmk_usb_get_status()) { case USB_DC_SUSPEND: return usb_wakeup_request(); @@ -48,6 +112,23 @@ int zmk_usb_hid_send_report(const uint8_t *report, size_t len) { } } +int zmk_usb_hid_send_keyboard_report() { + size_t len; + uint8_t *report = get_keyboard_report(&len); + return zmk_usb_hid_send_report(report, len); +} + +int zmk_usb_hid_send_consumer_report() { +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + if (hid_protocol == HID_PROTOCOL_BOOT) { + return -ENOTSUP; + } +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + + struct zmk_hid_consumer_report *report = zmk_hid_get_consumer_report(); + return zmk_usb_hid_send_report((uint8_t *)report, sizeof(*report)); +} + static int zmk_usb_hid_init(const struct device *_arg) { hid_dev = device_get_binding("HID_0"); if (hid_dev == NULL) { @@ -56,6 +137,11 @@ static int zmk_usb_hid_init(const struct device *_arg) { } usb_hid_register_device(hid_dev, zmk_hid_report_desc, sizeof(zmk_hid_report_desc), &ops); + +#if IS_ENABLED(CONFIG_ZMK_USB_BOOT) + usb_hid_set_proto_code(hid_dev, HID_BOOT_IFACE_CODE_KEYBOARD); +#endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ + usb_hid_init(hid_dev); return 0; From c1bf35ce1de4b7d99c034300c9a813a0a3d11669 Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 10 Nov 2023 22:40:55 -0800 Subject: [PATCH 05/13] feat(build): Add support for artifact-name in build.yaml --- .github/workflows/build-user-config.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-user-config.yml b/.github/workflows/build-user-config.yml index c1a97b4d6e0..5aacadca90c 100644 --- a/.github/workflows/build-user-config.yml +++ b/.github/workflows/build-user-config.yml @@ -55,12 +55,14 @@ jobs: - name: Prepare variables shell: sh -x {0} env: + board: ${{ matrix.board }} shield: ${{ matrix.shield }} + artifact_name: ${{ matrix.artifact-name }} run: | echo "zephyr_version=${ZEPHYR_VERSION}" >> $GITHUB_ENV echo "extra_cmake_args=${shield:+-DSHIELD=\"$shield\"}" >> $GITHUB_ENV - echo "display_name=${shield:+$shield - }${{ matrix.board }}" >> $GITHUB_ENV - echo "artifact_name=${shield:+$shield-}${{ matrix.board }}-zmk" >> $GITHUB_ENV + echo "display_name=${shield:+$shield - }${board}" >> $GITHUB_ENV + echo "artifact_name=${artifact_name:-\"${shield:+$shield-}${board}-zmk\"}" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v3 From 2554b5c88f4d304f311d9f29017ac6fbe948ca7a Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 10 Nov 2023 22:08:37 -0800 Subject: [PATCH 06/13] fix(docs): Update boards in build examples to common+uf2 ones --- docs/docs/development/build-flash.md | 6 +++--- docs/docs/development/new-shield.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/development/build-flash.md b/docs/docs/development/build-flash.md index 94bbcdf93a8..0243983c9d8 100644 --- a/docs/docs/development/build-flash.md +++ b/docs/docs/development/build-flash.md @@ -65,7 +65,7 @@ west build -b planck_rev6 When building for a new board and/or shield after having built one previously, you may need to enable the pristine build option. This option removes all existing files in the build directory before regenerating them, and can be enabled by adding either --pristine or -p to the command: ```sh -west build -p -b proton_c -- -DSHIELD=kyria_left +west build -p -b nice_nano_v2 -- -DSHIELD=kyria_left ``` ### Building For Split Keyboards @@ -77,13 +77,13 @@ For split keyboards, you will have to build and flash each side separately the f By default, the `build` command outputs a single .uf2 file named `zmk.uf2` so building left and then right immediately after will overwrite your left firmware. In addition, you will need to pristine build each side to ensure the correct files are used. To avoid having to pristine build every time and separate the left and right build files, we recommend setting up separate build directories for each half. You can do this by using the `-d` parameter and first building left into `build/left`: ```sh -west build -d build/left -b nice_nano -- -DSHIELD=kyria_left +west build -d build/left -b nice_nano_v2 -- -DSHIELD=kyria_left ``` and then building right into `build/right`: ```sh -west build -d build/right -b nice_nano -- -DSHIELD=kyria_right +west build -d build/right -b nice_nano_v2 -- -DSHIELD=kyria_right ``` This produces `left` and `right` subfolders under the `build` directory and two separate .uf2 files. For future work on a specific half, use the `-d` parameter again to ensure you are building into the correct location. diff --git a/docs/docs/development/new-shield.md b/docs/docs/development/new-shield.md index 0771122985b..7f6a8644e11 100644 --- a/docs/docs/development/new-shield.md +++ b/docs/docs/development/new-shield.md @@ -493,7 +493,7 @@ Once you've fully created the new keyboard shield definition, you should be able to test with a build command like: ```sh -west build --pristine -b proton_c -- -DSHIELD=my_board +west build --pristine -b nice_nano_v2 -- -DSHIELD=my_board ``` The above build command generates `build/zephyr/zmk.uf2`. If your board From a5c3edd51b46f45a7fdf9ff157f69296d7a9fddb Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 10 Nov 2023 22:22:05 -0800 Subject: [PATCH 07/13] refactor(docs): Remove local build section in customization --- docs/docs/customization.md | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/docs/docs/customization.md b/docs/docs/customization.md index 4f75e743a66..a68e8595fa9 100644 --- a/docs/docs/customization.md +++ b/docs/docs/customization.md @@ -11,15 +11,15 @@ This makes flashing ZMK to your keyboard much easier, especially because you don By default, the `zmk-config` folder should contain two files: -- `.conf` -- `.keymap` +- `.conf` +- `.keymap` However, your config folder can also be modified to include a `boards/` directory for keymaps and configurations for multiple boards/shields outside of the default keyboard setting definitions. ## Configuration Changes -The setup script creates a `config/.conf` file that allows you to add additional configuration options to +The setup script creates a `config/.conf` file that allows you to add additional configuration options to control what features and options are built into your firmware. Opening that file with your text editor will allow you to see the various config settings that can be commented/uncommented to modify how your firmware is built. @@ -27,7 +27,7 @@ Refer to the [Configuration](/docs/config) documentation for more details on thi ## Keymap -Once you have the basic user config completed, you can find the keymap file in `config/.keymap` and customize from there. +Once you have the basic user config completed, you can find the keymap file in `config/.keymap` and customize from there. Refer to the [Keymap](features/keymaps.md) documentation to learn more. ## Publishing @@ -39,18 +39,11 @@ GitHub Actions job to build your firmware which you can download once it complet If you need to, a review of [Learn The Basics Of Git In Under 10 Minutes](https://www.freecodecamp.org/news/learn-the-basics-of-git-in-under-10-minutes-da548267cc91/) will help you get these steps right. ::: -## Building from a local `zmk` fork using `zmk-config` - -[As outlined here](development/build-flash.md), firmware comes in the form of .uf2 files, which can be built locally using the command `west build`. Normally, -`west build` will default to using the in-tree .keymap and .conf files found in your local copy of the `zmk` repository. However, you can append the command, `-DZMK_CONFIG="C:/the/absolute/path/config"` to `west build` in order to use the contents of your `zmk-config` folder instead of the -default keyboard settings. -**Notice that this path should point to the folder labelled `config` within your `zmk-config` folder.** - -For instance, building kyria firmware from a user `myUser`'s `zmk-config` folder on Windows 10 may look something like this: - -```bash -west build -b nice_nano -- -DSHIELD=kyria_left -DZMK_CONFIG="C:/Users/myUser/Documents/Github/zmk-config/config" -``` +:::note +It is also possible to build firmware locally on your computer by following the [toolchain setup](development/setup.md) and +[building instructions](development/build-flash.md), which includes pointers to +[building using your `zmk-config` folder](development/build-flash.md#building-from-zmk-config-folder). +::: ## Flashing Your Changes From 7b4b5d4ff20957c3cba0d3e3eb679dd45c3181f5 Mon Sep 17 00:00:00 2001 From: Cem Aksoylar Date: Fri, 10 Nov 2023 22:01:31 -0800 Subject: [PATCH 08/13] fix(docs): Fix debouncing driver support note --- docs/docs/features/debouncing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/features/debouncing.md b/docs/docs/features/debouncing.md index cbea7092884..38ded2d7952 100644 --- a/docs/docs/features/debouncing.md +++ b/docs/docs/features/debouncing.md @@ -20,7 +20,7 @@ socket or using some sharp tweezers to bend the contacts back together. ## Debounce Configuration :::note -Currently only the `zmk,kscan-gpio-matrix` driver supports these options. The other drivers have not yet been updated to use the new debouncing code. +Currently the `zmk,kscan-gpio-matrix` and `zmk,kscan-gpio-direct` [drivers](../config/kscan.md) supports these options, while `zmk,kscan-gpio-demux` driver does not. ::: ### Global Options From 964c54139dcc5fca466eb2a6dc72b4092c7152a0 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Mon, 13 Nov 2023 11:00:28 -0800 Subject: [PATCH 09/13] fix(usb): Tweak how ZMK_USB gets enabled. * Previous version of multiple overrides of the default value of ZMK_USB were problematic. Move to using board _defconfig files for the defaults for those, along with proper `depends on` for ZMK_USB that accounts for split and split roles. --- app/Kconfig | 13 ++++++++----- app/boards/arm/bdn9/Kconfig.defconfig | 3 --- app/boards/arm/bdn9/bdn9_rev2_defconfig | 1 + app/boards/arm/bluemicro840/Kconfig.defconfig | 6 ------ .../arm/bluemicro840/bluemicro840_v1_defconfig | 3 +++ app/boards/arm/bt60/Kconfig.defconfig | 6 ------ app/boards/arm/bt60/bt60_v1_defconfig | 3 +++ app/boards/arm/bt60/bt60_v1_hs_defconfig | 3 +++ app/boards/arm/ckp/Kconfig.defconfig | 6 ------ app/boards/arm/ckp/bt60_v2_defconfig | 3 +++ app/boards/arm/ckp/bt65_v1_defconfig | 3 +++ app/boards/arm/ckp/bt75_v1_defconfig | 3 +++ app/boards/arm/corneish_zen/Kconfig.defconfig | 6 ------ .../arm/corneish_zen/corneish_zen_v1_left_defconfig | 3 +++ .../corneish_zen/corneish_zen_v1_right_defconfig | 3 +++ .../arm/corneish_zen/corneish_zen_v2_left_defconfig | 3 +++ .../corneish_zen/corneish_zen_v2_right_defconfig | 3 +++ app/boards/arm/dz60rgb/Kconfig.defconfig | 3 --- app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig | 2 ++ app/boards/arm/ferris/Kconfig.defconfig | 3 --- app/boards/arm/kbdfans_tofu65/Kconfig.defconfig | 3 --- .../arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig | 2 ++ app/boards/arm/mikoto/Kconfig.defconfig | 6 ------ app/boards/arm/mikoto/mikoto_520_defconfig | 3 +++ app/boards/arm/nice60/Kconfig.defconfig | 6 ------ app/boards/arm/nice60/nice60_defconfig | 4 ++++ app/boards/arm/nice_nano/Kconfig.defconfig | 6 ------ app/boards/arm/nice_nano/nice_nano_defconfig | 3 +++ app/boards/arm/nice_nano/nice_nano_v2_defconfig | 3 +++ app/boards/arm/nrf52840_m2/Kconfig.defconfig | 6 ------ app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig | 3 +++ app/boards/arm/nrfmicro/Kconfig.defconfig | 6 ------ app/boards/arm/nrfmicro/nrfmicro_11_defconfig | 3 +++ .../arm/nrfmicro/nrfmicro_11_flipped_defconfig | 3 +++ app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig | 3 +++ app/boards/arm/nrfmicro/nrfmicro_13_defconfig | 3 +++ app/boards/arm/pillbug/Kconfig.defconfig | 6 ------ app/boards/arm/pillbug/pillbug_defconfig | 3 +++ app/boards/arm/planck/Kconfig.defconfig | 3 --- app/boards/arm/planck/planck_rev6_defconfig | 2 ++ app/boards/arm/preonic/Kconfig.defconfig | 3 --- app/boards/arm/preonic/preonic_rev3_defconfig | 2 ++ app/boards/arm/proton_c/Kconfig.defconfig | 3 --- app/boards/arm/proton_c/proton_c_defconfig | 1 + app/boards/arm/puchi_ble/Kconfig.defconfig | 6 ------ app/boards/arm/puchi_ble/puchi_ble_v1_defconfig | 3 +++ app/boards/arm/s40nc/Kconfig.defconfig | 6 ------ app/boards/arm/s40nc/s40nc_defconfig | 3 +++ app/boards/shields/nibble/Kconfig.defconfig | 4 ---- app/src/split/bluetooth/Kconfig | 3 --- 50 files changed, 85 insertions(+), 105 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index 798cb7855d5..282339e3e40 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -91,10 +91,18 @@ menu "Output Types" config ZMK_USB bool "USB" + depends on (!ZMK_SPLIT || (ZMK_SPLIT && ZMK_SPLIT_ROLE_CENTRAL)) select USB select USB_DEVICE_STACK select USB_DEVICE_HID +config ZMK_USB_BOOT + bool "USB Boot Protocol Support" + default y + depends on ZMK_USB + select USB_HID_BOOT_PROTOCOL + select USB_DEVICE_SOF + if ZMK_USB config USB_NUMOF_EP_WRITE_RETRIES @@ -103,11 +111,6 @@ config USB_NUMOF_EP_WRITE_RETRIES config USB_HID_POLL_INTERVAL_MS default 1 -config ZMK_USB_BOOT - bool "USB Boot Protocol Support" - default y - select USB_HID_BOOT_PROTOCOL - select USB_DEVICE_SOF #ZMK_USB endif diff --git a/app/boards/arm/bdn9/Kconfig.defconfig b/app/boards/arm/bdn9/Kconfig.defconfig index d1c82811d28..96b7fe55329 100644 --- a/app/boards/arm/bdn9/Kconfig.defconfig +++ b/app/boards/arm/bdn9/Kconfig.defconfig @@ -11,9 +11,6 @@ config BOARD config ZMK_KEYBOARD_NAME default "BDN9 Rev2" -config ZMK_USB - default y - config ZMK_RGB_UNDERGLOW select SPI select WS2812_STRIP diff --git a/app/boards/arm/bdn9/bdn9_rev2_defconfig b/app/boards/arm/bdn9/bdn9_rev2_defconfig index 24dddb932d5..05087eeb4c6 100644 --- a/app/boards/arm/bdn9/bdn9_rev2_defconfig +++ b/app/boards/arm/bdn9/bdn9_rev2_defconfig @@ -23,3 +23,4 @@ CONFIG_HEAP_MEM_POOL_SIZE=1024 # clock configuration CONFIG_CLOCK_CONTROL=y +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/bluemicro840/Kconfig.defconfig b/app/boards/arm/bluemicro840/Kconfig.defconfig index 732805ae199..ff61ec92f81 100644 --- a/app/boards/arm/bluemicro840/Kconfig.defconfig +++ b/app/boards/arm/bluemicro840/Kconfig.defconfig @@ -18,10 +18,4 @@ endif # USB_DEVICE_STACK config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - endif # BOARD_BLUEMICRO840_V1 diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1_defconfig b/app/boards/arm/bluemicro840/bluemicro840_v1_defconfig index 99d51a94334..3e13e77d0b5 100644 --- a/app/boards/arm/bluemicro840/bluemicro840_v1_defconfig +++ b/app/boards/arm/bluemicro840/bluemicro840_v1_defconfig @@ -21,3 +21,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y diff --git a/app/boards/arm/bt60/Kconfig.defconfig b/app/boards/arm/bt60/Kconfig.defconfig index e7cf1a48cff..c44901bd8d4 100644 --- a/app/boards/arm/bt60/Kconfig.defconfig +++ b/app/boards/arm/bt60/Kconfig.defconfig @@ -19,12 +19,6 @@ endif # USB config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - config ZMK_KEYBOARD_NAME default "BT60" diff --git a/app/boards/arm/bt60/bt60_v1_defconfig b/app/boards/arm/bt60/bt60_v1_defconfig index 813dcecea5a..04adb8a3cd8 100644 --- a/app/boards/arm/bt60/bt60_v1_defconfig +++ b/app/boards/arm/bt60/bt60_v1_defconfig @@ -23,3 +23,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/bt60/bt60_v1_hs_defconfig b/app/boards/arm/bt60/bt60_v1_hs_defconfig index f2327fd3f42..f16d82ac41d 100644 --- a/app/boards/arm/bt60/bt60_v1_hs_defconfig +++ b/app/boards/arm/bt60/bt60_v1_hs_defconfig @@ -23,3 +23,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/ckp/Kconfig.defconfig b/app/boards/arm/ckp/Kconfig.defconfig index d5bf4ded1eb..376d4619fde 100644 --- a/app/boards/arm/ckp/Kconfig.defconfig +++ b/app/boards/arm/ckp/Kconfig.defconfig @@ -25,10 +25,4 @@ endif # USB config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - endif # BOARD_BT60_V2 || BOARD_BT65_V1 || BOARD_BT75_V1 diff --git a/app/boards/arm/ckp/bt60_v2_defconfig b/app/boards/arm/ckp/bt60_v2_defconfig index f6dc7e09a68..fd1ae985995 100644 --- a/app/boards/arm/ckp/bt60_v2_defconfig +++ b/app/boards/arm/ckp/bt60_v2_defconfig @@ -36,3 +36,6 @@ CONFIG_WS2812_STRIP=y CONFIG_SPI=y CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y diff --git a/app/boards/arm/ckp/bt65_v1_defconfig b/app/boards/arm/ckp/bt65_v1_defconfig index e40ae2dbb54..be5f17eb54f 100644 --- a/app/boards/arm/ckp/bt65_v1_defconfig +++ b/app/boards/arm/ckp/bt65_v1_defconfig @@ -36,3 +36,6 @@ CONFIG_WS2812_STRIP=y CONFIG_SPI=y CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/ckp/bt75_v1_defconfig b/app/boards/arm/ckp/bt75_v1_defconfig index 510d6994dc1..b4d85338aec 100644 --- a/app/boards/arm/ckp/bt75_v1_defconfig +++ b/app/boards/arm/ckp/bt75_v1_defconfig @@ -36,3 +36,6 @@ CONFIG_WS2812_STRIP=y CONFIG_SPI=y CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/corneish_zen/Kconfig.defconfig b/app/boards/arm/corneish_zen/Kconfig.defconfig index feab3eca773..f3cc959edd0 100644 --- a/app/boards/arm/corneish_zen/Kconfig.defconfig +++ b/app/boards/arm/corneish_zen/Kconfig.defconfig @@ -25,12 +25,6 @@ config ZMK_SPLIT config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - if USB config USB_NRFX diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_left_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v1_left_defconfig index a71ac680bb6..d738255601b 100644 --- a/app/boards/arm/corneish_zen/corneish_zen_v1_left_defconfig +++ b/app/boards/arm/corneish_zen/corneish_zen_v1_left_defconfig @@ -39,6 +39,9 @@ CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + # enable display drivers CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 diff --git a/app/boards/arm/corneish_zen/corneish_zen_v1_right_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v1_right_defconfig index f099392ff6a..5284159d83f 100644 --- a/app/boards/arm/corneish_zen/corneish_zen_v1_right_defconfig +++ b/app/boards/arm/corneish_zen/corneish_zen_v1_right_defconfig @@ -39,6 +39,9 @@ CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + # enable display drivers CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_left_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v2_left_defconfig index 3b7b4d9e276..29a5f878ac2 100644 --- a/app/boards/arm/corneish_zen/corneish_zen_v2_left_defconfig +++ b/app/boards/arm/corneish_zen/corneish_zen_v2_left_defconfig @@ -35,6 +35,9 @@ CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + # enable display drivers CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 diff --git a/app/boards/arm/corneish_zen/corneish_zen_v2_right_defconfig b/app/boards/arm/corneish_zen/corneish_zen_v2_right_defconfig index b361b08d9a0..506aa67e1b1 100644 --- a/app/boards/arm/corneish_zen/corneish_zen_v2_right_defconfig +++ b/app/boards/arm/corneish_zen/corneish_zen_v2_right_defconfig @@ -35,6 +35,9 @@ CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_30PPM=y +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + # enable display drivers CONFIG_ZMK_DISPLAY_WORK_QUEUE_DEDICATED=y CONFIG_ZMK_DISPLAY_DEDICATED_THREAD_STACK_SIZE=2048 diff --git a/app/boards/arm/dz60rgb/Kconfig.defconfig b/app/boards/arm/dz60rgb/Kconfig.defconfig index 2e30e3d048d..6e0592569de 100644 --- a/app/boards/arm/dz60rgb/Kconfig.defconfig +++ b/app/boards/arm/dz60rgb/Kconfig.defconfig @@ -8,7 +8,4 @@ if BOARD_DZ60RGB_REV1 config ZMK_KEYBOARD_NAME default "DZ60RGB Rev 1" -config ZMK_USB - default y - endif # BOARD_DZ60RGB_REV1 diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig index 33840f966ef..53bc0e11034 100644 --- a/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig @@ -25,3 +25,5 @@ CONFIG_CLOCK_STM32_PLL_MULTIPLIER=9 CONFIG_CLOCK_STM32_AHB_PRESCALER=1 CONFIG_CLOCK_STM32_APB1_PRESCALER=2 CONFIG_CLOCK_STM32_APB2_PRESCALER=1 + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/ferris/Kconfig.defconfig b/app/boards/arm/ferris/Kconfig.defconfig index 7cf43bcb9e6..420ea01fab9 100644 --- a/app/boards/arm/ferris/Kconfig.defconfig +++ b/app/boards/arm/ferris/Kconfig.defconfig @@ -11,9 +11,6 @@ config BOARD config ZMK_KEYBOARD_NAME default "Ferris rev 0.2" -config ZMK_USB - default y - config ZMK_KSCAN_MATRIX_POLLING default y diff --git a/app/boards/arm/kbdfans_tofu65/Kconfig.defconfig b/app/boards/arm/kbdfans_tofu65/Kconfig.defconfig index 993d51423b5..0444f510105 100644 --- a/app/boards/arm/kbdfans_tofu65/Kconfig.defconfig +++ b/app/boards/arm/kbdfans_tofu65/Kconfig.defconfig @@ -9,7 +9,4 @@ config ZMK_KEYBOARD_NAME config RP2_FLASH_W25Q080 default y -config ZMK_USB - default y - endif # BOARD_KBDFANS_TOFU65_V2 diff --git a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig index cf546683452..57014acf37a 100644 --- a/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig +++ b/app/boards/arm/kbdfans_tofu65/kbdfans_tofu65_v2_defconfig @@ -18,3 +18,5 @@ CONFIG_USE_DT_CODE_PARTITION=y # Output UF2 by default, native bootloader supports it. CONFIG_BUILD_OUTPUT_UF2=y + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/mikoto/Kconfig.defconfig b/app/boards/arm/mikoto/Kconfig.defconfig index 8c7746dbb8e..8117cc87329 100644 --- a/app/boards/arm/mikoto/Kconfig.defconfig +++ b/app/boards/arm/mikoto/Kconfig.defconfig @@ -21,12 +21,6 @@ endif # USB config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - config PINMUX default y diff --git a/app/boards/arm/mikoto/mikoto_520_defconfig b/app/boards/arm/mikoto/mikoto_520_defconfig index c755633e4cf..354fa56aa34 100644 --- a/app/boards/arm/mikoto/mikoto_520_defconfig +++ b/app/boards/arm/mikoto/mikoto_520_defconfig @@ -21,3 +21,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nice60/Kconfig.defconfig b/app/boards/arm/nice60/Kconfig.defconfig index f3347df9c6e..76818e87b0f 100644 --- a/app/boards/arm/nice60/Kconfig.defconfig +++ b/app/boards/arm/nice60/Kconfig.defconfig @@ -16,10 +16,4 @@ endif # USB_DEVICE_STACK config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - endif # BOARD_NICE60 diff --git a/app/boards/arm/nice60/nice60_defconfig b/app/boards/arm/nice60/nice60_defconfig index 48936a04704..fabcb7eddf4 100644 --- a/app/boards/arm/nice60/nice60_defconfig +++ b/app/boards/arm/nice60/nice60_defconfig @@ -28,3 +28,7 @@ CONFIG_WS2812_STRIP=y CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=160 CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3 + + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nice_nano/Kconfig.defconfig b/app/boards/arm/nice_nano/Kconfig.defconfig index ada59dd9f2e..63102a571f9 100644 --- a/app/boards/arm/nice_nano/Kconfig.defconfig +++ b/app/boards/arm/nice_nano/Kconfig.defconfig @@ -16,10 +16,4 @@ endif # USB_DEVICE_STACK config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - endif # BOARD_NICE_NANO || BOARD_NICE_NANO_V2 diff --git a/app/boards/arm/nice_nano/nice_nano_defconfig b/app/boards/arm/nice_nano/nice_nano_defconfig index a837b7d2875..6b7fcab252d 100644 --- a/app/boards/arm/nice_nano/nice_nano_defconfig +++ b/app/boards/arm/nice_nano/nice_nano_defconfig @@ -22,3 +22,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nice_nano/nice_nano_v2_defconfig b/app/boards/arm/nice_nano/nice_nano_v2_defconfig index 667cf71aca2..6b5044e5ef0 100644 --- a/app/boards/arm/nice_nano/nice_nano_v2_defconfig +++ b/app/boards/arm/nice_nano/nice_nano_v2_defconfig @@ -22,3 +22,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_BLE=y +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/nrf52840_m2/Kconfig.defconfig b/app/boards/arm/nrf52840_m2/Kconfig.defconfig index 50a049bb926..a5227fc0a10 100644 --- a/app/boards/arm/nrf52840_m2/Kconfig.defconfig +++ b/app/boards/arm/nrf52840_m2/Kconfig.defconfig @@ -16,10 +16,4 @@ endif # USB_DEVICE_STACK config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - endif # BOARD_NRF52840_M2 diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig b/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig index b7671ba9f12..93eef9e6ef8 100644 --- a/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig @@ -20,3 +20,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/Kconfig.defconfig b/app/boards/arm/nrfmicro/Kconfig.defconfig index 7d752ac6ee6..659e9c5c173 100644 --- a/app/boards/arm/nrfmicro/Kconfig.defconfig +++ b/app/boards/arm/nrfmicro/Kconfig.defconfig @@ -18,12 +18,6 @@ endif # USB_DEVICE_STACK config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - config PINMUX default y diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_defconfig b/app/boards/arm/nrfmicro/nrfmicro_11_defconfig index b51929b0c8f..5ba4d6e1478 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_11_defconfig +++ b/app/boards/arm/nrfmicro/nrfmicro_11_defconfig @@ -23,3 +23,6 @@ CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped_defconfig b/app/boards/arm/nrfmicro/nrfmicro_11_flipped_defconfig index 335a2d75b12..31cbfc9ae75 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_11_flipped_defconfig +++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped_defconfig @@ -23,3 +23,6 @@ CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig b/app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig index 4af1ff86a7c..f459f35636a 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig +++ b/app/boards/arm/nrfmicro/nrfmicro_13_52833_defconfig @@ -23,3 +23,6 @@ CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/nrfmicro_13_defconfig b/app/boards/arm/nrfmicro/nrfmicro_13_defconfig index 43ba40e2dc3..9ffb2766a66 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_13_defconfig +++ b/app/boards/arm/nrfmicro/nrfmicro_13_defconfig @@ -23,3 +23,6 @@ CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/pillbug/Kconfig.defconfig b/app/boards/arm/pillbug/Kconfig.defconfig index 8657f8aea30..48427ed3ec2 100644 --- a/app/boards/arm/pillbug/Kconfig.defconfig +++ b/app/boards/arm/pillbug/Kconfig.defconfig @@ -16,10 +16,4 @@ endif # USB_DEVICE_STACK config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - endif # BOARD_PILLBUG diff --git a/app/boards/arm/pillbug/pillbug_defconfig b/app/boards/arm/pillbug/pillbug_defconfig index 9781cf995cc..9ec72c417ef 100644 --- a/app/boards/arm/pillbug/pillbug_defconfig +++ b/app/boards/arm/pillbug/pillbug_defconfig @@ -23,3 +23,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/planck/Kconfig.defconfig b/app/boards/arm/planck/Kconfig.defconfig index d1304da0588..69dea84ce54 100644 --- a/app/boards/arm/planck/Kconfig.defconfig +++ b/app/boards/arm/planck/Kconfig.defconfig @@ -8,9 +8,6 @@ if BOARD_PLANCK_REV6 config ZMK_KEYBOARD_NAME default "Planck V6" -config ZMK_USB - default y - config ZMK_KSCAN_MATRIX_POLLING default y diff --git a/app/boards/arm/planck/planck_rev6_defconfig b/app/boards/arm/planck/planck_rev6_defconfig index a78ea45de88..74050f3d9c1 100644 --- a/app/boards/arm/planck/planck_rev6_defconfig +++ b/app/boards/arm/planck/planck_rev6_defconfig @@ -15,3 +15,5 @@ CONFIG_GPIO=y # clock configuration CONFIG_CLOCK_CONTROL=y + +CONFIG_ZMK_USB=y diff --git a/app/boards/arm/preonic/Kconfig.defconfig b/app/boards/arm/preonic/Kconfig.defconfig index 186c88bc5e3..86b2e3d0ef4 100644 --- a/app/boards/arm/preonic/Kconfig.defconfig +++ b/app/boards/arm/preonic/Kconfig.defconfig @@ -8,9 +8,6 @@ if BOARD_PREONIC_REV3 config ZMK_KEYBOARD_NAME default "Preonic V3" -config ZMK_USB - default y - config ZMK_KSCAN_MATRIX_POLLING default y diff --git a/app/boards/arm/preonic/preonic_rev3_defconfig b/app/boards/arm/preonic/preonic_rev3_defconfig index ab19d10f6f8..e063827a4e2 100644 --- a/app/boards/arm/preonic/preonic_rev3_defconfig +++ b/app/boards/arm/preonic/preonic_rev3_defconfig @@ -13,3 +13,5 @@ CONFIG_GPIO=y # clock configuration CONFIG_CLOCK_CONTROL=y + +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/proton_c/Kconfig.defconfig b/app/boards/arm/proton_c/Kconfig.defconfig index f5089119c13..eed4b830442 100644 --- a/app/boards/arm/proton_c/Kconfig.defconfig +++ b/app/boards/arm/proton_c/Kconfig.defconfig @@ -8,7 +8,4 @@ if BOARD_QMK_PROTON_C config BOARD default "proton_c" -config ZMK_USB - default y - endif # BOARD_QMK_PROTON_C diff --git a/app/boards/arm/proton_c/proton_c_defconfig b/app/boards/arm/proton_c/proton_c_defconfig index 32e1ade9604..c552bf15df9 100644 --- a/app/boards/arm/proton_c/proton_c_defconfig +++ b/app/boards/arm/proton_c/proton_c_defconfig @@ -17,3 +17,4 @@ CONFIG_GPIO=y # clock configuration CONFIG_CLOCK_CONTROL=y +CONFIG_ZMK_USB=y \ No newline at end of file diff --git a/app/boards/arm/puchi_ble/Kconfig.defconfig b/app/boards/arm/puchi_ble/Kconfig.defconfig index c4fca8e1f31..3533104b2a5 100644 --- a/app/boards/arm/puchi_ble/Kconfig.defconfig +++ b/app/boards/arm/puchi_ble/Kconfig.defconfig @@ -16,12 +16,6 @@ endif # USB_DEVICE_STACK config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - config PINMUX default y diff --git a/app/boards/arm/puchi_ble/puchi_ble_v1_defconfig b/app/boards/arm/puchi_ble/puchi_ble_v1_defconfig index 1adb9217c8a..ab197df0a80 100644 --- a/app/boards/arm/puchi_ble/puchi_ble_v1_defconfig +++ b/app/boards/arm/puchi_ble/puchi_ble_v1_defconfig @@ -25,3 +25,6 @@ CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y CONFIG_CLOCK_CONTROL_NRF=y CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/arm/s40nc/Kconfig.defconfig b/app/boards/arm/s40nc/Kconfig.defconfig index 11e62cf54c5..f892f392d5c 100644 --- a/app/boards/arm/s40nc/Kconfig.defconfig +++ b/app/boards/arm/s40nc/Kconfig.defconfig @@ -19,10 +19,4 @@ endif # USB config BT_CTLR default BT -config ZMK_BLE - default y - -config ZMK_USB - default y - endif # BOARD_S40NC diff --git a/app/boards/arm/s40nc/s40nc_defconfig b/app/boards/arm/s40nc/s40nc_defconfig index 31972781db1..b523ceb80b7 100644 --- a/app/boards/arm/s40nc/s40nc_defconfig +++ b/app/boards/arm/s40nc/s40nc_defconfig @@ -20,3 +20,6 @@ CONFIG_SETTINGS_NVS=y CONFIG_FLASH=y CONFIG_FLASH_PAGE_LAYOUT=y CONFIG_FLASH_MAP=y + +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y \ No newline at end of file diff --git a/app/boards/shields/nibble/Kconfig.defconfig b/app/boards/shields/nibble/Kconfig.defconfig index 31ac7cfe7dd..19bddec77b8 100644 --- a/app/boards/shields/nibble/Kconfig.defconfig +++ b/app/boards/shields/nibble/Kconfig.defconfig @@ -6,10 +6,6 @@ if SHIELD_NIBBLE config ZMK_KEYBOARD_NAME default "NIBBLE" -config ZMK_USB - default y - - if ZMK_DISPLAY config I2C diff --git a/app/src/split/bluetooth/Kconfig b/app/src/split/bluetooth/Kconfig index 5919010ba31..858e7308fef 100644 --- a/app/src/split/bluetooth/Kconfig +++ b/app/src/split/bluetooth/Kconfig @@ -62,9 +62,6 @@ config ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE int "Max number of key position state events to queue to send to the central" default 10 -config ZMK_USB - default n - config BT_MAX_PAIRED default 1 From afe65ead9c0f1418fa34bfa93325d0cce33c6c2c Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 13 Nov 2023 16:50:00 -0500 Subject: [PATCH 10/13] Revert "feat(build): Add support for artifact-name in build.yaml" This reverts commit c1bf35ce1de4b7d99c034300c9a813a0a3d11669. --- .github/workflows/build-user-config.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-user-config.yml b/.github/workflows/build-user-config.yml index 5aacadca90c..c1a97b4d6e0 100644 --- a/.github/workflows/build-user-config.yml +++ b/.github/workflows/build-user-config.yml @@ -55,14 +55,12 @@ jobs: - name: Prepare variables shell: sh -x {0} env: - board: ${{ matrix.board }} shield: ${{ matrix.shield }} - artifact_name: ${{ matrix.artifact-name }} run: | echo "zephyr_version=${ZEPHYR_VERSION}" >> $GITHUB_ENV echo "extra_cmake_args=${shield:+-DSHIELD=\"$shield\"}" >> $GITHUB_ENV - echo "display_name=${shield:+$shield - }${board}" >> $GITHUB_ENV - echo "artifact_name=${artifact_name:-\"${shield:+$shield-}${board}-zmk\"}" >> $GITHUB_ENV + echo "display_name=${shield:+$shield - }${{ matrix.board }}" >> $GITHUB_ENV + echo "artifact_name=${shield:+$shield-}${{ matrix.board }}-zmk" >> $GITHUB_ENV - name: Checkout uses: actions/checkout@v3 From 2a1904e184c5802a50c13f2d0ceca63df7c1b7df Mon Sep 17 00:00:00 2001 From: Chris Andreae Date: Tue, 14 Nov 2023 16:08:58 +0900 Subject: [PATCH 11/13] feat(boards): Add Glove80 to boards * Add board definition for MoErgo Glove80 --- app/boards/arm/glove80/CMakeLists.txt | 3 + app/boards/arm/glove80/Kconfig | 8 ++ app/boards/arm/glove80/Kconfig.board | 10 ++ app/boards/arm/glove80/Kconfig.defconfig | 65 ++++++++++ app/boards/arm/glove80/board.cmake | 6 + app/boards/arm/glove80/glove80.dtsi | 107 ++++++++++++++++ app/boards/arm/glove80/glove80.keymap | 114 ++++++++++++++++++ app/boards/arm/glove80/glove80.yaml | 19 +++ app/boards/arm/glove80/glove80.zmk.yml | 16 +++ .../arm/glove80/glove80_lh-pinctrl.dtsi | 47 ++++++++ app/boards/arm/glove80/glove80_lh.dts | 101 ++++++++++++++++ app/boards/arm/glove80/glove80_lh.keymap | 7 ++ app/boards/arm/glove80/glove80_lh_defconfig | 92 ++++++++++++++ .../arm/glove80/glove80_rh-pinctrl.dtsi | 48 ++++++++ app/boards/arm/glove80/glove80_rh.dts | 108 +++++++++++++++++ app/boards/arm/glove80/glove80_rh.keymap | 7 ++ app/boards/arm/glove80/glove80_rh_defconfig | 89 ++++++++++++++ app/boards/arm/glove80/readme.md | 13 ++ app/boards/arm/glove80/usb_serial_number.c | 67 ++++++++++ 19 files changed, 927 insertions(+) create mode 100644 app/boards/arm/glove80/CMakeLists.txt create mode 100644 app/boards/arm/glove80/Kconfig create mode 100644 app/boards/arm/glove80/Kconfig.board create mode 100644 app/boards/arm/glove80/Kconfig.defconfig create mode 100644 app/boards/arm/glove80/board.cmake create mode 100644 app/boards/arm/glove80/glove80.dtsi create mode 100644 app/boards/arm/glove80/glove80.keymap create mode 100644 app/boards/arm/glove80/glove80.yaml create mode 100644 app/boards/arm/glove80/glove80.zmk.yml create mode 100644 app/boards/arm/glove80/glove80_lh-pinctrl.dtsi create mode 100644 app/boards/arm/glove80/glove80_lh.dts create mode 100644 app/boards/arm/glove80/glove80_lh.keymap create mode 100644 app/boards/arm/glove80/glove80_lh_defconfig create mode 100644 app/boards/arm/glove80/glove80_rh-pinctrl.dtsi create mode 100644 app/boards/arm/glove80/glove80_rh.dts create mode 100644 app/boards/arm/glove80/glove80_rh.keymap create mode 100644 app/boards/arm/glove80/glove80_rh_defconfig create mode 100644 app/boards/arm/glove80/readme.md create mode 100644 app/boards/arm/glove80/usb_serial_number.c diff --git a/app/boards/arm/glove80/CMakeLists.txt b/app/boards/arm/glove80/CMakeLists.txt new file mode 100644 index 00000000000..3eb2cd276ea --- /dev/null +++ b/app/boards/arm/glove80/CMakeLists.txt @@ -0,0 +1,3 @@ +zephyr_library() +zephyr_library_sources(usb_serial_number.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) diff --git a/app/boards/arm/glove80/Kconfig b/app/boards/arm/glove80/Kconfig new file mode 100644 index 00000000000..f1c12e7e314 --- /dev/null +++ b/app/boards/arm/glove80/Kconfig @@ -0,0 +1,8 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on (BOARD_GLOVE80_LH || BOARD_GLOVE80_RH) diff --git a/app/boards/arm/glove80/Kconfig.board b/app/boards/arm/glove80/Kconfig.board new file mode 100644 index 00000000000..f689103710f --- /dev/null +++ b/app/boards/arm/glove80/Kconfig.board @@ -0,0 +1,10 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config BOARD_GLOVE80_LH + bool "Glove80 LH" + depends on SOC_NRF52840_QIAA + +config BOARD_GLOVE80_RH + bool "Glove80 RH" + depends on SOC_NRF52840_QIAA diff --git a/app/boards/arm/glove80/Kconfig.defconfig b/app/boards/arm/glove80/Kconfig.defconfig new file mode 100644 index 00000000000..e1c452a5444 --- /dev/null +++ b/app/boards/arm/glove80/Kconfig.defconfig @@ -0,0 +1,65 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if BOARD_GLOVE80_LH + +config BOARD + default "glove80 lh" + +config ZMK_SPLIT_BLE_ROLE_CENTRAL + default y + +endif # BOARD_GLOVE80_LH + +if BOARD_GLOVE80_RH + +config BOARD + default "glove80 rh" + +endif # BOARD_GLOVE80_RH + +if BOARD_GLOVE80_LH || BOARD_GLOVE80_RH + +config ZMK_SPLIT + default y + +config BT_CTLR + default BT + +config ZMK_KSCAN_MATRIX_WAIT_BETWEEN_OUTPUTS + default 5 + +config PINCTRL + default y + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +if ZMK_BACKLIGHT + +config PWM + default y + +config LED_PWM + default y + +endif # ZMK_BACKLIGHT + +if ZMK_RGB_UNDERGLOW + +config SPI + default y + +config WS2812_STRIP + default y + +endif # ZMK_RGB_UNDERGLOW + +endif # BOARD_GLOVE80_LH || BOARD_GLOVE80_RH diff --git a/app/boards/arm/glove80/board.cmake b/app/boards/arm/glove80/board.cmake new file mode 100644 index 00000000000..36030db7b10 --- /dev/null +++ b/app/boards/arm/glove80/board.cmake @@ -0,0 +1,6 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) diff --git a/app/boards/arm/glove80/glove80.dtsi b/app/boards/arm/glove80/glove80.dtsi new file mode 100644 index 00000000000..f3f58cf7b42 --- /dev/null +++ b/app/boards/arm/glove80/glove80.dtsi @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + zephyr,code-partition = &code_partition; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,console = &cdc_acm_uart; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <6>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,13) + RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,13) + RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(0,6) RC(1,6) RC(2,6) RC(2,7) RC(1,7) RC(0,7) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(3,6) RC(4,6) RC(5,6) RC(5,7) RC(4,7) RC(3,7) RC(5,9) RC(5,10) RC(5,11) RC(5,12) RC(5,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + debounce-press-ms = <4>; + debounce-release-ms = <20>; + }; + +}; + +&adc { + status = "okay"; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&usbd { + status = "okay"; + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + label = "CDC_ACM_0"; + }; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/devices/dts/flash_partitions.html + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + sd_partition: partition@0 { + label = "softdevice"; + reg = <0x00000000 0x00026000>; + }; + code_partition: partition@26000 { + label = "code_partition"; + reg = <0x00026000 0x000c6000>; + }; + + /* + * The flash starting at 0x000ec000 and ending at + * 0x000f3fff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@ec000 { + label = "storage"; + reg = <0x000ec000 0x00008000>; + }; + + boot_partition: partition@f4000 { + label = "adafruit_boot"; + reg = <0x000f4000 0x0000c000>; + }; + }; +}; diff --git a/app/boards/arm/glove80/glove80.keymap b/app/boards/arm/glove80/glove80.keymap new file mode 100644 index 00000000000..6c920ca1dcd --- /dev/null +++ b/app/boards/arm/glove80/glove80.keymap @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +// layers +#define DEFAULT 0 +#define LOWER 1 +#define MAGIC 2 + +/ { + behaviors { + // For the "layer" key, it'd nice to be able to use it as either a shift or a toggle. + // Configure it as a tap dance, so the first tap (or hold) is a &mo and the second tap is a &to + layer_td: tap_dance_0 { + compatible = "zmk,behavior-tap-dance"; + label = "LAYER_TAP_DANCE"; + #binding-cells = <0>; + tapping-term-ms = <200>; + bindings = <&mo LOWER>, <&to LOWER>; + }; + }; + + macros { + bt_0: bt_profile_macro_0 { + label = "BT_0"; + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 0>; + }; + + bt_1: bt_profile_macro_1 { + label = "BT_1"; + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 1>; + }; + + bt_2: bt_profile_macro_2 { + label = "BT_2"; + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 2>; + }; + + bt_3: bt_profile_macro_3 { + label = "BT_3"; + compatible = "zmk,behavior-macro"; + #binding-cells = <0>; + bindings + = <&out OUT_BLE>, + <&bt BT_SEL 3>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + + default_layer { + // --------------------------------------------------------------------------------------------------------------------------------- + // | F1 | F2 | F3 | F4 | F5 | | F6 | F7 | F8 | F9 | F10 | + // | = | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | - | + // | TAB | Q | W | E | R | T | | Y | U | I | O | P | \ | + // | ESC | A | S | D | F | G | | H | J | K | L | ; | ' | + // | ` | Z | X | C | V | B | LSHFT | LCTRL | LOWER | | LGUI | RCTRL | RSHFT | N | M | , | . | / | PGUP | + // | MAGIC | HOME| END | LEFT | RIGHT| | BSPC | DEL | LALT | | RALT | RET | SPACE | | UP | DOWN | [ | ] | PGDN | + + bindings = < + &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 + &kp EQUAL &kp N1 &kp N2 &kp N3 &kp N4 &kp N5 &kp N6 &kp N7 &kp N8 &kp N9 &kp N0 &kp MINUS + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BSLH + &kp ESC &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SEMI &kp SQT + &kp GRAVE &kp Z &kp X &kp C &kp V &kp B &kp LSHFT &kp LCTRL &layer_td &kp LGUI &kp RCTRL &kp RSHFT &kp N &kp M &kp COMMA &kp DOT &kp FSLH &kp PG_UP + &mo MAGIC &kp HOME &kp END &kp LEFT &kp RIGHT &kp BSPC &kp DEL &kp LALT &kp RALT &kp RET &kp SPACE &kp UP &kp DOWN &kp LBKT &kp RBKT &kp PG_DN + >; + }; + + lower_layer { + bindings = < + &kp C_BRI_DN &kp C_BRI_UP &kp C_PREV &kp C_NEXT &kp C_PP &kp C_MUTE &kp C_VOL_DN &kp C_VOL_UP &none &kp PAUSE_BREAK + &trans &none &none &none &none &kp HOME &kp LPAR &kp KP_NUM &kp KP_EQUAL &kp KP_DIVIDE &kp KP_MULTIPLY &kp PSCRN + &trans &none &none &kp UP &none &kp END &kp RPAR &kp KP_N7 &kp KP_N8 &kp KP_N9 &kp KP_MINUS &kp SLCK + &trans &none &kp LEFT &kp DOWN &kp RIGHT &kp PG_UP &kp PRCNT &kp KP_N4 &kp KP_N5 &kp KP_N6 &kp KP_PLUS &none + &trans &kp K_CMENU &none &kp F11 &kp F12 &kp PG_DN &trans &trans &to DEFAULT &trans &trans &trans &kp COMMA &kp KP_N1 &kp KP_N2 &kp KP_N3 &kp KP_ENTER &trans + &trans &kp CAPS &kp INS &kp F11 &kp F12 &trans &trans &trans &trans &trans &trans &kp KP_N0 &kp KP_N0 &kp KP_DOT &kp KP_ENTER &trans + >; + }; + + magic_layer { + bindings = < + &bt BT_CLR &none &none &none &none &none &none &none &none &none + &none &none &none &none &none &none &none &none &none &none &none &none + &none &rgb_ug RGB_SPI &rgb_ug RGB_SAI &rgb_ug RGB_HUI &rgb_ug RGB_BRI &rgb_ug RGB_TOG &none &none &none &none &none &none + &bootloader &rgb_ug RGB_SPD &rgb_ug RGB_SAD &rgb_ug RGB_HUD &rgb_ug RGB_BRD &rgb_ug RGB_EFF &none &none &none &none &none &bootloader + &sys_reset &none &none &none &none &none &bt_2 &bt_3 &none &none &none &none &none &none &none &none &none &sys_reset + &none &none &none &none &none &bt_0 &bt_1 &out OUT_USB &none &none &none &none &none &none &none &none + >; + }; + }; +}; diff --git a/app/boards/arm/glove80/glove80.yaml b/app/boards/arm/glove80/glove80.yaml new file mode 100644 index 00000000000..90a5e13307f --- /dev/null +++ b/app/boards/arm/glove80/glove80.yaml @@ -0,0 +1,19 @@ +identifier: glove80 +name: Glove80 +url: https://www.moergo.com/ +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog + - gpio + - i2c + - spi diff --git a/app/boards/arm/glove80/glove80.zmk.yml b/app/boards/arm/glove80/glove80.zmk.yml new file mode 100644 index 00000000000..ca70b7d6acf --- /dev/null +++ b/app/boards/arm/glove80/glove80.zmk.yml @@ -0,0 +1,16 @@ +file_format: "1" +id: glove80 +name: Glove80 +type: board +arch: arm +url: https://www.moergo.com/ +features: + - keys + - underglow + - backlight +outputs: + - usb + - ble +siblings: + - glove80_lh + - glove80_rh diff --git a/app/boards/arm/glove80/glove80_lh-pinctrl.dtsi b/app/boards/arm/glove80/glove80_lh-pinctrl.dtsi new file mode 100644 index 00000000000..3dbf3d7e1a1 --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh-pinctrl.dtsi @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; // WS2812_VEXT_DATA + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; // rear LED + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + bias-pull-down; + }; + }; + + uart0_default: uart0_default { + group1 { + psels = , // EXT1 + ; // EXT2 + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; diff --git a/app/boards/arm/glove80/glove80_lh.dts b/app/boards/arm/glove80/glove80_lh.dts new file mode 100644 index 00000000000..ed40e0d2d1e --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh.dts @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "glove80.dtsi" +#include "glove80_lh-pinctrl.dtsi" + +#include + +/ { + model = "glove80_lh"; + compatible = "glove80_lh"; + + chosen { + zmk,underglow = &led_strip; + zmk,backlight = &back_led_backlight; + zmk,battery = &vbatt; + }; + + back_led_backlight: pwmleds { + compatible = "pwm-leds"; + label = "BACK LED"; + pwm_led_0 { + pwms = <&pwm0 0 PWM_USEC(20) PWM_POLARITY_NORMAL>; + label = "Back LED configured as backlight"; + }; + }; + + ext-power { + compatible = "zmk,ext-power-generic"; + label = "EXT_POWER"; + control-gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; /* WS2812_CE */ + init-delay-ms = <100>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-nrf-vddh"; + label = "BATTERY"; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + label = "WS2812C-2020"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <40>; /* 40 keys have underglow at the moment */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&uart0 { + compatible = "nordic,nrf-uarte"; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&kscan0 { + row-gpios + = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW1 + , <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW2 + , <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW3 + , <&gpio0 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW4 + , <&gpio0 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW5 + , <&gpio1 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // LH ROW6 + ; + col-gpios + = <&gpio1 8 GPIO_ACTIVE_HIGH> // LH COL6 + , <&gpio1 4 GPIO_ACTIVE_HIGH> // LH COL5 + , <&gpio1 6 GPIO_ACTIVE_HIGH> // LH COL4 + , <&gpio1 7 GPIO_ACTIVE_HIGH> // LH COL3 + , <&gpio1 5 GPIO_ACTIVE_HIGH> // LH COL2 + , <&gpio1 3 GPIO_ACTIVE_HIGH> // LH COL1 + , <&gpio1 1 GPIO_ACTIVE_HIGH> // LH Thumb + ; +}; diff --git a/app/boards/arm/glove80/glove80_lh.keymap b/app/boards/arm/glove80/glove80_lh.keymap new file mode 100644 index 00000000000..dd4c2d6a01f --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh.keymap @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "glove80.keymap" diff --git a/app/boards/arm/glove80/glove80_lh_defconfig b/app/boards/arm/glove80/glove80_lh_defconfig new file mode 100644 index 00000000000..a93f27cd8f2 --- /dev/null +++ b/app/boards/arm/glove80/glove80_lh_defconfig @@ -0,0 +1,92 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_GLOVE80_LH=y + +# Enable both USB and BLE +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# Keyboard IDs +CONFIG_ZMK_KEYBOARD_NAME="Glove80 Left" +CONFIG_USB_DEVICE_PID=0x27db +CONFIG_USB_DEVICE_VID=0x16c0 +CONFIG_USB_DEVICE_MANUFACTURER="MoErgo" +CONFIG_USB_DEVICE_SN="moergo.com:GLV80-0123456789ABCDEF" + +CONFIG_BT_DIS_PNP_PID=0x27db +CONFIG_BT_DIS_PNP_VID=0x16c0 +CONFIG_BT_DIS_MANUF="MoErgo" +CONFIG_BT_DIS_MODEL="Glove80" + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +# Work-around for Windows bug with battery notifications +CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION=n + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Build configurations +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_UF2_FAMILY_ID="0x9807B007" +CONFIG_USE_DT_CODE_PARTITION=y + +# Flash configuration +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y + +# Enable RGB underglow +CONFIG_ZMK_RGB_UNDERGLOW=y + +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n +CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP=4 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN=4 + +# DO NOT CHANGE CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX TO ABOVE 80. Configuring +# BRT_MAX above 80% will draw additional current and can potentially damage your +# computer. WARRANTY IS VOID IF BRT_MAX SET ABOVE 80. +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX=80 + +CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3 +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=285 +CONFIG_ZMK_RGB_UNDERGLOW_SAT_START=75 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=16 + +# The power LED is implemented as a backlight +# For now, the power LED is acting as a "USB connected" indicator +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_ON_START=y +CONFIG_ZMK_BACKLIGHT_BRT_START=5 +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB=y + +# The full two-byte consumer report space has compatibility issues with some +# operating systems, most notably macOS. Use the more basic single-byte usage +# space. +CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y + +# Turn on debugging to disable optimization. Debug messages can result in larger +# stacks, so enable stack protection and particularly a larger BLE peripheral stack. +# CONFIG_DEBUG=y +# CONFIG_DEBUG_THREAD_INFO=y +# CONFIG_EXCEPTION_STACK_TRACE=y +# CONFIG_HW_STACK_PROTECTION=y +# CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE=1300 + +# Log via USB or Segger RTT +CONFIG_ZMK_USB_LOGGING=n +CONFIG_ZMK_RTT_LOGGING=n diff --git a/app/boards/arm/glove80/glove80_rh-pinctrl.dtsi b/app/boards/arm/glove80/glove80_rh-pinctrl.dtsi new file mode 100644 index 00000000000..454a2621051 --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh-pinctrl.dtsi @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +&pinctrl { + spi3_default: spi3_default { + group1 { + psels = ; // WS2812_VEXT_DATA + }; + }; + + spi3_sleep: spi3_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + pwm0_default: pwm0_default { + group1 { + psels = ; // Rear LED + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + bias-pull-down; + }; + }; + + uart0_default: uart0_default { + group1 { + psels = , // EXT1 + ; // EXT2 + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + +}; diff --git a/app/boards/arm/glove80/glove80_rh.dts b/app/boards/arm/glove80/glove80_rh.dts new file mode 100644 index 00000000000..288f63688ca --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh.dts @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2021 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + +#include "glove80.dtsi" +#include "glove80_rh-pinctrl.dtsi" + +#include + +/ { + model = "glove80_rh"; + compatible = "glove80_rh"; + + chosen { + zmk,underglow = &led_strip; + zmk,backlight = &back_led_backlight; + zmk,battery = &vbatt; + }; + + back_led_backlight: pwmleds { + compatible = "pwm-leds"; + label = "BACK LED"; + pwm_led_0 { + pwms = <&pwm0 0 PWM_USEC(20) PWM_POLARITY_NORMAL>; + label = "Back LED configured as backlight"; + }; + }; + + ext-power { + compatible = "zmk,ext-power-generic"; + label = "EXT_POWER"; + control-gpios = <&gpio0 19 GPIO_ACTIVE_HIGH>; /* WS2812_CE */ + init-delay-ms = <100>; + }; + + vbatt: vbatt { + compatible = "zmk,battery-nrf-vddh"; + label = "BATTERY"; + }; +}; + +&spi3 { + compatible = "nordic,nrf-spim"; + status = "okay"; + + pinctrl-0 = <&spi3_default>; + pinctrl-1 = <&spi3_sleep>; + pinctrl-names = "default", "sleep"; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + label = "WS2812C-2020"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <40>; /* 40 keys have underglow at the moment */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + + color-mapping = ; + }; +}; + +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + + +&uart0 { + compatible = "nordic,nrf-uarte"; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +/* For right hand, the columns are offset by 7 */ +&default_transform { + col-offset = <7>; +}; + +&kscan0 { + row-gpios + = <&gpio0 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW1 + , <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW2 + , <&gpio0 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW3 + , <&gpio1 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW4 + , <&gpio0 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW5 + , <&gpio0 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // RH ROW6 + ; + col-gpios + = <&gpio1 6 GPIO_ACTIVE_HIGH> // RH Thumb + , <&gpio1 4 GPIO_ACTIVE_HIGH> // RH COL1 + , <&gpio0 2 GPIO_ACTIVE_HIGH> // RH COL2 + , <&gpio1 7 GPIO_ACTIVE_HIGH> // RH COL3 + , <&gpio1 5 GPIO_ACTIVE_HIGH> // RH COL4 + , <&gpio1 3 GPIO_ACTIVE_HIGH> // RH COL5 + , <&gpio1 1 GPIO_ACTIVE_HIGH> // RH COL6 + ; +}; diff --git a/app/boards/arm/glove80/glove80_rh.keymap b/app/boards/arm/glove80/glove80_rh.keymap new file mode 100644 index 00000000000..dd4c2d6a01f --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh.keymap @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include "glove80.keymap" diff --git a/app/boards/arm/glove80/glove80_rh_defconfig b/app/boards/arm/glove80/glove80_rh_defconfig new file mode 100644 index 00000000000..ef29d682a54 --- /dev/null +++ b/app/boards/arm/glove80/glove80_rh_defconfig @@ -0,0 +1,89 @@ +# Copyright (c) 2021 The ZMK Contributors +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_GLOVE80_RH=y + +# Enable both USB and BLE +CONFIG_ZMK_USB=y +CONFIG_ZMK_BLE=y + +# Keyboard IDs +CONFIG_ZMK_KEYBOARD_NAME="Glove80 Right" +CONFIG_USB_DEVICE_PID=0x27d9 +CONFIG_USB_DEVICE_VID=0x16c0 +CONFIG_USB_DEVICE_MANUFACTURER="MoErgo" +CONFIG_USB_DEVICE_SN="moergo.com:GLV80-0123456789ABCDEF" + +CONFIG_BT_DIS_PNP_PID=0x27d9 +CONFIG_BT_DIS_PNP_VID=0x16c0 +CONFIG_BT_DIS_MANUF="MoErgo" +CONFIG_BT_DIS_MODEL="Glove80 Right" + +CONFIG_BT_CTLR_TX_PWR_PLUS_8=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# Enable GPIO +CONFIG_GPIO=y + +# Build configurations +CONFIG_BUILD_OUTPUT_UF2=y +CONFIG_BUILD_OUTPUT_UF2_FAMILY_ID="0x9808B007" +CONFIG_USE_DT_CODE_PARTITION=y + +# Flash configuration +CONFIG_MPU_ALLOW_FLASH_WRITE=y +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_FLASH=y +CONFIG_FLASH_PAGE_LAYOUT=y +CONFIG_FLASH_MAP=y + +# Enable 32kHz crystal +CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y + +# Enable RGB underglow +CONFIG_ZMK_RGB_UNDERGLOW=y + +CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y +CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n +CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP=4 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN=4 + +# DO NOT CHANGE CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX TO ABOVE 80. Configuring +# BRT_MAX above 80% will draw additional current and can potentially damage your +# computer. WARRANTY IS VOID IF BRT_MAX SET ABOVE 80. +CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX=80 + +CONFIG_ZMK_RGB_UNDERGLOW_EFF_START=3 +CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=285 +CONFIG_ZMK_RGB_UNDERGLOW_SAT_START=75 +CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=16 + +# The power LED is implemented as a backlight +# For now, the power LED is acting as a "USB connected" indicator +CONFIG_ZMK_BACKLIGHT=y +CONFIG_ZMK_BACKLIGHT_ON_START=y +CONFIG_ZMK_BACKLIGHT_BRT_START=5 +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE=y +CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB=y + +# The full two-byte consumer report space has compatibility issues with some +# operating systems, most notably macOS. Use the more basic single-byte usage +# space. +CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y + +# Turn on debugging to disable optimization. Debug messages can result in larger +# stacks, so enable stack protection and particularly a larger BLE peripheral stack. +# CONFIG_DEBUG=y +# CONFIG_DEBUG_THREAD_INFO=y +# CONFIG_EXCEPTION_STACK_TRACE=y +# CONFIG_HW_STACK_PROTECTION=y +# CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE=1300 + +# Log via USB or Segger RTT +CONFIG_ZMK_USB_LOGGING=n +CONFIG_ZMK_RTT_LOGGING=n diff --git a/app/boards/arm/glove80/readme.md b/app/boards/arm/glove80/readme.md new file mode 100644 index 00000000000..2c770376116 --- /dev/null +++ b/app/boards/arm/glove80/readme.md @@ -0,0 +1,13 @@ +## MoErgo Glove80 + +This board definition provides ZMK support for the [MoErgo Glove80](https://www.moergo.com) +keyboard. + +MoErgo additionally offers a customized version of ZMK which adds additional functionality such as +RGB status indicators, available on GitHub at [moergo-sc/zmk](https://github.com/moergo-sc/zmk). The +MoErgo customized ZMK fork is regularly updated to include the latest changes from mainline ZMK, but +will not always be completely up-to-date. MoErgo also offers an online layout configurator and +firmware builder application using the customized fork at [my.glove80.com](https://my.glove80.com). + +While mainline ZMK is expected to work well with Glove80, MoErgo only provides support for use of +their customized fork. Likewise, the ZMK community cannot directly provide support for MoErgo's fork. diff --git a/app/boards/arm/glove80/usb_serial_number.c b/app/boards/arm/glove80/usb_serial_number.c new file mode 100644 index 00000000000..44d7ee20363 --- /dev/null +++ b/app/boards/arm/glove80/usb_serial_number.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include "usb_descriptor.h" + +#define LOG_LEVEL CONFIG_USB_DEVICE_LOG_LEVEL +#include +LOG_MODULE_DECLARE(usb_descriptor); + +int base16_encode(const uint8_t *data, int length, uint8_t *result, int bufSize); + +uint8_t *usb_update_sn_string_descriptor(void) { + /* + * nrf52840 hwinfo returns a 64-bit hardware id. Glove80 uses this as a + * serial number, encoded as base16 into the last 16 characters of the + * CONFIG_USB_DEVICE_SN template. If insufficient template space is + * available, instead return the static serial number string. + */ + const uint8_t template_len = sizeof(CONFIG_USB_DEVICE_SN); + const uint8_t sn_len = 16; + + if (template_len < sn_len + 1) { + LOG_DBG("Serial number template too short"); + return CONFIG_USB_DEVICE_SN; + } + + static uint8_t serial[sizeof(CONFIG_USB_DEVICE_SN)]; + strncpy(serial, CONFIG_USB_DEVICE_SN, template_len); + + uint8_t hwid[8]; + memset(hwid, 0, sizeof(hwid)); + uint8_t hwlen = hwinfo_get_device_id(hwid, sizeof(hwid)); + + if (hwlen > 0) { + const uint8_t offset = template_len - sn_len - 1; + LOG_HEXDUMP_DBG(&hwid, sn_len, "Serial Number"); + base16_encode(hwid, hwlen, serial + offset, sn_len + 1); + } + + return serial; +} + +int base16_encode(const uint8_t *data, int length, uint8_t *result, int bufSize) { + const char hex[] = "0123456789ABCDEF"; + + int i = 0; + while (i < bufSize && i < length * 2) { + uint8_t nibble; + if (i % 2 == 0) { + nibble = data[i / 2] >> 4; + } else { + nibble = data[i / 2] & 0xF; + } + result[i] = hex[nibble]; + ++i; + } + if (i < bufSize) { + result[i] = '\0'; + } + return i; +} From f6716f869a0fd20ac9520e2808dc4183742436a5 Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Tue, 14 Nov 2023 07:03:25 +0000 Subject: [PATCH 12/13] fix(usb): Build with ZMK_USB_BOOT disabled. * Invert the logic so `get_keyboard_report` is sane when `ZMK_USB_BOOT` is disabled. --- app/src/usb_hid.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c index c72bb36c9ef..d2a52cf24ab 100644 --- a/app/src/usb_hid.c +++ b/app/src/usb_hid.c @@ -39,16 +39,16 @@ void zmk_usb_hid_set_protocol(uint8_t protocol) { hid_protocol = protocol; } #endif /* IS_ENABLED(CONFIG_ZMK_USB_BOOT) */ static uint8_t *get_keyboard_report(size_t *len) { - if (hid_protocol == HID_PROTOCOL_REPORT) { - struct zmk_hid_keyboard_report *report = zmk_hid_get_keyboard_report(); - *len = sizeof(*report); - return (uint8_t *)report; - } #if IS_ENABLED(CONFIG_ZMK_USB_BOOT) - zmk_hid_boot_report_t *boot_report = zmk_hid_get_boot_report(); - *len = sizeof(*boot_report); - return (uint8_t *)boot_report; + if (hid_protocol != HID_PROTOCOL_REPORT) { + zmk_hid_boot_report_t *boot_report = zmk_hid_get_boot_report(); + *len = sizeof(*boot_report); + return (uint8_t *)boot_report; + } #endif + struct zmk_hid_keyboard_report *report = zmk_hid_get_keyboard_report(); + *len = sizeof(*report); + return (uint8_t *)report; } static int get_report_cb(const struct device *dev, struct usb_setup_packet *setup, int32_t *len, From 3027b2a6e8f2896f7e08d5a502be50ad21f32d7f Mon Sep 17 00:00:00 2001 From: Peter Johanson Date: Tue, 14 Nov 2023 07:50:48 +0000 Subject: [PATCH 13/13] chore(usb): Don't enable ZMK_USB_ROOT by default. * Some initial reports of crashes with this code enabled, so disabling by default for now pending further investigation. --- app/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Kconfig b/app/Kconfig index 282339e3e40..072795e317b 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -98,7 +98,6 @@ config ZMK_USB config ZMK_USB_BOOT bool "USB Boot Protocol Support" - default y depends on ZMK_USB select USB_HID_BOOT_PROTOCOL select USB_DEVICE_SOF