From bc282a0a4f1af4f6f78a0dd63e5b022eb76a603c Mon Sep 17 00:00:00 2001 From: Nick Date: Sun, 2 Aug 2020 10:29:07 -0500 Subject: [PATCH 001/227] WIP DZ60RGB board definition --- app/boards/arm/dz60rgb/CMakeLists.txt | 9 ++ app/boards/arm/dz60rgb/Kconfig.board | 6 ++ app/boards/arm/dz60rgb/Kconfig.defconfig | 14 +++ app/boards/arm/dz60rgb/board.cmake | 6 ++ app/boards/arm/dz60rgb/dz60rgb_rev1.dts | 87 +++++++++++++++++++ app/boards/arm/dz60rgb/dz60rgb_rev1.yaml | 19 ++++ app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig | 30 +++++++ app/boards/arm/dz60rgb/keymap/keymap.overlay | 37 ++++++++ app/boards/arm/dz60rgb/pinmux.c | 69 +++++++++++++++ 9 files changed, 277 insertions(+) create mode 100644 app/boards/arm/dz60rgb/CMakeLists.txt create mode 100644 app/boards/arm/dz60rgb/Kconfig.board create mode 100644 app/boards/arm/dz60rgb/Kconfig.defconfig create mode 100644 app/boards/arm/dz60rgb/board.cmake create mode 100644 app/boards/arm/dz60rgb/dz60rgb_rev1.dts create mode 100644 app/boards/arm/dz60rgb/dz60rgb_rev1.yaml create mode 100644 app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig create mode 100644 app/boards/arm/dz60rgb/keymap/keymap.overlay create mode 100644 app/boards/arm/dz60rgb/pinmux.c diff --git a/app/boards/arm/dz60rgb/CMakeLists.txt b/app/boards/arm/dz60rgb/CMakeLists.txt new file mode 100644 index 00000000..6a0ec73e --- /dev/null +++ b/app/boards/arm/dz60rgb/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT + +list(APPEND EXTRA_DTC_FLAGS "-qq") + +if(CONFIG_PINMUX) +zephyr_library() +zephyr_library_sources(pinmux.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) +endif() diff --git a/app/boards/arm/dz60rgb/Kconfig.board b/app/boards/arm/dz60rgb/Kconfig.board new file mode 100644 index 00000000..a96271f0 --- /dev/null +++ b/app/boards/arm/dz60rgb/Kconfig.board @@ -0,0 +1,6 @@ +# Copyright (c) 2020 Nick Winans +# SPDX-License-Identifier: MIT + +config BOARD_DZ60RGB_REV1 + bool "DZ60RGB Keyboard" + depends on SOC_STM32F303XC diff --git a/app/boards/arm/dz60rgb/Kconfig.defconfig b/app/boards/arm/dz60rgb/Kconfig.defconfig new file mode 100644 index 00000000..cfa71d3f --- /dev/null +++ b/app/boards/arm/dz60rgb/Kconfig.defconfig @@ -0,0 +1,14 @@ +# Planck keyboard configuration + +# Copyright (c) 2020 Nick Winans +# SPDX-License-Identifier: MIT + +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/board.cmake b/app/boards/arm/dz60rgb/board.cmake new file mode 100644 index 00000000..4843c415 --- /dev/null +++ b/app/boards/arm/dz60rgb/board.cmake @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: MIT + +board_runner_args(jlink "--device=STM32F303VC" "--speed=4000") + +include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts new file mode 100644 index 00000000..8066b5ad --- /dev/null +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Nick Winans + * + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +#include + +/ { + model = "DZ60RGB, Rev 1"; + compatible = "dz60rgb,rev1", "st,stm32f303"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zmk,kscan = &kscan0; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <14>; + rows = <5>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) 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,6) RC(1,7) 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,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) +RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&gpioa 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpiob 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpioa 6 GPIO_ACTIVE_HIGH> + , <&gpioa 7 GPIO_ACTIVE_HIGH> + , <&gpiob 0 GPIO_ACTIVE_HIGH> + , <&gpiob 13 GPIO_ACTIVE_HIGH> + , <&gpiob 15 GPIO_ACTIVE_HIGH> + , <&gpioa 8 GPIO_ACTIVE_HIGH> + , <&gpioa 15 GPIO_ACTIVE_HIGH> + , <&gpiob 3 GPIO_ACTIVE_HIGH> + , <&gpiob 4 GPIO_ACTIVE_HIGH> + , <&gpiob 5 GPIO_ACTIVE_HIGH> + , <&gpiob 6 GPIO_ACTIVE_HIGH> + , <&gpiob 9 GPIO_ACTIVE_HIGH> + , <&gpioc 13 GPIO_ACTIVE_HIGH> + , <&gpioc 14 GPIO_ACTIVE_HIGH> + ; + }; + +}; + +&usb { + status = "okay"; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Set 6Kb of storage at the end of the 256Kb of flash */ + storage_partition: partition@3e800 { + label = "storage"; + reg = <0x0003e800 0x00001800>; + }; + }; +}; diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.yaml b/app/boards/arm/dz60rgb/dz60rgb_rev1.yaml new file mode 100644 index 00000000..d2836218 --- /dev/null +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.yaml @@ -0,0 +1,19 @@ +identifier: DZ60RGB_rev1 +name: DZ60RGBREV1 +type: keyboard +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 40 +supported: + - gpio + - i2c + - counter + - spi + - usb_device + - lsm303dlhc + - nvs + - can + - kscan diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig new file mode 100644 index 00000000..5a4c0995 --- /dev/null +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: MIT + +CONFIG_SOC_SERIES_STM32F3X=y +CONFIG_SOC_STM32F303XC=y +# 72MHz system clock +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=72000000 + +# enable pinmux +CONFIG_PINMUX=y + +# enable GPIO +CONFIG_GPIO=y + +# clock configuration +CONFIG_CLOCK_CONTROL=y + +# Clock configuration for Cube Clock control driver +CONFIG_CLOCK_STM32_HSE_CLOCK=8000000 +CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL=y +# use HSE as PLL input +CONFIG_CLOCK_STM32_PLL_SRC_HSE=y +# however, the board does not have an external oscillator, so just use +# the 8MHz clock signal coming from integrated STLink +CONFIG_CLOCK_STM32_HSE_BYPASS=y +# produce 72MHz clock at PLL output +CONFIG_CLOCK_STM32_PLL_PREDIV=1 +CONFIG_CLOCK_STM32_PLL_MULTIPLIER=9 +CONFIG_CLOCK_STM32_AHB_PRESCALER=1 +CONFIG_CLOCK_STM32_APB1_PRESCALER=2 +CONFIG_CLOCK_STM32_APB2_PRESCALER=1 diff --git a/app/boards/arm/dz60rgb/keymap/keymap.overlay b/app/boards/arm/dz60rgb/keymap/keymap.overlay new file mode 100644 index 00000000..9d83adcf --- /dev/null +++ b/app/boards/arm/dz60rgb/keymap/keymap.overlay @@ -0,0 +1,37 @@ +#include +#include +#include + +/ { + chosen { + zmk,keymap = &keymap0; + }; + + keymap0: keymap { + compatible = "zmk,keymap"; + label ="Default DZ60RGB Keymap"; + layers = <&default>; + }; + + layers { + compatible = "zmk,layers"; + + default: layer_0 { + label = "DEFAULT"; +// ------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | +// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | +// | SHIFT | Z | X | C | V | B | N | M | , | . | SHIFT(/) | ^ | DEL | +// | CTL | WIN | ALT | SPACE | ALT | MO(1) | <- | v | -> | +// ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp MINUS &kp EQL &kp BKSP + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp QUOT &kp RET + &kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &mt MOD_RSFT FSLH &kp UARW &kp DEL + &kp LCTL &kp LGUI &kp LALT &kp SPC &kp RALT &mo 1 &kp LARW &kp DARW &kp RARW + >; + }; + }; +}; diff --git a/app/boards/arm/dz60rgb/pinmux.c b/app/boards/arm/dz60rgb/pinmux.c new file mode 100644 index 00000000..5df5c90e --- /dev/null +++ b/app/boards/arm/dz60rgb/pinmux.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017 I-SENSE group of ICCS + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include + +#include + +/* pin assignments for STM32F3DISCOVERY board */ +static const struct pin_config pinconf[] = { +#ifdef CONFIG_UART_1 + {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, + {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, +#endif /* CONFIG_UART_1 */ +#ifdef CONFIG_UART_2 + {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, + {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, +#endif /* CONFIG_UART_2 */ +#ifdef CONFIG_I2C_1 + {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, + {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, +#endif /* CONFIG_I2C_1 */ +#ifdef CONFIG_I2C_2 + {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, + {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, +#endif /* CONFIG_I2C_2 */ +#ifdef CONFIG_SPI_1 +#ifdef CONFIG_SPI_STM32_USE_HW_SS + {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, +#endif /* CONFIG_SPI_STM32_USE_HW_SS */ + {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, + {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, + {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, +#endif /* CONFIG_SPI_1 */ +#ifdef CONFIG_SPI_2 +#ifdef CONFIG_SPI_STM32_USE_HW_SS + {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, +#endif /* CONFIG_SPI_STM32_USE_HW_SS */ + {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, + {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, + {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, +#endif /* CONFIG_SPI_2 */ +#ifdef CONFIG_USB_DC_STM32 + {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, + {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, +#endif /* CONFIG_USB_DC_STM32 */ +#ifdef CONFIG_CAN_1 + {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, + {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, +#endif /* CONFIG_CAN_1 */ +}; + +static int pinmux_stm32_init(struct device *port) +{ + ARG_UNUSED(port); + + stm32_setup_pins(pinconf, ARRAY_SIZE(pinconf)); + + return 0; +} + +SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, + CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); From 3ee2d1196b9335a081d841ff3918d2fdf722d5b9 Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 20 Aug 2020 00:07:04 -0500 Subject: [PATCH 002/227] feat(rgb): underglow state Kconfig and settings --- app/Kconfig | 24 +++++++++++++ app/src/rgb_underglow.c | 77 +++++++++++++++++++++++++++++++---------- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index 416c9852..cefae21a 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -180,6 +180,30 @@ config ZMK_RGB_UNDERGLOW_BRT_STEP int "RGB underglow brightness step in percent" default 10 +config ZMK_RGB_UNDERGLOW_HUE_START + int "RGB underglow start hue value from 0-359" + default 0 + +config ZMK_RGB_UNDERGLOW_SAT_START + int "RGB underglow start saturations value from 0-100" + default 100 + +config ZMK_RGB_UNDERGLOW_BRT_START + int "RGB underglow start brightness value from 0-100" + default 100 + +config ZMK_RGB_UNDERGLOW_SPD_START + int "RGB underglow start animation speed value from 1-5" + default 3 + +config ZMK_RGB_UNDERGLOW_EFF_START + int "RGB underglow start effect int value related to the effect enum list" + default 0 + +config ZMK_RGB_UNDERGLOW_ON_START + bool "Whether RGB underglow starts on by default" + default y + endif endmenu diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 95adcec2..5f557980 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -45,12 +46,39 @@ struct rgb_underglow_state { bool on; }; -struct rgb_underglow_state state; - struct device *led_strip; struct led_rgb pixels[STRIP_NUM_PIXELS]; +struct rgb_underglow_state state; + +static int rgb_settings_set(const char *name, size_t len, + settings_read_cb read_cb, void *cb_arg) +{ + const char *next; + int rc; + + if (settings_name_steq(name, "state", &next) && !next) { + if (len != sizeof(state)) { + return -EINVAL; + } + + rc = read_cb(cb_arg, &state, sizeof(state)); + if (rc >= 0) { + return 0; + } + + return rc; + } + + return -ENOENT; +} + +struct settings_handler rgb_conf = { + .name = "rgb", + .h_set = rgb_settings_set +}; + static struct led_rgb hsb_to_rgb(struct led_hsb hsb) { double r, g, b; @@ -187,20 +215,35 @@ static int zmk_rgb_underglow_init(struct device *_arg) } state = (struct rgb_underglow_state){ - hue: 0, - saturation: 100, - brightness: 100, - animation_speed: 3, - current_effect: 0, + hue: CONFIG_ZMK_RGB_UNDERGLOW_HUE_START, + saturation: CONFIG_ZMK_RGB_UNDERGLOW_SAT_START, + brightness: CONFIG_ZMK_RGB_UNDERGLOW_BRT_START, + animation_speed: CONFIG_ZMK_RGB_UNDERGLOW_SPD_START, + current_effect: CONFIG_ZMK_RGB_UNDERGLOW_EFF_START, animation_step: 0, +#ifdef CONFIG_ZMK_RGB_UNDERGLOW_ON_START on: true +#else + on: false +#endif }; - k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50)); + settings_subsys_init(); + settings_register(&rgb_conf); + settings_load(); + + if (state.on) { + k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50)); + } return 0; } +int zmk_rgb_underglow_save_state() +{ + return settings_save_one("rgb/state", &state, sizeof(state)); +} + int zmk_rgb_underglow_cycle_effect(int direction) { if (!led_strip) return -ENODEV; @@ -218,7 +261,7 @@ int zmk_rgb_underglow_cycle_effect(int direction) state.animation_step = 0; - return 0; + return zmk_rgb_underglow_save_state(); } int zmk_rgb_underglow_toggle() @@ -242,7 +285,7 @@ int zmk_rgb_underglow_toggle() k_timer_stop(&underglow_tick); } - return 0; + return zmk_rgb_underglow_save_state(); } int zmk_rgb_underglow_change_hue(int direction) @@ -250,17 +293,15 @@ int zmk_rgb_underglow_change_hue(int direction) if (!led_strip) return -ENODEV; if (state.hue == 0 && direction < 0) { - state.hue = 350; + state.hue = 360 - CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP; return 0; } state.hue += direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP; - if (state.hue > 350) { - state.hue = 0; - } + state.hue = state.hue % 360; - return 0; + return zmk_rgb_underglow_save_state(); } int zmk_rgb_underglow_change_sat(int direction) @@ -277,7 +318,7 @@ int zmk_rgb_underglow_change_sat(int direction) state.saturation = 100; } - return 0; + return zmk_rgb_underglow_save_state(); } int zmk_rgb_underglow_change_brt(int direction) @@ -294,7 +335,7 @@ int zmk_rgb_underglow_change_brt(int direction) state.brightness = 100; } - return 0; + return zmk_rgb_underglow_save_state(); } int zmk_rgb_underglow_change_spd(int direction) @@ -311,7 +352,7 @@ int zmk_rgb_underglow_change_spd(int direction) state.animation_speed = 5; } - return 0; + return zmk_rgb_underglow_save_state(); } SYS_INIT(zmk_rgb_underglow_init, From bee5f7c350be17f0260004850ac715336a27fc94 Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 20 Aug 2020 21:13:05 -0500 Subject: [PATCH 003/227] fix(rgb): add missing Kconfig docs --- docs/docs/feature/underglow.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/docs/feature/underglow.md b/docs/docs/feature/underglow.md index c6517ced..ab44ebd1 100644 --- a/docs/docs/feature/underglow.md +++ b/docs/docs/feature/underglow.md @@ -35,11 +35,17 @@ If your board or shield does not have RGB underglow configured, refer to [Adding There are various Kconfig options used to configure the RGB underglow feature. These can all be set in the `.conf` file. -| Option | Description | Default | -| ---------------------------- | ---------------------------------------------- | ------- | -| `ZMK_RGB_UNDERGLOW_HUE_STEP` | Hue step in degrees of 360 used by RGB actions | `10` | -| `ZMK_RGB_UNDERGLOW_SAT_STEP` | Saturation step in percent used by RGB actions | `10` | -| `ZMK_RGB_UNDERGLOW_BRT_STEP` | Brightness step in percent used by RGB actions | `10` | +| Option | Description | Default | +|-------------------------------|------------------------------------------------|---------| +| `ZMK_RGB_UNDERGLOW_HUE_STEP` | Hue step in degrees of 360 used by RGB actions | 10 | +| `ZMK_RGB_UNDERGLOW_SAT_STEP` | Saturation step in percent used by RGB actions | 10 | +| `ZMK_RGB_UNDERGLOW_BRT_STEP` | Brightness step in percent used by RGB actions | 10 | +| `ZMK_RGB_UNDERGLOW_HUE_START` | Default hue 0-359 in degrees | 0 | +| `ZMK_RGB_UNDERGLOW_SAT_START` | Default saturation 0-100 in percent | 100 | +| `ZMK_RGB_UNDERGLOW_BRT_START` | Default brightness 0-100 in percent | 100 | +| `ZMK_RGB_UNDERGLOW_SPD_START` | Default effect speed 1-5 | 3 | +| `ZMK_RGB_UNDERGLOW_EFF_START` | Default effect integer from the effect enum | 0 | +| `ZMK_RGB_UNDERGLOW_ON_START` | Default on state | y | ## Adding RGB Underglow to a Board From 74fd4fc997c0cf78cc9acabdd61466fa4857e7ba Mon Sep 17 00:00:00 2001 From: Nick Date: Thu, 20 Aug 2020 21:13:17 -0500 Subject: [PATCH 004/227] fix(rgb): fix underglow settings location --- app/src/rgb_underglow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 5f557980..86223b17 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -75,7 +75,7 @@ static int rgb_settings_set(const char *name, size_t len, } struct settings_handler rgb_conf = { - .name = "rgb", + .name = "rgb/underglow", .h_set = rgb_settings_set }; @@ -241,7 +241,7 @@ static int zmk_rgb_underglow_init(struct device *_arg) int zmk_rgb_underglow_save_state() { - return settings_save_one("rgb/state", &state, sizeof(state)); + return settings_save_one("rgb/underglow/state", &state, sizeof(state)); } int zmk_rgb_underglow_cycle_effect(int direction) From c5c21022a23cae3fecaf17e13d18d7d1ebd5f150 Mon Sep 17 00:00:00 2001 From: Nick Date: Sun, 23 Aug 2020 10:33:19 -0500 Subject: [PATCH 005/227] Move settings load --- app/CMakeLists.txt | 1 + app/src/rgb_underglow.c | 40 ++++++++++++++++++++++------------------ app/src/settings.c | 13 +++++++++++++ 3 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 app/src/settings.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 054f84a7..bb4af555 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -55,4 +55,5 @@ target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) target_sources(app PRIVATE src/endpoints.c) target_sources(app PRIVATE src/hid_listener.c) +target_sources(app PRIVATE src/settings.c) target_sources(app PRIVATE src/main.c) diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 86223b17..3851421b 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -15,7 +15,6 @@ #include #include -#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -106,6 +105,16 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) return rgb; } +static void zmk_rgb_underglow_off() +{ + for (int i=0; i +#include +#include +#include + +static int zmk_settings_init(struct device *_arg) +{ + return settings_load(); +} + +SYS_INIT(zmk_settings_init, + APPLICATION, + CONFIG_APPLICATION_INIT_PRIORITY); From 979a5bffffeac0fed12db00409dedb8ed6c4ad87 Mon Sep 17 00:00:00 2001 From: Nick Date: Sun, 23 Aug 2020 15:56:18 -0500 Subject: [PATCH 006/227] fix(rgb): check if settings enabled --- app/CMakeLists.txt | 2 +- app/src/rgb_underglow.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index bb4af555..bbb54b95 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -55,5 +55,5 @@ target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) target_sources(app PRIVATE src/endpoints.c) target_sources(app PRIVATE src/hid_listener.c) -target_sources(app PRIVATE src/settings.c) +target_sources_ifdef(CONFIG_SETTINGS app PRIVATE src/settings.c) target_sources(app PRIVATE src/main.c) diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 3851421b..cb98e8d9 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -51,6 +51,7 @@ struct led_rgb pixels[STRIP_NUM_PIXELS]; struct rgb_underglow_state state; +#if IS_ENABLED(CONFIG_SETTINGS) static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) { @@ -77,6 +78,7 @@ struct settings_handler rgb_conf = { .name = "rgb/underglow", .h_set = rgb_settings_set }; +#endif static struct led_rgb hsb_to_rgb(struct led_hsb hsb) { @@ -242,7 +244,9 @@ static int zmk_rgb_underglow_init(struct device *_arg) on: IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_ON_START) }; +#if IS_ENABLED(CONFIG_SETTINGS) settings_register(&rgb_conf); +#endif k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50)); @@ -251,7 +255,11 @@ static int zmk_rgb_underglow_init(struct device *_arg) int zmk_rgb_underglow_save_state() { +#if IS_ENABLED(CONFIG_SETTINGS) return settings_save_one("rgb/underglow/state", &state, sizeof(state)); +#else + return 0; +#endif } int zmk_rgb_underglow_cycle_effect(int direction) From 4551d307693dae30802a3f06d5f62fcf3155f8c0 Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 3 Sep 2020 13:20:05 +0100 Subject: [PATCH 007/227] ad cradios --- app/boards/shields/cradios/Kconfig.defconfig | 14 +++++++ app/boards/shields/cradios/Kconfig.shield | 5 +++ app/boards/shields/cradios/cradios.dtsi | 31 +++++++++++++++ app/boards/shields/cradios/cradios.keymap | 17 +++++++++ app/boards/shields/cradios/cradios_left.conf | 2 + .../shields/cradios/cradios_left.overlay | 34 +++++++++++++++++ app/boards/shields/cradios/cradios_right.conf | 2 + .../shields/cradios/cradios_right.overlay | 38 +++++++++++++++++++ app/boards/shields/cradios/default.keymap | 19 ++++++++++ 9 files changed, 162 insertions(+) create mode 100644 app/boards/shields/cradios/Kconfig.defconfig create mode 100644 app/boards/shields/cradios/Kconfig.shield create mode 100644 app/boards/shields/cradios/cradios.dtsi create mode 100644 app/boards/shields/cradios/cradios.keymap create mode 100644 app/boards/shields/cradios/cradios_left.conf create mode 100644 app/boards/shields/cradios/cradios_left.overlay create mode 100644 app/boards/shields/cradios/cradios_right.conf create mode 100644 app/boards/shields/cradios/cradios_right.overlay create mode 100644 app/boards/shields/cradios/default.keymap diff --git a/app/boards/shields/cradios/Kconfig.defconfig b/app/boards/shields/cradios/Kconfig.defconfig new file mode 100644 index 00000000..0aca38fc --- /dev/null +++ b/app/boards/shields/cradios/Kconfig.defconfig @@ -0,0 +1,14 @@ + +if SHIELD_CRADIOS + +config ZMK_KEYBOARD_NAME + default "cradios" + +# Unable to use interrupts as the same pin number is used +# across A & B controllers, and STM32F303CCT6 can't enable +# interrutps for multiple controllers for the same "line" +# for the external interrupts. +config ZMK_KSCAN_GPIO_POLLING + default y + +endif diff --git a/app/boards/shields/cradios/Kconfig.shield b/app/boards/shields/cradios/Kconfig.shield new file mode 100644 index 00000000..844d4332 --- /dev/null +++ b/app/boards/shields/cradios/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_CRADIOS + def_bool $(shields_list_contains,cradios) diff --git a/app/boards/shields/cradios/cradios.dtsi b/app/boards/shields/cradios/cradios.dtsi new file mode 100644 index 00000000..7c20c009 --- /dev/null +++ b/app/boards/shields/cradios/cradios.dtsi @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + #include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; + map = < +RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) +RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) +RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) + RC(3,4) RC(3,5) RC(3,6) RC(3,7) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + }; + + }; diff --git a/app/boards/shields/cradios/cradios.keymap b/app/boards/shields/cradios/cradios.keymap new file mode 100644 index 00000000..29392241 --- /dev/null +++ b/app/boards/shields/cradios/cradios.keymap @@ -0,0 +1,17 @@ +#include +#include + + +/ { + keymap0: keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH + &kp DEL &kp RET &kp RET &SPC + }; + }; +}; diff --git a/app/boards/shields/cradios/cradios_left.conf b/app/boards/shields/cradios/cradios_left.conf new file mode 100644 index 00000000..1e028a78 --- /dev/null +++ b/app/boards/shields/cradios/cradios_left.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y diff --git a/app/boards/shields/cradios/cradios_left.overlay b/app/boards/shields/cradios/cradios_left.overlay new file mode 100644 index 00000000..6f53d8b9 --- /dev/null +++ b/app/boards/shields/cradios/cradios_left.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ +#include "cradios.dtsi" + +kscan_0 { + + input-gpios + = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; + +&bt_unpair_combo { + key-positions = <0 38>; +}; + diff --git a/app/boards/shields/cradios/cradios_right.conf b/app/boards/shields/cradios/cradios_right.conf new file mode 100644 index 00000000..990cf7c0 --- /dev/null +++ b/app/boards/shields/cradios/cradios_right.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL=y diff --git a/app/boards/shields/cradios/cradios_right.overlay b/app/boards/shields/cradios/cradios_right.overlay new file mode 100644 index 00000000..f991ef9c --- /dev/null +++ b/app/boards/shields/cradios/cradios_right.overlay @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ +#include "cradios.dtsi" + +&default_transform { + col-offset = <5>; +}; + + &kscan0 { + input-gpios + + = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; + +&bt_unpair_combo { + key-positions = <0 38>; +}; + diff --git a/app/boards/shields/cradios/default.keymap b/app/boards/shields/cradios/default.keymap new file mode 100644 index 00000000..08210052 --- /dev/null +++ b/app/boards/shields/cradios/default.keymap @@ -0,0 +1,19 @@ +#include +#include + + +/ { + keymap0: keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH + &kp DEL &kp RET &kp RET &kp SPC + + >; + }; + }; +}; From 95bb220702121756a1f7458dcf549bd3c9187216 Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 3 Sep 2020 14:46:54 +0100 Subject: [PATCH 008/227] now compiles, not work, baby steps --- app/boards/shields/cradios/cradios.dtsi | 11 ++++++----- app/boards/shields/cradios/cradios.keymap | 13 +++++++------ app/boards/shields/cradios/cradios_left.overlay | 7 +++---- app/boards/shields/cradios/cradios_right.overlay | 9 +++------ 4 files changed, 19 insertions(+), 21 deletions(-) diff --git a/app/boards/shields/cradios/cradios.dtsi b/app/boards/shields/cradios/cradios.dtsi index 7c20c009..f5ebb962 100644 --- a/app/boards/shields/cradios/cradios.dtsi +++ b/app/boards/shields/cradios/cradios.dtsi @@ -14,18 +14,19 @@ default_transform: keymap_transform_0 { compatible = "zmk,matrix-transform"; - columns = <10>; - rows = <4>; + columns = <34>; + rows = <1>; map = < RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) -RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) -RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) - RC(3,4) RC(3,5) RC(3,6) RC(3,7) +RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) RC(0,16) RC(0,17) RC(0,18) RC(0,19) RC(0,20) +RC(0,21) RC(0,22) RC(0,23) RC(0,24) RC(0,25) RC(0,26) RC(0,27) RC(0,28) RC(0,29) RC(0,30) +RC(0,31) RC(0,32) RC(0,33) RC(0,34) >; }; kscan0: kscan { compatible = "zmk,kscan-gpio-direct"; + label = "KSCAN"; }; }; diff --git a/app/boards/shields/cradios/cradios.keymap b/app/boards/shields/cradios/cradios.keymap index 29392241..3da61b74 100644 --- a/app/boards/shields/cradios/cradios.keymap +++ b/app/boards/shields/cradios/cradios.keymap @@ -3,15 +3,16 @@ / { - keymap0: keymap { - compatible = "zmk,keymap"; + keymap { + compatible = "zmk,keymap"; - default_layer { + default_layer { bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P - &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN - &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH - &kp DEL &kp RET &kp RET &SPC + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH + &kp 3 &kp 4 &kp 2 &kp 1 + >; }; }; }; diff --git a/app/boards/shields/cradios/cradios_left.overlay b/app/boards/shields/cradios/cradios_left.overlay index 6f53d8b9..3c3e9863 100644 --- a/app/boards/shields/cradios/cradios_left.overlay +++ b/app/boards/shields/cradios/cradios_left.overlay @@ -5,7 +5,8 @@ */ #include "cradios.dtsi" -kscan_0 { + +&kscan0 { input-gpios = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> @@ -28,7 +29,5 @@ kscan_0 { ; }; -&bt_unpair_combo { - key-positions = <0 38>; -}; + diff --git a/app/boards/shields/cradios/cradios_right.overlay b/app/boards/shields/cradios/cradios_right.overlay index f991ef9c..7b47924d 100644 --- a/app/boards/shields/cradios/cradios_right.overlay +++ b/app/boards/shields/cradios/cradios_right.overlay @@ -6,12 +6,11 @@ #include "cradios.dtsi" &default_transform { - col-offset = <5>; + col-offset = <17>; }; - &kscan0 { +&kscan0 { input-gpios - = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> @@ -32,7 +31,5 @@ ; }; -&bt_unpair_combo { - key-positions = <0 38>; -}; + From 8bad40282b89859766cd28949b48fe34c24371fe Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 3 Sep 2020 22:02:25 +0100 Subject: [PATCH 009/227] actually working --- app/boards/shields/cradios/Kconfig.defconfig | 4 ++-- app/boards/shields/cradios/cradios.dtsi | 10 +++++----- app/boards/shields/cradios/cradios.keymap | 2 +- app/boards/shields/cradios/cradios_left.overlay | 3 +-- app/boards/shields/cradios/cradios_right.overlay | 5 ++--- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/app/boards/shields/cradios/Kconfig.defconfig b/app/boards/shields/cradios/Kconfig.defconfig index 0aca38fc..5b9ca9a1 100644 --- a/app/boards/shields/cradios/Kconfig.defconfig +++ b/app/boards/shields/cradios/Kconfig.defconfig @@ -1,5 +1,5 @@ -if SHIELD_CRADIOS + config ZMK_KEYBOARD_NAME default "cradios" @@ -11,4 +11,4 @@ config ZMK_KEYBOARD_NAME config ZMK_KSCAN_GPIO_POLLING default y -endif + diff --git a/app/boards/shields/cradios/cradios.dtsi b/app/boards/shields/cradios/cradios.dtsi index f5ebb962..95b4f272 100644 --- a/app/boards/shields/cradios/cradios.dtsi +++ b/app/boards/shields/cradios/cradios.dtsi @@ -17,11 +17,11 @@ columns = <34>; rows = <1>; map = < -RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) -RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15) RC(0,16) RC(0,17) RC(0,18) RC(0,19) RC(0,20) -RC(0,21) RC(0,22) RC(0,23) RC(0,24) RC(0,25) RC(0,26) RC(0,27) RC(0,28) RC(0,29) RC(0,30) -RC(0,31) RC(0,32) RC(0,33) RC(0,34) - >; +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,17) RC(0,18) RC(0,19) RC(0,20) RC(0,21) +RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,22) RC(0,23) RC(0,24) RC(0,25) RC(0,26) +RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,27) RC(0,28) RC(0,29) RC(0,30) RC(0,31) +RC(0,15) RC(0,16) RC(0,32) RC(0,33) +>; }; kscan0: kscan { diff --git a/app/boards/shields/cradios/cradios.keymap b/app/boards/shields/cradios/cradios.keymap index 3da61b74..c46468dd 100644 --- a/app/boards/shields/cradios/cradios.keymap +++ b/app/boards/shields/cradios/cradios.keymap @@ -11,7 +11,7 @@ &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH - &kp 3 &kp 4 &kp 2 &kp 1 + &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 >; }; }; diff --git a/app/boards/shields/cradios/cradios_left.overlay b/app/boards/shields/cradios/cradios_left.overlay index 3c3e9863..ab5a874d 100644 --- a/app/boards/shields/cradios/cradios_left.overlay +++ b/app/boards/shields/cradios/cradios_left.overlay @@ -7,9 +7,8 @@ &kscan0 { - input-gpios - = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> diff --git a/app/boards/shields/cradios/cradios_right.overlay b/app/boards/shields/cradios/cradios_right.overlay index 7b47924d..59a81ba5 100644 --- a/app/boards/shields/cradios/cradios_right.overlay +++ b/app/boards/shields/cradios/cradios_right.overlay @@ -8,10 +8,9 @@ &default_transform { col-offset = <17>; }; - &kscan0 { input-gpios - = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + = <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> @@ -27,7 +26,7 @@ , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> ; }; From bdeb6865e18c211a2d26a1f007711710f489db27 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Sun, 6 Sep 2020 19:55:56 -0700 Subject: [PATCH 010/227] Update sidebars.js --- docs/sidebars.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/sidebars.js b/docs/sidebars.js index 3df183b3..7da0f5bb 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -7,6 +7,7 @@ module.exports = { "user-setup", "customization", "bond-reset", + "troubleshooting" ], Features: [ "feature/keymaps", From cb95b9f11a687cb165adaffdeed866e80c7fdc7b Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Sun, 6 Sep 2020 20:03:33 -0700 Subject: [PATCH 011/227] Restored Troubleshooting.md and associated files --- .../troubleshooting/keymaps/errorscreen.png | Bin 0 -> 186351 bytes .../troubleshooting/keymaps/healthyEDIT.png | Bin 0 -> 188078 bytes .../troubleshooting/keymaps/unhealthyEDIT.png | Bin 0 -> 187729 bytes docs/docs/behavior/key-press.md | 7 +++- docs/docs/troubleshooting.md | 33 ++++++++++++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 docs/docs/assets/troubleshooting/keymaps/errorscreen.png create mode 100644 docs/docs/assets/troubleshooting/keymaps/healthyEDIT.png create mode 100644 docs/docs/assets/troubleshooting/keymaps/unhealthyEDIT.png create mode 100644 docs/docs/troubleshooting.md diff --git a/docs/docs/assets/troubleshooting/keymaps/errorscreen.png b/docs/docs/assets/troubleshooting/keymaps/errorscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..73b5b58487eb96ac22651edbf0fb9f90ca198eb9 GIT binary patch literal 186351 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�oN3TeHS02;_erTgMa_v{ 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 z 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�Ji0$nC~tz*fHIHQloRKRkvR*xT068 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

$U= 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 literal 0 HcmV?d00001 diff --git a/docs/docs/assets/troubleshooting/keymaps/unhealthyEDIT.png b/docs/docs/assets/troubleshooting/keymaps/unhealthyEDIT.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd8dc70fb1f79085f8ce70ac6627f151aa6b92c GIT binary patch literal 187729 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 QAGq+#m7jBUZ~pqf0FSe~%K!iX literal 0 HcmV?d00001 diff --git a/docs/docs/behavior/key-press.md b/docs/docs/behavior/key-press.md index f58225d7..d427f9d2 100644 --- a/docs/docs/behavior/key-press.md +++ b/docs/docs/behavior/key-press.md @@ -27,6 +27,11 @@ There is an [open issue](https://github.com/zmkfirmware/zmk/issues/21) to provid complete set of defines for the full keypad and consumer usage pages in the future for ZMK. ::: +### Improperly defined keymap - `dtlib.DTError: .dts.pre.tmp:` + +When compiling firmware from a keymap, it may be common to encounter an error in the form of a`dtlib.DTError: .dts.pre.tmp:`. +For instructions to resolve such an error, click [here](../troubleshooting###Improperly-defined-keymap) + ## Keypad Key Press The "keypad key press" behavior sends standard keypad keycodes on press/release. @@ -59,4 +64,4 @@ Example: ``` &cp M_PREV -``` +``` \ No newline at end of file diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md new file mode 100644 index 00000000..cecee25d --- /dev/null +++ b/docs/docs/troubleshooting.md @@ -0,0 +1,33 @@ +--- +id: troubleshooting +title: Troubleshooting +sidebar_title: Troubleshooting +--- +### Summary + +The following page provides suggestions for common errors that may occur during firmware compilation. If the information provided is insufficient to resolve the issue, feel free to seek out help from the [ZMK Discord](https://zmkfirmware.dev/community/discord/invite). + +### Environment Variables not Defined + +An error along the lines of `CMake Error at (zmk directory)/zephyr/cmake/generic_toolchain.cmake:64 (include): include could not find load file:` during firmware compilation indicates that the Zephyr Environment Variables are not properly defined. +For more information, click [here](../docs/dev-setup#environment-variables). + +### Improperly defined keymap + +An error along the lines of `dtlib.DTError: .dts.pre.tmp:` during firmware compilation indicates an issue within the `.keymap` file. +This can be verified by checking the file in question, found in `mkdir/app/build`. + +| ![Example Error Screen](../docs/assets/troubleshooting/keymaps/errorscreen.png) | +| :-------------------------------------------------------------------------------: | +| An example of the dtlib.DTError when compiling an iris with the nice!nano while the keymap is not properly defined | + +After opening the `.dts.pre.tmp:` and scrolling down to the referenced line, one can locate errors within their shield's keymap by checking if the referenced keycodes were properly converted into the correct [USB HID Usage ID](https://www.usb.org/document-library/hid-usage-tables-12). + +| ![Unhealthy Keymap Temp](../docs/assets/troubleshooting/keymaps/unhealthyEDIT.png) | +| :-------------------------------------------------------------------------------: | +| An incorrectly defined keymap unable to compile. As shown in red, `&kp SPAC` is not a valid +reference to the [USB HID Usage ID](https://www.usb.org/document-library/hid-usage-tables-12) used for "Keyboard Spacebar" | + +| ![Healthy Keymap Temp](../docs/assets/troubleshooting/keymaps/healthyEDIT.png) | +| :-------------------------------------------------------------------------------: | +| A properly defined keymap with successful compilation. As shown in red, the corrected keycode (`&kp SPC`) references the proper Usage ID defined in the [USB HID Usage Tables](https://www.usb.org/document-library/hid-usage-tables-12)| \ No newline at end of file From 336cae9d0fd0aa84a30768f2629bbbf357e8cdaa Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Sun, 6 Sep 2020 20:13:45 -0700 Subject: [PATCH 012/227] Adjusted lines to fix caption format --- docs/docs/troubleshooting.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index cecee25d..61c6e79f 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -24,9 +24,8 @@ This can be verified by checking the file in question, found in `mkdir/app/build After opening the `.dts.pre.tmp:` and scrolling down to the referenced line, one can locate errors within their shield's keymap by checking if the referenced keycodes were properly converted into the correct [USB HID Usage ID](https://www.usb.org/document-library/hid-usage-tables-12). | ![Unhealthy Keymap Temp](../docs/assets/troubleshooting/keymaps/unhealthyEDIT.png) | -| :-------------------------------------------------------------------------------: | -| An incorrectly defined keymap unable to compile. As shown in red, `&kp SPAC` is not a valid -reference to the [USB HID Usage ID](https://www.usb.org/document-library/hid-usage-tables-12) used for "Keyboard Spacebar" | +| :-------------------------------------------------------------------------------: | +| An incorrectly defined keymap unable to compile. As shown in red, `&kp SPAC` is not a valid reference to the [USB HID Usage ID](https://www.usb.org/document-library/hid-usage-tables-12) used for "Keyboard Spacebar" | | ![Healthy Keymap Temp](../docs/assets/troubleshooting/keymaps/healthyEDIT.png) | | :-------------------------------------------------------------------------------: | From 618c537be14e3bf8ba0515784078df1b42c60915 Mon Sep 17 00:00:00 2001 From: Kurtis Lew Date: Sun, 6 Sep 2020 20:45:28 -0700 Subject: [PATCH 013/227] Updated Headers --- docs/docs/troubleshooting.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index 61c6e79f..cd8bfd64 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -7,12 +7,12 @@ sidebar_title: Troubleshooting The following page provides suggestions for common errors that may occur during firmware compilation. If the information provided is insufficient to resolve the issue, feel free to seek out help from the [ZMK Discord](https://zmkfirmware.dev/community/discord/invite). -### Environment Variables not Defined +### CMake Error An error along the lines of `CMake Error at (zmk directory)/zephyr/cmake/generic_toolchain.cmake:64 (include): include could not find load file:` during firmware compilation indicates that the Zephyr Environment Variables are not properly defined. For more information, click [here](../docs/dev-setup#environment-variables). -### Improperly defined keymap +### dtlib.DTError An error along the lines of `dtlib.DTError: .dts.pre.tmp:` during firmware compilation indicates an issue within the `.keymap` file. This can be verified by checking the file in question, found in `mkdir/app/build`. @@ -29,4 +29,4 @@ After opening the `.dts.pre.tmp:` and scrolling down to the | ![Healthy Keymap Temp](../docs/assets/troubleshooting/keymaps/healthyEDIT.png) | | :-------------------------------------------------------------------------------: | -| A properly defined keymap with successful compilation. As shown in red, the corrected keycode (`&kp SPC`) references the proper Usage ID defined in the [USB HID Usage Tables](https://www.usb.org/document-library/hid-usage-tables-12)| \ No newline at end of file +| A properly defined keymap with successful compilation. As shown in red, the corrected keycode (`&kp SPC`) references the proper Usage ID defined in the [USB HID Usage Tables](https://www.usb.org/document-library/hid-usage-tables-12)| From 6b433fdefd0793e836574f528445b7d4b6d781bc Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 7 Sep 2020 12:24:47 -0500 Subject: [PATCH 014/227] Finish DZ60RGB board definition --- app/boards/arm/dz60rgb/CMakeLists.txt | 2 -- app/boards/arm/dz60rgb/board.cmake | 3 +- app/boards/arm/dz60rgb/dz60rgb_rev1.dts | 5 +-- .../keymap.overlay => dz60rgb_rev1.keymap} | 18 ++--------- app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig | 3 -- app/boards/arm/dz60rgb/pinmux.c | 32 +++++++++---------- 6 files changed, 24 insertions(+), 39 deletions(-) rename app/boards/arm/dz60rgb/{keymap/keymap.overlay => dz60rgb_rev1.keymap} (85%) diff --git a/app/boards/arm/dz60rgb/CMakeLists.txt b/app/boards/arm/dz60rgb/CMakeLists.txt index 6a0ec73e..940af1fe 100644 --- a/app/boards/arm/dz60rgb/CMakeLists.txt +++ b/app/boards/arm/dz60rgb/CMakeLists.txt @@ -1,7 +1,5 @@ # SPDX-License-Identifier: MIT -list(APPEND EXTRA_DTC_FLAGS "-qq") - if(CONFIG_PINMUX) zephyr_library() zephyr_library_sources(pinmux.c) diff --git a/app/boards/arm/dz60rgb/board.cmake b/app/boards/arm/dz60rgb/board.cmake index 4843c415..10f6e291 100644 --- a/app/boards/arm/dz60rgb/board.cmake +++ b/app/boards/arm/dz60rgb/board.cmake @@ -1,6 +1,7 @@ # SPDX-License-Identifier: MIT -board_runner_args(jlink "--device=STM32F303VC" "--speed=4000") +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") +board_runner_args(jlink "--device=STM32F303CC" "--speed=4000") include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts index 8066b5ad..dc1b6ea5 100644 --- a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts @@ -17,6 +17,7 @@ zephyr,sram = &sram0; zephyr,flash = &flash0; zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; }; default_transform: keymap_transform_0 { @@ -28,7 +29,7 @@ RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) 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,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,13) RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,13) -RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,13) +RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4,8) RC(4,9) RC(4,10) RC(4,11) RC(4,13) >; }; @@ -55,7 +56,7 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,5) RC(4 , <&gpiob 3 GPIO_ACTIVE_HIGH> , <&gpiob 4 GPIO_ACTIVE_HIGH> , <&gpiob 5 GPIO_ACTIVE_HIGH> - , <&gpiob 6 GPIO_ACTIVE_HIGH> + , <&gpiob 8 GPIO_ACTIVE_HIGH> , <&gpiob 9 GPIO_ACTIVE_HIGH> , <&gpioc 13 GPIO_ACTIVE_HIGH> , <&gpioc 14 GPIO_ACTIVE_HIGH> diff --git a/app/boards/arm/dz60rgb/keymap/keymap.overlay b/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap similarity index 85% rename from app/boards/arm/dz60rgb/keymap/keymap.overlay rename to app/boards/arm/dz60rgb/dz60rgb_rev1.keymap index 9d83adcf..8de01c17 100644 --- a/app/boards/arm/dz60rgb/keymap/keymap.overlay +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.keymap @@ -1,23 +1,11 @@ #include #include -#include / { - chosen { - zmk,keymap = &keymap0; - }; - - keymap0: keymap { + keymap { compatible = "zmk,keymap"; - label ="Default DZ60RGB Keymap"; - layers = <&default>; - }; - layers { - compatible = "zmk,layers"; - - default: layer_0 { - label = "DEFAULT"; + default_layer { // ------------------------------------------------------------------------------------------ // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | // | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | @@ -34,4 +22,4 @@ >; }; }; -}; +}; \ No newline at end of file diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig index 5a4c0995..33840f96 100644 --- a/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1_defconfig @@ -19,9 +19,6 @@ CONFIG_CLOCK_STM32_HSE_CLOCK=8000000 CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL=y # use HSE as PLL input CONFIG_CLOCK_STM32_PLL_SRC_HSE=y -# however, the board does not have an external oscillator, so just use -# the 8MHz clock signal coming from integrated STLink -CONFIG_CLOCK_STM32_HSE_BYPASS=y # produce 72MHz clock at PLL output CONFIG_CLOCK_STM32_PLL_PREDIV=1 CONFIG_CLOCK_STM32_PLL_MULTIPLIER=9 diff --git a/app/boards/arm/dz60rgb/pinmux.c b/app/boards/arm/dz60rgb/pinmux.c index 5df5c90e..60e231b6 100644 --- a/app/boards/arm/dz60rgb/pinmux.c +++ b/app/boards/arm/dz60rgb/pinmux.c @@ -14,46 +14,46 @@ /* pin assignments for STM32F3DISCOVERY board */ static const struct pin_config pinconf[] = { -#ifdef CONFIG_UART_1 +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usart1), okay) && CONFIG_SERIAL {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, -#endif /* CONFIG_UART_1 */ -#ifdef CONFIG_UART_2 +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usart2), okay) && CONFIG_SERIAL {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, -#endif /* CONFIG_UART_2 */ -#ifdef CONFIG_I2C_1 +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c1), okay) && CONFIG_I2C {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, -#endif /* CONFIG_I2C_1 */ -#ifdef CONFIG_I2C_2 +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c2), okay) && CONFIG_I2C {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, -#endif /* CONFIG_I2C_2 */ -#ifdef CONFIG_SPI_1 +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(spi1), okay) && CONFIG_SPI #ifdef CONFIG_SPI_STM32_USE_HW_SS {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, -#endif /* CONFIG_SPI_1 */ -#ifdef CONFIG_SPI_2 +#endif +#if DT_NODE_HAS_STATUS(DT_NODELABEL(spi2), okay) && CONFIG_SPI #ifdef CONFIG_SPI_STM32_USE_HW_SS {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, -#endif /* CONFIG_SPI_2 */ +#endif #ifdef CONFIG_USB_DC_STM32 {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, -#endif /* CONFIG_USB_DC_STM32 */ -#ifdef CONFIG_CAN_1 +#endif /* CONFIG_USB_DC_STM32 */ +#if DT_NODE_HAS_STATUS(DT_NODELABEL(can1), okay) && CONFIG_CAN {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, -#endif /* CONFIG_CAN_1 */ +#endif }; static int pinmux_stm32_init(struct device *port) @@ -66,4 +66,4 @@ static int pinmux_stm32_init(struct device *port) } SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, - CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); + CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); \ No newline at end of file From e845995c2d5ea90327e68495569f7d1a25242ee2 Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 7 Sep 2020 12:25:11 -0500 Subject: [PATCH 015/227] Fix Planck defconfig --- app/boards/arm/planck/planck_rev6_defconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/boards/arm/planck/planck_rev6_defconfig b/app/boards/arm/planck/planck_rev6_defconfig index a440ff17..e34ce002 100644 --- a/app/boards/arm/planck/planck_rev6_defconfig +++ b/app/boards/arm/planck/planck_rev6_defconfig @@ -20,9 +20,6 @@ CONFIG_CLOCK_STM32_HSE_CLOCK=8000000 CONFIG_CLOCK_STM32_SYSCLK_SRC_PLL=y # use HSE as PLL input CONFIG_CLOCK_STM32_PLL_SRC_HSE=y -# however, the board does not have an external oscillator, so just use -# the 8MHz clock signal coming from integrated STLink -CONFIG_CLOCK_STM32_HSE_BYPASS=y # produce 72MHz clock at PLL output CONFIG_CLOCK_STM32_PLL_PREDIV=1 CONFIG_CLOCK_STM32_PLL_MULTIPLIER=9 From ceda57ddfd7b49dd61e8795c37cd678b69a4a76f Mon Sep 17 00:00:00 2001 From: Nick Date: Mon, 7 Sep 2020 12:32:25 -0500 Subject: [PATCH 016/227] Fix comment name of keyboard --- app/boards/arm/dz60rgb/Kconfig.defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/boards/arm/dz60rgb/Kconfig.defconfig b/app/boards/arm/dz60rgb/Kconfig.defconfig index cfa71d3f..c97a3085 100644 --- a/app/boards/arm/dz60rgb/Kconfig.defconfig +++ b/app/boards/arm/dz60rgb/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Planck keyboard configuration +# DZ60RGB keyboard configuration # Copyright (c) 2020 Nick Winans # SPDX-License-Identifier: MIT From a65de800bf8779191c6b0e6ef17f12d1559389e1 Mon Sep 17 00:00:00 2001 From: Cody McGinnis Date: Tue, 8 Sep 2020 12:00:46 -0400 Subject: [PATCH 017/227] fix(tests): pending tests pass now --- app/tests/momentary-layer/early-key-release/pending | 0 app/tests/toggle-layer/early-key-release/pending | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/tests/momentary-layer/early-key-release/pending delete mode 100644 app/tests/toggle-layer/early-key-release/pending diff --git a/app/tests/momentary-layer/early-key-release/pending b/app/tests/momentary-layer/early-key-release/pending deleted file mode 100644 index e69de29b..00000000 diff --git a/app/tests/toggle-layer/early-key-release/pending b/app/tests/toggle-layer/early-key-release/pending deleted file mode 100644 index e69de29b..00000000 From df2da813f1f50dbd20ef226a439208fbf5d23c17 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 8 Sep 2020 16:08:09 -0400 Subject: [PATCH 018/227] fix(docs): Remove broken Discord invite links. --- docs/docs/faq.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/faq.md b/docs/docs/faq.md index 2ab158d3..d8bbd713 100644 --- a/docs/docs/faq.md +++ b/docs/docs/faq.md @@ -76,7 +76,7 @@ Please note, many keyboards only have a single PCB which includes the “brains ### What bootloader does ZMK use? -ZMK isn’t designed for any particular bootloader, and supports flashing different boards with different flash utilities (e.g. OpenOCD, nrfjprog, etc.). So if you have any difficulties, please let us know on [Discord](https://discord.gg/VJnx9kr)! +ZMK isn’t designed for any particular bootloader, and supports flashing different boards with different flash utilities (e.g. OpenOCD, nrfjprog, etc.). So if you have any difficulties, please let us know on [Discord](https://zmkfirmware.dev/community/discord/invite)! ### Can I contribute? @@ -84,11 +84,11 @@ Of course! Please use the developer [documentation](/docs) to get started! ### I have an idea! What should I do? -Please join us on [Discord](https://discord.gg/VJnx9kr) and discuss it with us! +Please join us on [Discord](https://zmkfirmware.dev/community/discord/invite) and discuss it with us! ### I want to add a new keyboard! What should I do? -The exact process for the management of all the possible hardware is still being finalized, but any developer looking to contribute new keyboard definitions should chat with us on [Discord](https://discord.gg/VJnx9kr) to get started. +The exact process for the management of all the possible hardware is still being finalized, but any developer looking to contribute new keyboard definitions should chat with us on [Discord](https://zmkfirmware.dev/community/discord/invite) to get started. ### Does ZMK have a Code of Conduct? From 6456fab8e0278d3cd5b73ef4ddca49845c00c19d Mon Sep 17 00:00:00 2001 From: Alexander Elias Date: Wed, 9 Sep 2020 09:14:01 -0700 Subject: [PATCH 019/227] Should this be org instead of com? --- docs/docs/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 29045f76..50a747cf 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -5,7 +5,7 @@ sidebar_label: Introduction --- ZMK Firmware is an open source (MIT) keyboard -firmware built on the [Zephyr™ Project](https://zephyrproject.com/) Real Time Operating System (RTOS). +firmware built on the [Zephyr™ Project](https://zephyrproject.org/) Real Time Operating System (RTOS). The goal is to provider a powerful, featureful keyboard firmware that is free of licensing issues that prevent upstream BLE support as a first-class From 6a0e85ea726ac49bb95bdfd1c7770f7da826bf1a Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Thu, 10 Sep 2020 09:54:22 +0530 Subject: [PATCH 020/227] labelled image to be added --- docs/docs/pro-micro-labelled-image.jpg | Bin 0 -> 115573 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/docs/pro-micro-labelled-image.jpg diff --git a/docs/docs/pro-micro-labelled-image.jpg b/docs/docs/pro-micro-labelled-image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f72d407719e9ff4d20ed45d93d12dead8caa9da5 GIT binary patch literal 115573 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 DB^7&W literal 0 HcmV?d00001 From 82ddf81fcb4f1f5e629fe2c2dd0c8c0ba803964f Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Thu, 10 Sep 2020 09:59:33 +0530 Subject: [PATCH 021/227] Update dev-guide-new-shield.md --- docs/docs/dev-guide-new-shield.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index bc5175bf..8aa62dac 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -64,6 +64,8 @@ endif ## Shield Overlay +![Labelled Pro Micro Image](pro-micro-labelled-image.jpg) + The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, this might look something like: From d02fc07c4f53868cc0b498cdc2fb6b0768cbe8cb Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Thu, 10 Sep 2020 10:02:25 +0530 Subject: [PATCH 022/227] Update dev-boards-shields-keymaps.md --- docs/docs/dev-boards-shields-keymaps.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/dev-boards-shields-keymaps.md b/docs/docs/dev-boards-shields-keymaps.md index cfe52526..9810558b 100644 --- a/docs/docs/dev-boards-shields-keymaps.md +++ b/docs/docs/dev-boards-shields-keymaps.md @@ -35,6 +35,8 @@ in the `app/boards/${arch}/${board_name}` directory, e.g. `app/boards/arm/planck ## Pro Micro Compatible Keyboard +![Labelled Pro Micro Image](pro-micro-labelled-image.jpg) + For keyboards that require a (usually Pro Micro compatible) add-on board to operate, the ZMK integration pieces are places in the _shield_ definition for that keyboard, allowing users to swap in different Pro Micro compatible boards (e.g. Proton-C, or nice!nano) and build a firmware the matches their actual From 3c9f58f9d40d21f5c0bec20b6da75e135503af0a Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Thu, 10 Sep 2020 10:03:48 +0530 Subject: [PATCH 023/227] Update dev-boards-shields-keymaps.md --- docs/docs/dev-boards-shields-keymaps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-boards-shields-keymaps.md b/docs/docs/dev-boards-shields-keymaps.md index 9810558b..17a38473 100644 --- a/docs/docs/dev-boards-shields-keymaps.md +++ b/docs/docs/dev-boards-shields-keymaps.md @@ -35,7 +35,7 @@ in the `app/boards/${arch}/${board_name}` directory, e.g. `app/boards/arm/planck ## Pro Micro Compatible Keyboard -![Labelled Pro Micro Image](pro-micro-labelled-image.jpg) +![Labelled Pro Micro pins](pro-micro-labelled-image.jpg) For keyboards that require a (usually Pro Micro compatible) add-on board to operate, the ZMK integration pieces are places in the _shield_ definition for that keyboard, allowing users to From 92b3ea8a6b75764acab216470050c8138acf2643 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Thu, 10 Sep 2020 10:04:15 +0530 Subject: [PATCH 024/227] Update dev-guide-new-shield.md --- docs/docs/dev-guide-new-shield.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 8aa62dac..23d2387d 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -64,7 +64,7 @@ endif ## Shield Overlay -![Labelled Pro Micro Image](pro-micro-labelled-image.jpg) +![Labelled Pro Micro pins](pro-micro-labelled-image.jpg) The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, this might look something like: From 68e72f9275401c3cb7541259c692a704cbfc5e82 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Wed, 9 Sep 2020 23:57:44 -0400 Subject: [PATCH 025/227] fix: Switch to single AUTHORS file.* Closes #164 --- AUTHORS | 11 +++++++++++ app/boards/arm/dz60rgb/Kconfig.board | 2 +- app/boards/arm/dz60rgb/Kconfig.defconfig | 2 +- app/boards/arm/dz60rgb/dz60rgb_rev1.dts | 2 +- app/boards/arm/nrfmicro/Kconfig.board | 2 +- app/boards/arm/nrfmicro/Kconfig.defconfig | 2 +- app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi | 2 +- .../arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi | 2 +- app/boards/arm/nrfmicro/nrfmicro_11.dts | 2 +- app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts | 2 +- app/boards/arm/nrfmicro/nrfmicro_13.dts | 2 +- app/boards/arm/nrfmicro/pinmux.c | 2 +- app/boards/arm/planck/Kconfig.board | 2 +- app/boards/arm/planck/Kconfig.defconfig | 2 +- app/drivers/zephyr/ec11.c | 2 +- app/drivers/zephyr/ec11.h | 2 +- app/drivers/zephyr/ec11_trigger.c | 2 +- app/drivers/zephyr/kscan_gpio_direct.c | 2 +- app/drivers/zephyr/kscan_gpio_matrix.c | 2 +- app/dts/behaviors/toggle_layer.dtsi | 6 +++--- app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml | 10 +++++----- .../behaviors/zmk,behavior-rgb-underglow.yaml | 4 ++-- .../bindings/behaviors/zmk,behavior-toggle-layer.yaml | 2 +- app/include/drivers/behavior.h | 2 +- app/include/dt-bindings/zmk/reset.h | 2 +- app/include/linker/zmk-events.ld | 2 +- app/include/zmk/behavior.h | 5 +++++ app/include/zmk/ble.h | 5 +++++ app/include/zmk/display.h | 2 +- app/include/zmk/endpoints.h | 6 ++++++ app/include/zmk/event-manager.h | 2 +- app/include/zmk/events/keycode-state-changed.h | 2 +- app/include/zmk/events/modifiers-state-changed.h | 2 +- app/include/zmk/events/position-state-changed.h | 2 +- app/include/zmk/events/sensor-event.h | 2 +- app/include/zmk/handlers.h | 6 ++++++ app/include/zmk/hid.h | 6 ++++++ app/include/zmk/hog.h | 5 +++++ app/include/zmk/keymap.h | 6 ++++++ app/include/zmk/keys.h | 6 ++++++ app/include/zmk/kscan.h | 6 ++++++ app/include/zmk/matrix.h | 6 ++++++ app/include/zmk/matrix_transform.h | 6 ++++++ app/include/zmk/rgb_underglow.h | 2 +- app/include/zmk/sensors.h | 2 +- app/include/zmk/usb_hid.h | 11 +++++++---- app/run-test.sh | 2 +- app/src/behaviors/behavior_hold_tap.c | 2 +- app/src/behaviors/behavior_key_press.c | 2 +- app/src/behaviors/behavior_momentary_layer.c | 2 +- app/src/behaviors/behavior_none.c | 2 +- app/src/behaviors/behavior_reset.c | 2 +- app/src/behaviors/behavior_rgb_underglow.c | 2 +- app/src/behaviors/behavior_sensor_rotate_key_press.c | 2 +- app/src/behaviors/behavior_toggle_layer.c | 2 +- app/src/behaviors/behavior_transparent.c | 2 +- app/src/ble.c | 2 +- app/src/ble_unpair_combo.c | 2 +- app/src/display.c | 2 +- app/src/endpoints.c | 5 +++++ app/src/event_manager.c | 2 +- app/src/events/keycode_state_changed.c | 2 +- app/src/events/modifiers_state_changed.c | 2 +- app/src/events/position_state_changed.c | 2 +- app/src/events/sensor_event.c | 2 +- app/src/hid.c | 6 ++++++ app/src/hid_listener.c | 2 +- app/src/hog.c | 6 ++++++ app/src/keymap.c | 5 +++++ app/src/kscan.c | 2 +- app/src/kscan_composite.c | 2 +- app/src/kscan_mock.c | 2 +- app/src/main.c | 2 +- app/src/matrix_transform.c | 5 +++++ app/src/rgb_underglow.c | 2 +- app/src/sensors.c | 2 +- app/src/split/bluetooth/central.c | 2 +- app/src/split/bluetooth/service.c | 5 +++++ app/src/split_listener.c | 2 +- app/src/usb_hid.c | 5 +++++ 80 files changed, 185 insertions(+), 71 deletions(-) create mode 100644 AUTHORS diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..8052fd95 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,11 @@ +# The ZMK Project consists of many contributors. This file includes individuals +# who have contributed significant changes to the project. To be added to here, +# please submit a PR to the project repo. +Peter Johanson (@petejohanson) +Innovaker (@innovaker) +Nick Winans (@Nicell) +Okke Formsma (@okke-formsma) +Cody McGinnis (@BrainWart) +Kurtis Lew (@kurtis-lew) +Richard Jones (@bmcgavin) +Kevin Chen (@chenkevinh) \ No newline at end of file diff --git a/app/boards/arm/dz60rgb/Kconfig.board b/app/boards/arm/dz60rgb/Kconfig.board index a96271f0..ec8dad68 100644 --- a/app/boards/arm/dz60rgb/Kconfig.board +++ b/app/boards/arm/dz60rgb/Kconfig.board @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Nick Winans +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT config BOARD_DZ60RGB_REV1 diff --git a/app/boards/arm/dz60rgb/Kconfig.defconfig b/app/boards/arm/dz60rgb/Kconfig.defconfig index c97a3085..779d3123 100644 --- a/app/boards/arm/dz60rgb/Kconfig.defconfig +++ b/app/boards/arm/dz60rgb/Kconfig.defconfig @@ -1,6 +1,6 @@ # DZ60RGB keyboard configuration -# Copyright (c) 2020 Nick Winans +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT if BOARD_DZ60RGB_REV1 diff --git a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts index dc1b6ea5..85c4ca56 100644 --- a/app/boards/arm/dz60rgb/dz60rgb_rev1.dts +++ b/app/boards/arm/dz60rgb/dz60rgb_rev1.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Nick Winans + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/arm/nrfmicro/Kconfig.board b/app/boards/arm/nrfmicro/Kconfig.board index 177373ab..36b2d55e 100644 --- a/app/boards/arm/nrfmicro/Kconfig.board +++ b/app/boards/arm/nrfmicro/Kconfig.board @@ -1,6 +1,6 @@ # nrfmicro board configuration -# Copyright (c) 2020 Okke Formsma, joric +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT config BOARD_NRFMICRO_11 diff --git a/app/boards/arm/nrfmicro/Kconfig.defconfig b/app/boards/arm/nrfmicro/Kconfig.defconfig index 9cce5a9b..7957b4a5 100644 --- a/app/boards/arm/nrfmicro/Kconfig.defconfig +++ b/app/boards/arm/nrfmicro/Kconfig.defconfig @@ -1,6 +1,6 @@ # Electronut Labs Papyr board configuration -# Copyright (c) 2020 Okke Formsma, joric +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT if BOARD_NRFMICRO_11 || BOARD_NRFMICRO_11_FLIPPED || BOARD_NRFMICRO_13 diff --git a/app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi b/app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi index 6cde2b49..558391dd 100644 --- a/app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi +++ b/app/boards/arm/nrfmicro/arduino_pro_micro_pins.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Okke Formsma, joric + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi b/app/boards/arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi index 9bad7f4a..68ca266d 100644 --- a/app/boards/arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi +++ b/app/boards/arm/nrfmicro/arduino_pro_micro_pins_flipped.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Okke Formsma, joric + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.dts b/app/boards/arm/nrfmicro/nrfmicro_11.dts index dc07ac89..95bd8adc 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_11.dts +++ b/app/boards/arm/nrfmicro/nrfmicro_11.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Okke Formsma, joric + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts index 5bf493f0..85693a8b 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts +++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Okke Formsma, joric + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/arm/nrfmicro/nrfmicro_13.dts b/app/boards/arm/nrfmicro/nrfmicro_13.dts index dc07ac89..95bd8adc 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_13.dts +++ b/app/boards/arm/nrfmicro/nrfmicro_13.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Okke Formsma, joric + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/arm/nrfmicro/pinmux.c b/app/boards/arm/nrfmicro/pinmux.c index 3792b597..0536fe0d 100644 --- a/app/boards/arm/nrfmicro/pinmux.c +++ b/app/boards/arm/nrfmicro/pinmux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Okke Formsma, joric + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/arm/planck/Kconfig.board b/app/boards/arm/planck/Kconfig.board index 09524489..fe15e1a9 100644 --- a/app/boards/arm/planck/Kconfig.board +++ b/app/boards/arm/planck/Kconfig.board @@ -1,6 +1,6 @@ # Planck V6 board configuration -# Copyright (c) 2020 Peter Johanson +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT config BOARD_PLANCK_REV6 diff --git a/app/boards/arm/planck/Kconfig.defconfig b/app/boards/arm/planck/Kconfig.defconfig index 93118d4f..6f5bf525 100644 --- a/app/boards/arm/planck/Kconfig.defconfig +++ b/app/boards/arm/planck/Kconfig.defconfig @@ -1,6 +1,6 @@ # Planck keyboard configuration -# Copyright (c) 2020 Peter Johanson +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT if BOARD_PLANCK_REV6 diff --git a/app/drivers/zephyr/ec11.c b/app/drivers/zephyr/ec11.c index 1bc5d6a6..dfa86efd 100644 --- a/app/drivers/zephyr/ec11.c +++ b/app/drivers/zephyr/ec11.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/drivers/zephyr/ec11.h b/app/drivers/zephyr/ec11.h index 823d92d8..27fed9bd 100644 --- a/app/drivers/zephyr/ec11.h +++ b/app/drivers/zephyr/ec11.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/drivers/zephyr/ec11_trigger.c b/app/drivers/zephyr/ec11_trigger.c index 709d1fbf..a04a5610 100644 --- a/app/drivers/zephyr/ec11_trigger.c +++ b/app/drivers/zephyr/ec11_trigger.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016 Intel Corporation + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c index a3aa8c46..6e6a01f3 100644 --- a/app/drivers/zephyr/kscan_gpio_direct.c +++ b/app/drivers/zephyr/kscan_gpio_direct.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index b19c4922..079a8309 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/dts/behaviors/toggle_layer.dtsi b/app/dts/behaviors/toggle_layer.dtsi index 86a050d9..40453962 100644 --- a/app/dts/behaviors/toggle_layer.dtsi +++ b/app/dts/behaviors/toggle_layer.dtsi @@ -1,10 +1,10 @@ /* - * Copyright (c) 2020 Cody McGinnis + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ - - / { + +/ { behaviors { tog: behavior_toggle_layer { compatible = "zmk,behavior-toggle-layer"; diff --git a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml index a20578fa..5f74e9ad 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-hold-tap.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2020, Cody McGinnis; Okke Formsma +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT description: Hold or Tap behavior @@ -12,12 +12,12 @@ properties: type: phandles required: true tapping_term_ms: - type: int + type: int flavor: type: string required: false default: "hold-preferred" enum: - - "hold-preferred" - - "balanced" - - "tap-preferred" \ No newline at end of file + - "hold-preferred" + - "balanced" + - "tap-preferred" diff --git a/app/dts/bindings/behaviors/zmk,behavior-rgb-underglow.yaml b/app/dts/bindings/behaviors/zmk,behavior-rgb-underglow.yaml index 6b6d5b00..2cb74b9c 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-rgb-underglow.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-rgb-underglow.yaml @@ -1,8 +1,8 @@ -# Copyright (c) 2020, Nick Winans +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT description: RGB Underglow Action compatible: "zmk,behavior-rgb-underglow" -include: one_param.yaml \ No newline at end of file +include: one_param.yaml diff --git a/app/dts/bindings/behaviors/zmk,behavior-toggle-layer.yaml b/app/dts/bindings/behaviors/zmk,behavior-toggle-layer.yaml index 065949fe..0a9723f7 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-toggle-layer.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-toggle-layer.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2020, Cody McGinnis +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT description: Toggle Layer diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index c24d11b3..617b5ab5 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/dt-bindings/zmk/reset.h b/app/include/dt-bindings/zmk/reset.h index b5136492..683f9658 100644 --- a/app/include/dt-bindings/zmk/reset.h +++ b/app/include/dt-bindings/zmk/reset.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/linker/zmk-events.ld b/app/include/linker/zmk-events.ld index 44063be0..78d00bb7 100644 --- a/app/include/linker/zmk-events.ld +++ b/app/include/linker/zmk-events.ld @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/behavior.h b/app/include/zmk/behavior.h index 63edcc9e..6f5815f1 100644 --- a/app/include/zmk/behavior.h +++ b/app/include/zmk/behavior.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #pragma once diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index e760ed70..d0aaa96b 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #pragma once diff --git a/app/include/zmk/display.h b/app/include/zmk/display.h index 93ac3ffd..def43920 100644 --- a/app/include/zmk/display.h +++ b/app/include/zmk/display.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/endpoints.h b/app/include/zmk/endpoints.h index 4c0f4425..aad6265b 100644 --- a/app/include/zmk/endpoints.h +++ b/app/include/zmk/endpoints.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/app/include/zmk/event-manager.h b/app/include/zmk/event-manager.h index d9a56a4f..9da66029 100644 --- a/app/include/zmk/event-manager.h +++ b/app/include/zmk/event-manager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/events/keycode-state-changed.h b/app/include/zmk/events/keycode-state-changed.h index e12813c7..fc37946b 100644 --- a/app/include/zmk/events/keycode-state-changed.h +++ b/app/include/zmk/events/keycode-state-changed.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/events/modifiers-state-changed.h b/app/include/zmk/events/modifiers-state-changed.h index a17a0931..b39e11e0 100644 --- a/app/include/zmk/events/modifiers-state-changed.h +++ b/app/include/zmk/events/modifiers-state-changed.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/events/position-state-changed.h b/app/include/zmk/events/position-state-changed.h index c91688ee..f88080d2 100644 --- a/app/include/zmk/events/position-state-changed.h +++ b/app/include/zmk/events/position-state-changed.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/events/sensor-event.h b/app/include/zmk/events/sensor-event.h index f881ac5c..a9302a5c 100644 --- a/app/include/zmk/events/sensor-event.h +++ b/app/include/zmk/events/sensor-event.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/handlers.h b/app/include/zmk/handlers.h index a10851f8..7ce1d27e 100644 --- a/app/include/zmk/handlers.h +++ b/app/include/zmk/handlers.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index 138606a5..a945e729 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/app/include/zmk/hog.h b/app/include/zmk/hog.h index e2f976a2..a7dda515 100644 --- a/app/include/zmk/hog.h +++ b/app/include/zmk/hog.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #pragma once diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index c1f63932..61925878 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once bool zmk_keymap_layer_active(u8_t layer); diff --git a/app/include/zmk/keys.h b/app/include/zmk/keys.h index 6966bbac..ee9c3d93 100644 --- a/app/include/zmk/keys.h +++ b/app/include/zmk/keys.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/app/include/zmk/kscan.h b/app/include/zmk/kscan.h index ebffccda..33526008 100644 --- a/app/include/zmk/kscan.h +++ b/app/include/zmk/kscan.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once int zmk_kscan_init(char *name); diff --git a/app/include/zmk/matrix.h b/app/include/zmk/matrix.h index 30882638..16143176 100644 --- a/app/include/zmk/matrix.h +++ b/app/include/zmk/matrix.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include diff --git a/app/include/zmk/matrix_transform.h b/app/include/zmk/matrix_transform.h index e9e969a4..29c2afcd 100644 --- a/app/include/zmk/matrix_transform.h +++ b/app/include/zmk/matrix_transform.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once u32_t zmk_matrix_transform_row_column_to_position(u32_t row, u32_t column); \ No newline at end of file diff --git a/app/include/zmk/rgb_underglow.h b/app/include/zmk/rgb_underglow.h index 69e9a9bb..94cc32cc 100644 --- a/app/include/zmk/rgb_underglow.h +++ b/app/include/zmk/rgb_underglow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Nick Winans + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/sensors.h b/app/include/zmk/sensors.h index c60cd4be..63dcade0 100644 --- a/app/include/zmk/sensors.h +++ b/app/include/zmk/sensors.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/usb_hid.h b/app/include/zmk/usb_hid.h index 5d7c744a..7ee26298 100644 --- a/app/include/zmk/usb_hid.h +++ b/app/include/zmk/usb_hid.h @@ -1,5 +1,10 @@ -#ifndef ZMK_USB_HID -#define ZMK_USB_HID +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once #include #include @@ -10,5 +15,3 @@ int zmk_usb_hid_init(); int zmk_usb_hid_send_report(u8_t *report, size_t len); - -#endif diff --git a/app/run-test.sh b/app/run-test.sh index be335c62..3b7cd589 100755 --- a/app/run-test.sh +++ b/app/run-test.sh @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2020 Peter Johanson; Cody McGinnis +# Copyright (c) 2020 The ZMK Contributors # # SPDX-License-Identifier: MIT # diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index 2c6d996e..dce724d9 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Cody McGinnis, Okke Formsma + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c index 7404c798..42becf50 100644 --- a/app/src/behaviors/behavior_key_press.c +++ b/app/src/behaviors/behavior_key_press.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c index 8a8584a9..7d651354 100644 --- a/app/src/behaviors/behavior_momentary_layer.c +++ b/app/src/behaviors/behavior_momentary_layer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_none.c b/app/src/behaviors/behavior_none.c index e822d5e1..c4649882 100644 --- a/app/src/behaviors/behavior_none.c +++ b/app/src/behaviors/behavior_none.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c index 30a96ea8..b5692b50 100644 --- a/app/src/behaviors/behavior_reset.c +++ b/app/src/behaviors/behavior_reset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index 7a48e070..f0a35ef8 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Nick Winans + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_sensor_rotate_key_press.c b/app/src/behaviors/behavior_sensor_rotate_key_press.c index fb0fb852..fa555752 100644 --- a/app/src/behaviors/behavior_sensor_rotate_key_press.c +++ b/app/src/behaviors/behavior_sensor_rotate_key_press.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_toggle_layer.c b/app/src/behaviors/behavior_toggle_layer.c index 02a76d29..c6d52251 100644 --- a/app/src/behaviors/behavior_toggle_layer.c +++ b/app/src/behaviors/behavior_toggle_layer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Cody McGinnis + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_transparent.c b/app/src/behaviors/behavior_transparent.c index 5109264a..51f682b5 100644 --- a/app/src/behaviors/behavior_transparent.c +++ b/app/src/behaviors/behavior_transparent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/ble.c b/app/src/ble.c index 0e96d16a..c4d3efd5 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/ble_unpair_combo.c b/app/src/ble_unpair_combo.c index 82fa8342..3633a5b0 100644 --- a/app/src/ble_unpair_combo.c +++ b/app/src/ble_unpair_combo.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/display.c b/app/src/display.c index 9021914f..dca462e4 100644 --- a/app/src/display.c +++ b/app/src/display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/endpoints.c b/app/src/endpoints.c index c9ba7169..61e86cee 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #include #include diff --git a/app/src/event_manager.c b/app/src/event_manager.c index 47ad6b73..6d37e4e6 100644 --- a/app/src/event_manager.c +++ b/app/src/event_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/events/keycode_state_changed.c b/app/src/events/keycode_state_changed.c index 73508e16..9a1984a3 100644 --- a/app/src/events/keycode_state_changed.c +++ b/app/src/events/keycode_state_changed.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/events/modifiers_state_changed.c b/app/src/events/modifiers_state_changed.c index 71ec015b..8becd02f 100644 --- a/app/src/events/modifiers_state_changed.c +++ b/app/src/events/modifiers_state_changed.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/events/position_state_changed.c b/app/src/events/position_state_changed.c index 69cba03c..f8f1a268 100644 --- a/app/src/events/position_state_changed.c +++ b/app/src/events/position_state_changed.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/events/sensor_event.c b/app/src/events/sensor_event.c index 1b0302dd..c6b80cd6 100644 --- a/app/src/events/sensor_event.c +++ b/app/src/events/sensor_event.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/hid.c b/app/src/hid.c index ca040562..07fc3a0b 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 69aa23e7..9f68ca20 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/hog.c b/app/src/hog.c index 589c28ff..92858d56 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include diff --git a/app/src/keymap.c b/app/src/keymap.c index 57cdad6e..b1c68f1e 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #include #include diff --git a/app/src/kscan.c b/app/src/kscan.c index 63713f1f..7a4d3a49 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/kscan_composite.c b/app/src/kscan_composite.c index d46484b7..15527ebe 100644 --- a/app/src/kscan_composite.c +++ b/app/src/kscan_composite.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/kscan_mock.c b/app/src/kscan_mock.c index d626c71e..741f6c17 100644 --- a/app/src/kscan_mock.c +++ b/app/src/kscan_mock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/main.c b/app/src/main.c index 5a678ee0..5da272e5 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/matrix_transform.c b/app/src/matrix_transform.c index 7ecf1ae0..8a037b34 100644 --- a/app/src/matrix_transform.c +++ b/app/src/matrix_transform.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #include #include diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 95adcec2..97c2ac0a 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Nick Winans + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/sensors.c b/app/src/sensors.c index 501ce15b..7a7c0c5b 100644 --- a/app/src/sensors.c +++ b/app/src/sensors.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 237096fd..9e67228e 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index e1d232a4..0a5ddb7a 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #include #include diff --git a/app/src/split_listener.c b/app/src/split_listener.c index 65f835a2..46a95e14 100644 --- a/app/src/split_listener.c +++ b/app/src/split_listener.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c index 784fc250..e2fe0f3d 100644 --- a/app/src/usb_hid.c +++ b/app/src/usb_hid.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #include #include From 073f5c8b98c5111d954fe5bfe98951b24983449d Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Thu, 10 Sep 2020 18:40:07 -0700 Subject: [PATCH 026/227] Added File Transfer Error/CMake Warning Docs --- .../troubleshooting/filetransfer/linux.png | Bin 0 -> 40111 bytes .../troubleshooting/filetransfer/windows.png | Bin 0 -> 12077 bytes docs/docs/troubleshooting.md | 31 +++++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 docs/docs/assets/troubleshooting/filetransfer/linux.png create mode 100644 docs/docs/assets/troubleshooting/filetransfer/windows.png diff --git a/docs/docs/assets/troubleshooting/filetransfer/linux.png b/docs/docs/assets/troubleshooting/filetransfer/linux.png new file mode 100644 index 0000000000000000000000000000000000000000..c192dfab8fe4cf1de2d9324fde1eebdc3789900c GIT binary patch literal 40111 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 HgJ1s*xk{lE literal 0 HcmV?d00001 diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index cd8bfd64..4820e116 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -7,11 +7,40 @@ sidebar_title: Troubleshooting The following page provides suggestions for common errors that may occur during firmware compilation. If the information provided is insufficient to resolve the issue, feel free to seek out help from the [ZMK Discord](https://zmkfirmware.dev/community/discord/invite). +### File Transfer Error + +Variations of the warnings shown below occur when flashing the `.uf2` onto the microcontroller. This is because the microcontroller resets itself before the OS receives confirmation that the file transfer is complete. Errors like this are normal and can generally be ignored. Verification of a functional board can be done by attempting to pair your computer to your newly flashed keyboard via Bluetooth or plugging in a USB cable if `ZMK_USB` is enabled in your Kconfig.defconfig. + +| ![Example Error Screen](../docs/assets/troubleshooting/filetransfer/windows.png) | +| :-------------------------------------------------------------------------------: | +| An example of the file transfer error on Windows 10 | + +| ![Example Error Screen](../docs/assets/troubleshooting/filetransfer/linux.png) | +| :-------------------------------------------------------------------------------: | +| An example of the file transfer error on Linux | + + ### CMake Error -An error along the lines of `CMake Error at (zmk directory)/zephyr/cmake/generic_toolchain.cmake:64 (include): include could not find load file:` during firmware compilation indicates that the Zephyr Environment Variables are not properly defined. +``` +CMake Warning at C:/zmk/zephyr/subsys/usb/CMakeLists.txt:28 (message): + CONFIG_USB_DEVICE_VID has default value 0x2FE3. + + This value is only for testing and MUST be configured for USB products. + + +CMake Warning at C:/zmk/zephyr/subsys/usb/CMakeLists.txt:34 (message): + CONFIG_USB_DEVICE_PID has default value 0x100. + + This value is only for testing and MUST be configured for USB products. +``` + +CMake Warnings shown above during `west build` are normal occurrences. They should not negatively affect the firmware's ability to function as normal. + +On the other hand, an error along the lines of `CMake Error at (zmk directory)/zephyr/cmake/generic_toolchain.cmake:64 (include): include could not find load file:` during firmware compilation indicates that the Zephyr Environment Variables are not properly defined. For more information, click [here](../docs/dev-setup#environment-variables). + ### dtlib.DTError An error along the lines of `dtlib.DTError: .dts.pre.tmp:` during firmware compilation indicates an issue within the `.keymap` file. From 5b38fcff71a0e22407dbd418fb1900614ecbfb6f Mon Sep 17 00:00:00 2001 From: Kurtis Lew Date: Thu, 10 Sep 2020 18:44:39 -0700 Subject: [PATCH 027/227] Reversed pairing instructions --- docs/docs/troubleshooting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index 4820e116..deb89b64 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -9,7 +9,7 @@ The following page provides suggestions for common errors that may occur during ### File Transfer Error -Variations of the warnings shown below occur when flashing the `.uf2` onto the microcontroller. This is because the microcontroller resets itself before the OS receives confirmation that the file transfer is complete. Errors like this are normal and can generally be ignored. Verification of a functional board can be done by attempting to pair your computer to your newly flashed keyboard via Bluetooth or plugging in a USB cable if `ZMK_USB` is enabled in your Kconfig.defconfig. +Variations of the warnings shown below occur when flashing the `.uf2` onto the microcontroller. This is because the microcontroller resets itself before the OS receives confirmation that the file transfer is complete. Errors like this are normal and can generally be ignored. Verification of a functional board can be done by attempting to pair your newly flashed keyboard to your computer via Bluetooth or plugging in a USB cable if `ZMK_USB` is enabled in your Kconfig.defconfig. | ![Example Error Screen](../docs/assets/troubleshooting/filetransfer/windows.png) | | :-------------------------------------------------------------------------------: | From 89ba824b2b28d4fdbd174ba20b1183d6547c19f8 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 11:04:58 +0530 Subject: [PATCH 028/227] typo --- docs/docs/user-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/user-setup.md b/docs/docs/user-setup.md index 2aade829..c2071363 100644 --- a/docs/docs/user-setup.md +++ b/docs/docs/user-setup.md @@ -179,7 +179,7 @@ storage device. Once the flash is complete, the controller should automatically ## Wirelessly Connecting Your Keyboard -Connecting your keyboard wirelessly is the same as adding other Bluetooth devides: press the reset button and scan for devices. However, pairing and bonding is still currently being worked on to increase relability and ease of use. In addition, users have in general reported that Bluetooth pairing with computers tends to be quite finnicky. Try out the connection with your tablet or phone first, as those devices seem to work much more consistently. See [BLE Reset](./bond-reset.md) for help on resetting your MCUs if you're experiencing connection issues. +Connecting your keyboard wirelessly is the same as adding other Bluetooth devices: press the reset button and scan for devices. However, pairing and bonding is still currently being worked on to increase relability and ease of use. In addition, users have in general reported that Bluetooth pairing with computers tends to be quite finnicky. Try out the connection with your tablet or phone first, as those devices seem to work much more consistently. See [BLE Reset](./bond-reset.md) for help on resetting your MCUs if you're experiencing connection issues. ### Connecting Split Keyboard Halves From cd00c0aad41e4aad369bbc12f68b888ab2d9ddd4 Mon Sep 17 00:00:00 2001 From: Cody McGinnis Date: Fri, 11 Sep 2020 02:28:55 -0400 Subject: [PATCH 029/227] fix(docs): Fix the example mod tap configuration --- docs/docs/behavior/mod-tap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/behavior/mod-tap.md b/docs/docs/behavior/mod-tap.md index dcac4920..068928ad 100644 --- a/docs/docs/behavior/mod-tap.md +++ b/docs/docs/behavior/mod-tap.md @@ -31,8 +31,8 @@ You can configure a different tapping term in your keymap: ``` &mt { - tapping_term_ms: <400>; -} + tapping_term_ms = <400>; +}; / { keymap { From ce862d148db09ed318c9d592bef4e29f59949b5e Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 19:47:20 +0530 Subject: [PATCH 030/227] Delete pro-micro-labelled-image.jpg --- docs/docs/pro-micro-labelled-image.jpg | Bin 115573 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/docs/pro-micro-labelled-image.jpg diff --git a/docs/docs/pro-micro-labelled-image.jpg b/docs/docs/pro-micro-labelled-image.jpg deleted file mode 100644 index f72d407719e9ff4d20ed45d93d12dead8caa9da5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 115573 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 DB^7&W From 69e6a99180b51c0d9bdca44741e71e54a162bf14 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 19:49:46 +0530 Subject: [PATCH 031/227] Add files via upload --- .../pro-micro/pro-micro-pins-labelled.jpg | Bin 0 -> 115573 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg diff --git a/docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg b/docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f72d407719e9ff4d20ed45d93d12dead8caa9da5 GIT binary patch literal 115573 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 DB^7&W literal 0 HcmV?d00001 From e660e56dfb428d58d6c6548ac804c8933495c22d Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 19:52:32 +0530 Subject: [PATCH 032/227] Update dev-boards-shields-keymaps.md --- docs/docs/dev-boards-shields-keymaps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-boards-shields-keymaps.md b/docs/docs/dev-boards-shields-keymaps.md index 17a38473..9ed5a328 100644 --- a/docs/docs/dev-boards-shields-keymaps.md +++ b/docs/docs/dev-boards-shields-keymaps.md @@ -35,7 +35,7 @@ in the `app/boards/${arch}/${board_name}` directory, e.g. `app/boards/arm/planck ## Pro Micro Compatible Keyboard -![Labelled Pro Micro pins](pro-micro-labelled-image.jpg) +![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) For keyboards that require a (usually Pro Micro compatible) add-on board to operate, the ZMK integration pieces are places in the _shield_ definition for that keyboard, allowing users to From 4ce70831dddfbe1c8fda8d23086388ad36a421a5 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 19:54:03 +0530 Subject: [PATCH 033/227] Update dev-guide-new-shield.md --- docs/docs/dev-guide-new-shield.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 23d2387d..832519d8 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -64,7 +64,7 @@ endif ## Shield Overlay -![Labelled Pro Micro pins](pro-micro-labelled-image.jpg) +![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, this might look something like: From c20eb9abac1797ff94012863d2bec582b68e6ded Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 20:01:46 +0530 Subject: [PATCH 034/227] Update hold-tap.md --- docs/docs/behavior/hold-tap.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/behavior/hold-tap.md b/docs/docs/behavior/hold-tap.md index fa68538b..6790e882 100644 --- a/docs/docs/behavior/hold-tap.md +++ b/docs/docs/behavior/hold-tap.md @@ -56,7 +56,7 @@ A code example which configures a mod-tap setting that works with homerow mods: If this config does not work for you, try the flavor "tap-preferred" and a short tapping_term_ms such as 120ms. -If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter.For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. +If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter. For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. #### Note -Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. \ No newline at end of file +Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. From 6d7fb6c48dcd62c9d436c08f545f065bb41f810f Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 20:10:23 +0530 Subject: [PATCH 035/227] Update dev-clean-room.md --- docs/docs/dev-clean-room.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-clean-room.md b/docs/docs/dev-clean-room.md index c11171c8..89e9826d 100644 --- a/docs/docs/dev-clean-room.md +++ b/docs/docs/dev-clean-room.md @@ -11,7 +11,7 @@ Anyone wanting to contribute code to ZMK _must_ read this, and adhere to the ste ::: ZMK Firmware is a [clean room design](https://en.wikipedia.org/wiki/Clean_room_design) keyboard firmware, that -borrows/implements a lot of the features found in popular keyboard firmwares projects like [QMK](https://qmk.fm) +borrows/implements a lot of the features found in popular keyboard firmware projects like [QMK](https://qmk.fm) and [TMK](https://github.com/tmk/tmk_keyboard). However, in order for ZMK to use the MIT, it _must_ not incorporate any of the GPL licensed code from those projects. From 178e5e5afbf5d9b4dabb1a247f36714f5234ad29 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 20:37:05 +0530 Subject: [PATCH 036/227] Reverting provious commit --- docs/docs/behavior/hold-tap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/behavior/hold-tap.md b/docs/docs/behavior/hold-tap.md index 6790e882..ab510223 100644 --- a/docs/docs/behavior/hold-tap.md +++ b/docs/docs/behavior/hold-tap.md @@ -56,7 +56,7 @@ A code example which configures a mod-tap setting that works with homerow mods: If this config does not work for you, try the flavor "tap-preferred" and a short tapping_term_ms such as 120ms. -If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter. For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. +If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter.For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. #### Note Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. From 7f5235904a5c49cc79875541d313317c9c6856c0 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 20:37:57 +0530 Subject: [PATCH 037/227] Reverting previous commit --- docs/docs/dev-clean-room.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-clean-room.md b/docs/docs/dev-clean-room.md index 89e9826d..c11171c8 100644 --- a/docs/docs/dev-clean-room.md +++ b/docs/docs/dev-clean-room.md @@ -11,7 +11,7 @@ Anyone wanting to contribute code to ZMK _must_ read this, and adhere to the ste ::: ZMK Firmware is a [clean room design](https://en.wikipedia.org/wiki/Clean_room_design) keyboard firmware, that -borrows/implements a lot of the features found in popular keyboard firmware projects like [QMK](https://qmk.fm) +borrows/implements a lot of the features found in popular keyboard firmwares projects like [QMK](https://qmk.fm) and [TMK](https://github.com/tmk/tmk_keyboard). However, in order for ZMK to use the MIT, it _must_ not incorporate any of the GPL licensed code from those projects. From 98bd4796cfa3888e0f91d295599e42524e8e07db Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 20:40:19 +0530 Subject: [PATCH 038/227] Reverting previous commit --- docs/docs/user-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/user-setup.md b/docs/docs/user-setup.md index c2071363..2aade829 100644 --- a/docs/docs/user-setup.md +++ b/docs/docs/user-setup.md @@ -179,7 +179,7 @@ storage device. Once the flash is complete, the controller should automatically ## Wirelessly Connecting Your Keyboard -Connecting your keyboard wirelessly is the same as adding other Bluetooth devices: press the reset button and scan for devices. However, pairing and bonding is still currently being worked on to increase relability and ease of use. In addition, users have in general reported that Bluetooth pairing with computers tends to be quite finnicky. Try out the connection with your tablet or phone first, as those devices seem to work much more consistently. See [BLE Reset](./bond-reset.md) for help on resetting your MCUs if you're experiencing connection issues. +Connecting your keyboard wirelessly is the same as adding other Bluetooth devides: press the reset button and scan for devices. However, pairing and bonding is still currently being worked on to increase relability and ease of use. In addition, users have in general reported that Bluetooth pairing with computers tends to be quite finnicky. Try out the connection with your tablet or phone first, as those devices seem to work much more consistently. See [BLE Reset](./bond-reset.md) for help on resetting your MCUs if you're experiencing connection issues. ### Connecting Split Keyboard Halves From 54437db0ba2809de5ef0b987f59cfe47c486c669 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 20:42:33 +0530 Subject: [PATCH 039/227] Update with the examples --- docs/docs/dev-guide-new-shield.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 832519d8..6140b078 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -66,6 +66,8 @@ endif ![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) +ZMK uses the green color coded pin names to generate devicetree node references. For example, to refer to the node `D0` in the devicetree files, use `&pro_micro_d 0` or to refer to `A1`, use `&pro_micro_a 1`. + The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, this might look something like: From 394bf7808745726df0440cfbd70e9f4487dfca9a Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 23:31:38 +0530 Subject: [PATCH 040/227] Reverting unwanted changes From 2e1bf46892881cf0e31f593ad5a2290083a3c633 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 23:35:57 +0530 Subject: [PATCH 041/227] Update hold-tap.md From c38d3dd849a29b786b8b6683dd627e7b27ef8ee6 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 23:39:29 +0530 Subject: [PATCH 042/227] Update hold-tap.md From 223a19cb0472d453fbe734b37a8ac59a82f61c67 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 23:45:29 +0530 Subject: [PATCH 043/227] Update hold-tap.md From ce8ade4afaa4cc9fc2b94050e98680301e539e56 Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 23:48:53 +0530 Subject: [PATCH 044/227] A bad commit --- docs/docs/behavior/hold-tap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/behavior/hold-tap.md b/docs/docs/behavior/hold-tap.md index ab510223..d51edd31 100644 --- a/docs/docs/behavior/hold-tap.md +++ b/docs/docs/behavior/hold-tap.md @@ -59,4 +59,4 @@ If this config does not work for you, try the flavor "tap-preferred" and a short If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter.For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. #### Note -Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. +Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT` From e11cad9fde0e90a47c9b09f66c612ee946f597cf Mon Sep 17 00:00:00 2001 From: Mamoor Jaan Khan <56243233+LowNightSnack@users.noreply.github.com> Date: Fri, 11 Sep 2020 23:49:12 +0530 Subject: [PATCH 045/227] Update hold-tap.md --- docs/docs/behavior/hold-tap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/behavior/hold-tap.md b/docs/docs/behavior/hold-tap.md index d51edd31..ab510223 100644 --- a/docs/docs/behavior/hold-tap.md +++ b/docs/docs/behavior/hold-tap.md @@ -59,4 +59,4 @@ If this config does not work for you, try the flavor "tap-preferred" and a short If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter.For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. #### Note -Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT` +Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. From 595dff68710f7f58e7e257c3d060e80e413dfb87 Mon Sep 17 00:00:00 2001 From: CrossR Date: Sun, 13 Sep 2020 18:07:45 +0100 Subject: [PATCH 046/227] Add PowerShell script and tidy up bash script. --- docs/static/setup.ps1 | 176 ++++++++++++++++++++++++++++++++++++++++++ docs/static/setup.sh | 64 ++++++++------- 2 files changed, 213 insertions(+), 27 deletions(-) create mode 100644 docs/static/setup.ps1 diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 new file mode 100644 index 00000000..acda1944 --- /dev/null +++ b/docs/static/setup.ps1 @@ -0,0 +1,176 @@ +$ErrorActionPreference = "Stop" + +function Get-Choice-From-Options { + param( + [String[]] $Options, + [String] $Prompt + ) + + while ($true) { + for ($i = 0; $i -lt $Options.length; $i++) { + Write-Host "$($i + 1)) $($Options[$i])" + } + + Write-Host "$($Options.length + 1)) Quit" + $selection = Read-Host $Prompt + + if ($selection -eq $Options.length + 1) { + Write-Host "Goodbye!" + exit + } + elseif ($selection -le $Options.length) { + $choice = $($selection - 1) + break + } + else { + Write-Host "Invalid Option. Try another one." + } + } + + return $choice +} + +function Test-Git-Config { + param( + [String] $Option, + [String] $ErrMsg + ) + + git config $Option | Out-Null + + if ($lastExitCode -ne 0) { + Write-Host $ErrMsg + exit + } +} + +try { + git | Out-Null +} +catch [System.Management.Automation.CommandNotFoundException] { + Write-Host "Git is not installed, and is required for this script!" + exit +} + +Test-Git-Config -Option "user.name" -ErrMsg "Git username not set!`nRun: git config --global user.name 'My Name'" +Test-Git-Config -Option "user.email" -ErrMsg "Git email not set!`nRun: git config --global user.name 'example@myemail.com'" + +$repo_path = "https://github.com/zmkfirmware/zmk-config-split-template.git" + +$title = "ZMK Config Setup:" +$prompt = "Pick an MCU board" +$options = "nice!nano", "QMK Proton-C", "BlueMicro840 (v1)" +$boards = "nice_nano", "proton_c", "bluemicro840_v1" + +Write-Host "$title" +Write-Host "" +Write-Host "MCU Board Selection:" + +$choice = Get-Choice-From-Options -Options $options -Prompt $prompt +$board = $($boards[$choice]) + +Write-Host "" +Write-Host "Keyboard Shield Selection:" +$prompt = "Pick a keyboard" + +# TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. +$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac" +$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac" +$splits = "y", "y", "y", "y", "y", "y", "n" + +$choice = Get-Choice-From-Options -Options $options -Prompt $prompt +$shield_title = $($options[$choice]) +$shield = $($names[$choice]) +$split = $($splits[$choice]) + +if ($split -eq "n") { + $repo_path = "https://github.com/zmkfirmware/zmk-config-template.git" +} + +$copy_keymap = Read-Host "Copy in the stock keymap for customisation? [Yn]" + +if ($copy_keymap -eq "" -or $copy_keymap -eq "Y" -or $copy_keymap -eq "y") { + $copy_keymap = "yes" +} + +$github_user = Read-Host "GitHub Username (leave empty to skip GitHub repo creation)" + +if ($github_user -ne "") { + $repo_name = Read-Host "GitHub Repo Name [zmk-config]" + + if ($repo_name -eq "") { + $repo_name = "zmk-config" + } + + $github_repo = Read-Host "GitHub Repo [https://github.com/$github_user/$repo_name.git]" + + if ($github_repo -eq "") { + $github_repo = "https://github.com/$github_user/$repo_name.git" + } +} +else { + $repo_name = "zmk-config" + $github_repo = "" +} + +Write-Host "" +Write-Host "Preparing a user config for:" +Write-Host "* MCU Board: ${board}" +Write-Host "* Shield: ${shield}" + +if ($copy_keymap -eq "yes") { + Write-Host "* Copy Keymap?: Yes" +} +else { + Write-Host "* Copy Keymap?: No" +} + +if ($github_repo -ne "") { + Write-Host "* GitHub Repo to Push (please create this in GH first!): $github_repo" +} + +Write-Host "" +$do_it = Read-Host "Continue? [Yn]" + +if ($do_it -ne "" -and $do_it -ne "Y" -and $do_it -ne "y") { + Write-Host "Aborting..." + exit +} + +git clone --single-branch "$repo_path" "$repo_name" +Set-Location "$repo_name" + +Push-Location config + +Invoke-RestMethod -Uri "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.conf" -OutFile "${shield}.conf" + +if ($copy_keymap -eq "yes") { + Invoke-RestMethod -Uri "https://raw.githubusercontent.com/zmkfirmware/zmk/main/app/boards/shields/${shield}/${shield}.keymap" -OutFile "${shield}.keymap" +} + +Pop-Location + +$build_file = (Get-Content .github/workflows/build.yml).replace("BOARD_NAME", $board) +$build_file = $build_file.replace("SHIELD_NAME", $shield) +$build_file = $build_file.replace("KEYBOARD_TITLE", $shield_title) + +if ($board -eq "proton_c") { + $build_file = $build_file.replace("uf2", "hex") +} + +Set-Content -Path .github/workflows/build.yml -Value $build_file + +Remove-Item -Recurse -Force .git +git init . +git add . +git commit -m "Initial User Config." + +if ($github_repo -ne "") { + git remote add origin "$github_repo" + git push --set-upstream origin $(git symbolic-ref --short HEAD) + + if ($github_repo -imatch "https") { + $actions = "$($github_repo.substring(0, $github_repo.length - 4))/actions" + Write-Host "Your firmware should be availalbe from the GitHub Actions shortly: $actions" + } +} diff --git a/docs/static/setup.sh b/docs/static/setup.sh index 5d203a4c..b3c14f77 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -1,15 +1,26 @@ -#!/bin/sh +#!/bin/bash set -e +CheckExists() { + command_to_run=$1 + error_message=$2 + + if ! eval "$command_to_run" &> /dev/null; then + printf "%s\n" "$error_message" + exit + fi +} + +CheckExists "command -v git" "git is not installed, and is required for this script!" +CheckExists "command -v curl" "curl is not installed, and is required for this script!" + +CheckExists "git config user.name" "Git username not set!\nRun: git config --global user.name 'My Name'" +CheckExists "git config user.email" "Git email not set!\nRun: git config --global user.email 'example@myemail.com'" + repo_path="https://github.com/zmkfirmware/zmk-config-split-template.git" title="ZMK Config Setup:" - -# TODO: Check for git being installed -# TODO: Check for curl being installed -# TODO: Check for user.name and user.email git configs being set - prompt="Pick an MCU board:" options=("nice!nano" "QMK Proton-C" "BlueMicro840 (v1)") @@ -31,9 +42,6 @@ select opt in "${options[@]}" "Quit"; do esac done -#read -p "Is this board a complete keyboard [yN]: " complete -#echo "$complete" - echo "" echo "Keyboard Shield Selection:" @@ -67,41 +75,43 @@ if [ "$split" == "n" ]; then repo_path="https://github.com/zmkfirmware/zmk-config-template.git" fi -read -e -p "Copy in the stock keymap for customization? [Yn]: " copy_keymap +read -r -e -p "Copy in the stock keymap for customization? [Yn]: " copy_keymap if [ -z "$copy_keymap" ] || [ "$copy_keymap" == "Y" ] || [ "$copy_keymap" == "y" ]; then copy_keymap="yes"; fi -read -e -p "GitHub Username (leave empty to skip GitHub repo creation): " github_user +read -r -e -p "GitHub Username (leave empty to skip GitHub repo creation): " github_user if [ -n "$github_user" ]; then - read -p "GitHub Repo Name [zmk-config]: " repo_name - if [ -z "$repo_name" ]; then repo_name="zmk-config"; fi + read -r -p "GitHub Repo Name [zmk-config]: " repo_name + if [ -z "$repo_name" ]; then repo_name="zmk-config"; fi - read -p "GitHub Repo [https://github.com/${github_user}/${repo_name}.git]: " github_repo + read -r -p "GitHub Repo [https://github.com/${github_user}/${repo_name}.git]: " github_repo - if [ -z "$github_repo" ]; then github_repo="https://github.com/${github_user}/${repo_name}.git"; fi + if [ -z "$github_repo" ]; then github_repo="https://github.com/${github_user}/${repo_name}.git"; fi else - repo_name="zmk-config" + repo_name="zmk-config" fi echo "" echo "Preparing a user config for:" echo "* MCU Board: ${board}" echo "* Shield: ${shield}" + if [ "$copy_keymap" == "yes" ]; then echo "* Copy Keymap?: ✓" else echo "* Copy Keymap?: ❌" fi + if [ -n "$github_repo" ]; then - echo "* GitHub Repo To Push (please create this in GH first!): ${github_repo}" + echo "* GitHub Repo To Push (please create this in GH first!): ${github_repo}" fi echo "" -read -p "Continue? [Yn]: " do_it +read -r -p "Continue? [Yn]: " do_it if [ -n "$do_it" ] && [ "$do_it" != "y" ] && [ "$do_it" != "Y" ]; then - echo "Aborting..." - exit + echo "Aborting..." + exit fi git clone --single-branch $repo_path ${repo_name} @@ -118,10 +128,10 @@ fi popd sed -i'.orig' \ - -e "s/BOARD_NAME/$board/" \ - -e "s/SHIELD_NAME/$shield/" \ - -e "s/KEYBOARD_TITLE/$shield_title/" \ - .github/workflows/build.yml + -e "s/BOARD_NAME/$board/" \ + -e "s/SHIELD_NAME/$shield/" \ + -e "s/KEYBOARD_TITLE/$shield_title/" \ + .github/workflows/build.yml if [ "$board" == "proton_c" ]; then # Proton-C board still fa @@ -136,11 +146,11 @@ git add . git commit -m "Initial User Config." if [ -n "$github_repo" ]; then - git remote add origin "$github_repo" - git push --set-upstream origin $(git symbolic-ref --short HEAD) + git remote add origin "$github_repo" + git push --set-upstream origin "$(git symbolic-ref --short HEAD)" # TODO: Support determing the actions URL when non-https:// repo URL is used. if [ "${github_repo}" != "${github_repo#https://}" ]; then - echo "Your firmware should be available from the GitHub Actions shortly: ${github_url%.git}/actions" + echo "Your firmware should be available from the GitHub Actions shortly: ${github_repo%.git}/actions" fi fi From 763d62f6f292bec20bd183f9ba4d0da65fb3f7b5 Mon Sep 17 00:00:00 2001 From: Okke Formsma Date: Fri, 4 Sep 2020 20:57:11 +0200 Subject: [PATCH 047/227] update intro page, add layer-tap docs and update hold-tap docs. --- docs/docs/behavior/hold-tap.md | 10 +++++++--- docs/docs/behavior/layers.md | 20 ++++++++++++++++++-- docs/docs/intro.md | 33 +++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 19 deletions(-) diff --git a/docs/docs/behavior/hold-tap.md b/docs/docs/behavior/hold-tap.md index ab510223..9f8f5fab 100644 --- a/docs/docs/behavior/hold-tap.md +++ b/docs/docs/behavior/hold-tap.md @@ -22,7 +22,11 @@ We call this the 'hold-preferred' flavor of hold-taps. While this flavor may wor ![Hold-tap comparison](../assets/hold-tap/comparison.png) -### Configuration +### Basic usage +For basic usage, please see [mod-tap](./mod-tap.md) and [layer-tap](./layers.md) pages. + + +### Advanced Configuration A code example which configures a mod-tap setting that works with homerow mods: ``` @@ -58,5 +62,5 @@ If this config does not work for you, try the flavor "tap-preferred" and a short If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter.For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. -#### Note -Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. +#### Comparison to QMK +The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting in QMK. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. \ No newline at end of file diff --git a/docs/docs/behavior/layers.md b/docs/docs/behavior/layers.md index da7f07f5..c7693887 100644 --- a/docs/docs/behavior/layers.md +++ b/docs/docs/behavior/layers.md @@ -26,7 +26,7 @@ This allows you to use those defines, e.g. `LOWER` later in your keymap. ## Momentary Layer -The "momentary layer" behavior allows you to enable a layer while a certain key is pressed. Immediately upon +The "momentary layer" behavior enables a layer while a certain key is pressed. Immediately upon activation of the key, the layer is enabled, and immediately open release of the key, the layer is disabled again. @@ -41,9 +41,25 @@ Example: &mo LOWER ``` +## Layer-tap + +The "layer-tap" behavior enables a layer when a key is held, and output another key when the key is only tapped for a short time. For more information on the inner workings of layer-tap, see [hold-tap](./hold-tap.md). + +### Behavior Binding +- Reference: `<` +- Parameter: The layer number to enable when held, e.g. `1` +- Parameter: The keycode to send when tapped, e.g. `A` + +Example: + +``` +< LOWER SPC +``` + + ## Toggle Layer -The "toggle layer" behavior allows you to enable a layer until the layer is manually disabled. +The "toggle layer" behavior enables a layer until the layer is manually disabled. ### Behavior Binding diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 50a747cf..8c1c043d 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -7,31 +7,36 @@ sidebar_label: Introduction ZMK Firmware is an open source (MIT) keyboard firmware built on the [Zephyr™ Project](https://zephyrproject.org/) Real Time Operating System (RTOS). -The goal is to provider a powerful, featureful keyboard firmware that is free +The goal is to provide a powerful, featureful keyboard firmware that is free of licensing issues that prevent upstream BLE support as a first-class feature. ## Features -At this point, ZMK is _missing_ more features than it has. Currently, the mostly working bits +At this point, ZMK is still missing many features. Currently, the working bits include: -- HID Over GATT (HOG) - This is the official term for BLE HID devices -- Keymaps and layers with basic keycodes -- Some initial work on one "behavior", Mod-Tap -- Basic HID over USB -- Basic consumer (media) keycodes. -- Basic OLED display logic -- Basic Split support -- Encoders +- Wireless connectivity via BLE HID Over GATT (HOG) +- USB connectivity +- Low active power usage +- Split keyboard support +- [Keymaps and layers](behavior/layers) +- [Hold-tap](behavior/hold-tap) (which includes [mod-tap](behavior/mod-tap), [layer-tap](behavior/layers)) +- [Basic HID over USB](behavior/key-press) +- [Basic consumer (media) keycodes](behavior/key-press#consumer-key-press) +- [Encoders](feature/encoders) +- Basic [OLED display support](feature/displays) +- [RGB Underglow](feature/underglow) ## Missing Features -- One Shot -- Layer Tap -- Complete split support +- One Shot Keys +- Combo keys +- Macros +- Complete split support (encoders and RGB are not supported on the 'peripheral' side) - Battery reporting -- Low power mode +- Low power sleep states +- Low power mode (to toggle LEDs and screen off) - Shell over BLE ## Code Of Conduct From cf970efb98c5af97955bfffbcebb3b065b16edc4 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 28 Aug 2020 14:15:16 -0400 Subject: [PATCH 048/227] feat(bluetooth): Proper bond management, identity support for non-splits * Add `bt` behavior that can be used to perform certain actions, such as next/prev identity, reset identity, etc. NOTE: Multiple identities is only supported for non-split shields, due to missing Zephyr identity functionality for dual central/peripheral devices. * Proper bond reset tied to action, that honors peripheral bonds, so folks can reset and pair to other hosts, without breaking bonds between splt halves. --- app/CMakeLists.txt | 7 +- app/Kconfig | 29 +- app/dts/behaviors.dtsi | 3 +- app/dts/behaviors/bluetooth.dtsi | 9 + .../behaviors/zmk,behavior-bluetooth.yaml | 8 + app/include/dt-bindings/zmk/bt.h | 17 + app/include/zmk/ble.h | 13 + app/src/behaviors/behavior_bt.c | 62 ++++ app/src/ble.c | 335 ++++++++++++++++-- app/src/split/bluetooth/central.c | 49 ++- docs/docs/behavior/bluetooth.md | 82 +++++ docs/sidebars.js | 1 + 12 files changed, 563 insertions(+), 52 deletions(-) create mode 100644 app/dts/behaviors/bluetooth.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml create mode 100644 app/include/dt-bindings/zmk/bt.h create mode 100644 app/src/behaviors/behavior_bt.c create mode 100644 docs/docs/behavior/bluetooth.md diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 2e24fdc2..0f2d2ba7 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -41,8 +41,11 @@ target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) -target_sources(app PRIVATE src/keymap.c) +if(NOT CONFIG_ZMK_BLE_SPLIT_PERIPHERAL) + target_sources(app PRIVATE src/keymap.c) +endif() target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c) +target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/behaviors/behavior_bt.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c) target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split_listener.c) @@ -57,4 +60,4 @@ target_sources(app PRIVATE src/endpoints.c) target_sources(app PRIVATE src/hid_listener.c) target_sources(app PRIVATE src/main.c) -zephyr_cc_option(-Wfatal-errors) \ No newline at end of file +zephyr_cc_option(-Wfatal-errors) diff --git a/app/Kconfig b/app/Kconfig index 877fce43..b60db056 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -40,8 +40,6 @@ menuconfig ZMK_BLE select BT_PERIPHERAL select BT_GATT_DIS select BT_GATT_BAS - select SETTINGS - # select BT_SETTINGS if ZMK_BLE @@ -49,6 +47,12 @@ config ZMK_BLE_INIT_PRIORITY int "Init Priority" default 50 +config SETTINGS + default y + +config BT_SETTINGS + default y + config SYSTEM_WORKQUEUE_STACK_SIZE default 2048 @@ -103,8 +107,11 @@ config ZMK_SPLIT_BLE_ROLE_CENTRAL if ZMK_SPLIT_BLE_ROLE_CENTRAL +config BT_MAX_PAIRED + default 2 + config BT_MAX_CONN - default 5 + default 2 config BT_MAX_PAIRED # Bump this everywhere once we support switching active connections! @@ -120,15 +127,18 @@ if ZMK_SPLIT_BLE_ROLE_PERIPHERAL config ZMK_USB default n +config BT_MAX_PAIRED + default 1 config BT_MAX_CONN - default 5 + default 2 config BT_GAP_AUTO_UPDATE_CONN_PARAMS default n endif + endchoice endif @@ -138,6 +148,17 @@ endif endmenu +if ZMK_BLE && !ZMK_SPLIT_BLE + +config BT_ID_MAX + default 5 + +# Used to update the name to include the identity used +config BT_DEVICE_NAME_DYNAMIC + default y + +endif + config ZMK_KSCAN_MOCK_DRIVER bool "Enable mock kscan driver to simulate key presses" default n diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index ab70bcc7..202202b4 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -7,4 +7,5 @@ #include #include #include -#include \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/app/dts/behaviors/bluetooth.dtsi b/app/dts/behaviors/bluetooth.dtsi new file mode 100644 index 00000000..ea09f4a2 --- /dev/null +++ b/app/dts/behaviors/bluetooth.dtsi @@ -0,0 +1,9 @@ +/ { + behaviors { + bt: behavior_bluetooth { + compatible = "zmk,behavior-bluetooth"; + label = "BLUETOOTH"; + #binding-cells = <2>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml b/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml new file mode 100644 index 00000000..127ebe0b --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-bluetooth.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2020, Peter Johanson +# SPDX-License-Identifier: MIT + +description: Bluetooth Behavior + +compatible: "zmk,behavior-bluetooth" + +include: two_param.yaml diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h new file mode 100644 index 00000000..6b05ff0c --- /dev/null +++ b/app/include/dt-bindings/zmk/bt.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 Peter Johanson + * + * SPDX-License-Identifier: MIT + */ + +#define BT_RST_CMD 0 +#define BT_IDENT_NEXT_CMD 1 +#define BT_IDENT_PREV_CMD 2 +#define BT_IDENT_SEL_CMD 3 +#define BT_IDENT_CLR_CMD 4 + +#define BT_RST BT_RST_CMD 0 +#define BT_IDENT_NEXT BT_IDENT_NEXT_CMD 0 +#define BT_IDENT_PREV BT_IDENT_PREV_CMD 0 +#define BT_IDENT_SEL BT_IDENT_SEL_CMD +#define BT_IDENT_CLR BT_IDENT_CLR_CMD 0 \ No newline at end of file diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index d0aaa96b..b3762cd4 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -6,7 +6,20 @@ #pragma once +#include #include +int zmk_ble_adv_pause(); +int zmk_ble_adv_resume(); + +int zmk_ble_identity_clear(); +int zmk_ble_identity_next(); +int zmk_ble_identity_prev(); +int zmk_ble_identity_select(u8_t index); + int zmk_ble_unpair_all(); bool zmk_ble_handle_key_user(struct zmk_key_event *key_event); + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) +void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr); +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ \ No newline at end of file diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c new file mode 100644 index 00000000..724d2457 --- /dev/null +++ b/app/src/behaviors/behavior_bt.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Peter Johanson + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_bluetooth + +#include +#include + +#include + +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include + +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t command, u32_t arg) +{ + switch (command) + { + case BT_RST_CMD: + return zmk_ble_unpair_all(); + case BT_IDENT_CLR_CMD: + return zmk_ble_identity_clear(); +#if CONFIG_BT_ID_MAX != 1 + case BT_IDENT_NEXT_CMD: + return zmk_ble_identity_next(); + case BT_IDENT_PREV_CMD: + return zmk_ble_identity_prev(); + case BT_IDENT_SEL_CMD: + return zmk_ble_identity_select(arg); +#endif /* BT_ID_MAX != 1 */ + } + + return -ENOTSUP; +} + +static int behavior_bt_init(struct device *dev) +{ + return 0; +}; + +static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, u32_t arg) +{ + return 0; +} + +static const struct behavior_driver_api behavior_bt_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +DEVICE_AND_API_INIT(behavior_bt, DT_INST_LABEL(0), + behavior_bt_init, + NULL, + NULL, + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &behavior_bt_driver_api); diff --git a/app/src/ble.c b/app/src/ble.c index c4d3efd5..97ff4619 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -8,6 +8,8 @@ #include #include +#include +#include #include #include @@ -15,6 +17,13 @@ #include #include #include +#include + +#if IS_ENABLED(CONFIG_SETTINGS) + +#include + +#endif #include @@ -28,16 +37,249 @@ static struct bt_conn *auth_passkey_entry_conn; static u8_t passkey_entries[6] = {0, 0, 0, 0, 0, 0}; static u8_t passkey_digit = 0; -#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) -#define ZMK_ADV_PARAMS BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | \ - BT_LE_ADV_OPT_USE_NAME | \ - BT_LE_ADV_OPT_ONE_TIME, \ +#define ZMK_BT_LE_ADV_PARAM_INIT(_id, _options, _int_min, _int_max, _peer) \ +{ \ + .id = _id, \ + .sid = 0, \ + .secondary_max_skip = 0, \ + .options = (_options), \ + .interval_min = (_int_min), \ + .interval_max = (_int_max), \ + .peer = (_peer), \ +} + +#define ZMK_BT_LE_ADV_PARAM(_id, _options, _int_min, _int_max, _peer) \ + ((struct bt_le_adv_param[]) { \ + ZMK_BT_LE_ADV_PARAM_INIT(_id, _options, _int_min, _int_max, _peer) \ + }) + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) +#define ZMK_ADV_PARAMS(_id) ZMK_BT_LE_ADV_PARAM(_id, \ + BT_LE_ADV_OPT_CONNECTABLE | \ + BT_LE_ADV_OPT_ONE_TIME | \ + BT_LE_ADV_OPT_USE_NAME, \ BT_GAP_ADV_FAST_INT_MIN_2, \ BT_GAP_ADV_FAST_INT_MAX_2, NULL) #else -#define ZMK_ADV_PARAMS BT_LE_ADV_CONN_NAME +#define ZMK_ADV_PARAMS(_id) ZMK_BT_LE_ADV_PARAM(_id, \ + BT_LE_ADV_OPT_CONNECTABLE | \ + BT_LE_ADV_OPT_USE_NAME, \ + BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, NULL) #endif +static const struct bt_data zmk_ble_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_SOME, +#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) + 0x12, 0x18, /* HID Service */ +#endif + 0x0f, 0x18 /* Battery Service */ + ), +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) + BT_DATA_BYTES(BT_DATA_UUID128_ALL, + ZMK_SPLIT_BT_SERVICE_UUID) +#endif +}; + +#define IDENTITY_COUNT CONFIG_BT_ID_MAX + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) + +static bt_addr_le_t peripheral_addr; + +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ + + +static u8_t active_identity = 0; + +int zmk_ble_adv_pause() +{ + int err = bt_le_adv_stop(); + if (err) { + LOG_ERR("Failed to stop advertising (err %d)", err); + return err; + } + + return 0; +}; + +int zmk_ble_adv_resume() +{ + struct bt_le_adv_param *adv_params = ZMK_ADV_PARAMS(active_identity); + + LOG_DBG(""); + int err = bt_le_adv_start(adv_params, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); + if (err) + { + LOG_ERR("Advertising failed to start (err %d)", err); + return err; + } + + return 0; +}; + +static void disconnect_host_connection(struct bt_conn *conn, void *arg) +{ + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + + if (info.role != BT_CONN_ROLE_SLAVE) { + return; + } + + bt_conn_disconnect(conn, BT_HCI_ERR_LOCALHOST_TERM_CONN); +}; + +static int activate_profile(u8_t index) +{ + int err; + + if (index >= IDENTITY_COUNT) { + return -EINVAL; + } + + if (active_identity != index) { + LOG_DBG("Persisting new active identity"); + active_identity = index; + +#if IS_ENABLED(CONFIG_SETTINGS) + err = settings_save_one("ble/active_identity", &active_identity, sizeof(u8_t)); + if (err) { + LOG_WRN("Failed to persist active_identity (err %d)", err); + } +#endif + +#if IS_ENABLED(CONFIG_BT_DEVICE_NAME_DYNAMIC) + char name[CONFIG_BT_DEVICE_NAME_MAX]; + snprintf(name, sizeof(name), "%s (Profile %d)", CONFIG_ZMK_KEYBOARD_NAME, active_identity + 1); + bt_set_name(name); +#endif /* IS_ENABLED(CONFIG_BT_DEVICE_NAME_DYNAMIC) */ + } + + return zmk_ble_adv_resume(); +}; + +static int deactivate_profile(u8_t index) +{ + int err = zmk_ble_adv_pause(); + if (err) { + LOG_WRN("Failed to pause advertising %d", err); + } + + bt_conn_foreach(BT_CONN_TYPE_ALL, disconnect_host_connection, NULL); + + return 0; +}; + +int zmk_ble_identity_select(u8_t index) +{ + LOG_DBG("index %d", index); + if (index >= IDENTITY_COUNT) { + return -EINVAL; + } + + int err = deactivate_profile(active_identity); + if (err) { + LOG_WRN("Failed to deactivate profile"); + return err; + } + + return activate_profile(index); +}; + +static void unpair_non_peripheral_bonds(const struct bt_bond_info *info, void *user_data) { + char addr[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(&info->addr, addr, sizeof(addr)); + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) + if (!bt_addr_le_cmp(&info->addr, &peripheral_addr)) { + LOG_DBG("Skipping unpairing peripheral %s", log_strdup(addr)); + return; + } +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ + + LOG_DBG("Unpairing %s", log_strdup(addr)); + bt_unpair(active_identity, &info->addr); +} + +int zmk_ble_identity_clear() +{ + LOG_DBG(""); + int err = deactivate_profile(active_identity); + if (err) { + return err; + } + + bt_foreach_bond(active_identity, unpair_non_peripheral_bonds, NULL); + + return activate_profile(active_identity); +}; + +int zmk_ble_identity_next() +{ + LOG_DBG("active_identity %d IDENTITY_COUNT %d", active_identity, IDENTITY_COUNT); + return zmk_ble_identity_select((active_identity + 1) % IDENTITY_COUNT); +} + +int zmk_ble_identity_prev() +{ + LOG_DBG(""); + return zmk_ble_identity_select((active_identity + IDENTITY_COUNT - 1) % IDENTITY_COUNT); +} + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) + +void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) +{ + memcpy(&peripheral_addr, addr, sizeof(bt_addr_le_t)); + settings_save_one("ble/peripheral_address", addr, sizeof(bt_addr_le_t)); +} + +#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ + +#if IS_ENABLED(CONFIG_SETTINGS) + +static int ble_profiles_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) +{ + const char *next; + + LOG_DBG("Setting BLE value %s", log_strdup(name)); + + if (settings_name_steq(name, "active_identity", &next) && !next) { + if (len != sizeof(active_identity)) { + return -EINVAL; + } + + int err = read_cb(cb_arg, &active_identity, sizeof(active_identity)); + if (err <= 0) { + LOG_ERR("Failed to handle profile from settings (err %d)", err); + return err; + } + LOG_DBG("Loaded active identity %d", active_identity); +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) + } else if (settings_name_steq(name, "peripheral_address", &next) && !next) { + if (len != sizeof(bt_addr_le_t)) { + return -EINVAL; + } + + int err = read_cb(cb_arg, &peripheral_addr, sizeof(bt_addr_le_t)); + if (err <= 0) { + LOG_ERR("Failed to handle peripheral address from settings (err %d)", err); + return err; + } +#endif + } + + return 0; +}; + +struct settings_handler profiles_handler = { + .name = "ble", + .h_set = ble_profiles_handle_set +}; +#endif /* IS_ENABLED(CONFIG_SETTINGS) */ + static void connected(struct bt_conn *conn, u8_t err) { char addr[BT_ADDR_LE_STR_LEN]; @@ -71,6 +313,12 @@ static void disconnected(struct bt_conn *conn, u8_t reason) bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason); + +#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) + if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) { + zmk_ble_adv_resume(); + } +#endif } static void security_changed(struct bt_conn *conn, bt_security_t level, @@ -146,19 +394,6 @@ static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { .cancel = auth_cancel, }; -static const struct bt_data zmk_ble_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_SOME, -#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) - 0x12, 0x18, /* HID Service */ -#endif - 0x0f, 0x18 /* Battery Service */ - ), -#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) - BT_DATA_BYTES(BT_DATA_UUID128_ALL, - ZMK_SPLIT_BT_SERVICE_UUID) -#endif -}; static void zmk_ble_ready(int err) { @@ -169,17 +404,42 @@ static void zmk_ble_ready(int err) return; } - err = bt_le_adv_start(ZMK_ADV_PARAMS, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); - if (err) - { - LOG_ERR("Advertising failed to start (err %d)", err); - return; - } + zmk_ble_identity_select(active_identity); } +#if CONFIG_BT_ID_MAX != 1 +static int initialize_identities() +{ + bt_addr_le_t addrs[CONFIG_BT_ID_MAX]; + size_t count = CONFIG_BT_ID_MAX; + + LOG_DBG(""); + bt_id_get(addrs, &count); + + for (int i = 0; i < count; i++) { + char addr[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(&addrs[i], addr, sizeof(addr)); + LOG_DBG("Existing identity %s", log_strdup(addr)); + } + + for (int i = count; i < CONFIG_BT_ID_MAX; i++) { + LOG_DBG("Initializing identity %d", i); + int id = bt_id_create(NULL, NULL); + if (id < 0) { + LOG_ERR("Failed to create new identity with id %d", i); + return id; + } + } + + return 0; +}; +#endif /* CONFIG_BT_ID_MAX != 1 */ + static int zmk_ble_init(struct device *_arg) { - int err = bt_enable(NULL); + int err; + + err = bt_enable(NULL); if (err) { @@ -187,11 +447,23 @@ static int zmk_ble_init(struct device *_arg) return err; } - if (IS_ENABLED(CONFIG_BT_SETTINGS)) - { - settings_load(); +#if IS_ENABLED(CONFIG_SETTINGS) + settings_subsys_init(); + + err = settings_register(&profiles_handler); + if (err) { + LOG_ERR("Failed to setup the profile settings handler (err %d)", err); + return err; } + settings_load(); + +#endif + +#if CONFIG_BT_ID_MAX != 1 + initialize_identities(); +#endif /* CONFIG_BT_ID_MAX != 1 */ + bt_conn_cb_register(&conn_callbacks); bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); @@ -203,7 +475,12 @@ static int zmk_ble_init(struct device *_arg) int zmk_ble_unpair_all() { LOG_DBG(""); - return bt_unpair(BT_ID_DEFAULT, NULL); + int err = bt_unpair(BT_ID_DEFAULT, NULL); + if (err) { + LOG_ERR("Failed to unpair devices (err %d)", err); + } + + return err; }; bool zmk_ble_handle_key_user(struct zmk_key_event *key_event) diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 9e67228e..df8f34ec 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -10,12 +10,14 @@ #include #include #include +#include #include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#include #include #include #include @@ -71,6 +73,18 @@ static u8_t split_central_notify_func(struct bt_conn *conn, return BT_GATT_ITER_CONTINUE; } +static int split_central_subscribe(struct bt_conn *conn) +{ + int err = bt_gatt_subscribe(conn, &subscribe_params); + if (err && err != -EALREADY) { + LOG_ERR("Subscribe failed (err %d)", err); + } else { + LOG_DBG("[SUBSCRIBED]"); + } + + return 0; +} + static u8_t split_central_discovery_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) @@ -112,12 +126,7 @@ static u8_t split_central_discovery_func(struct bt_conn *conn, subscribe_params.value = BT_GATT_CCC_NOTIFY; subscribe_params.ccc_handle = attr->handle; - err = bt_gatt_subscribe(conn, &subscribe_params); - if (err && err != -EALREADY) { - LOG_ERR("Subscribe failed (err %d)", err); - } else { - LOG_DBG("[SUBSCRIBED]"); - } + split_central_subscribe(conn); return BT_GATT_ITER_STOP; } @@ -137,16 +146,20 @@ static void split_central_process_connection(struct bt_conn *conn) { } if (conn == default_conn) { - discover_params.uuid = &uuid.uuid; - discover_params.func = split_central_discovery_func; - discover_params.start_handle = 0x0001; - discover_params.end_handle = 0xffff; - discover_params.type = BT_GATT_DISCOVER_PRIMARY; + if (subscribe_params.value) { + split_central_subscribe(conn); + } else { + discover_params.uuid = &uuid.uuid; + discover_params.func = split_central_discovery_func; + discover_params.start_handle = 0x0001; + discover_params.end_handle = 0xffff; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; - err = bt_gatt_discover(default_conn, &discover_params); - if (err) { - LOG_ERR("Discover failed(err %d)", err); - return; + err = bt_gatt_discover(default_conn, &discover_params); + if (err) { + LOG_ERR("Discover failed(err %d)", err); + return; + } } } @@ -194,6 +207,8 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data) LOG_DBG("Found the split service"); + zmk_ble_set_peripheral_addr(addr); + err = bt_le_scan_stop(); if (err) { LOG_ERR("Stop LE scan failed (err %d)", err); @@ -206,10 +221,11 @@ static bool split_central_eir_found(struct bt_data *data, void *user_data) split_central_process_connection(default_conn); } else { param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400); + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn); if (err) { - LOG_ERR("Create conn failed (err %d)", err); + LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, BT_HCI_OP_LE_CREATE_CONN); start_scan(); } @@ -263,6 +279,7 @@ static void split_central_connected(struct bt_conn *conn, u8_t conn_err) bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + if (conn_err) { LOG_ERR("Failed to connect to %s (%u)", addr, conn_err); diff --git a/docs/docs/behavior/bluetooth.md b/docs/docs/behavior/bluetooth.md new file mode 100644 index 00000000..df8ec26b --- /dev/null +++ b/docs/docs/behavior/bluetooth.md @@ -0,0 +1,82 @@ +--- +title: Bluetooth Behavior +sidebar_label: Bluetooth +--- + +## Summary + +The bluetooth behavior allows management of various settings and states related to the bluetooth connection(s) +between the keyboard and the host. + +## Bluetooth Command Defines + +Bluetooth command defines are provided through the [`dt-bindings/zmk/bt.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/bt.h) header, +which is added at the top of the keymap file: + +``` +#include +``` + +This will allow you to reference the actions defined in this header such as `BT_IDENT_CLR_CMD`. + +Here is a table describing the command for each define: + +| Define | Action | +| ------------------- | ----------------------------------------------------- | +| `BT_IDENT_CLR_CMD` | Clear paired keyboards (for the current identity)[^1] | +| `BT_IDENT_NEXT_CMD` | Switch to the next identity[^1] | +| `BT_IDENT_PREV_CMD` | Switch to the previous identity | +| `BT_IDENT_SEL_CMD` | Switch to a specific numbered identity | +| `BT_RST_CMD` | Hard reset of all bluetooth bonds | + +Because the `BT_IDENT_SEL_CMD` command takes an additional parameter, the numeric index of the identity to select, _all_ the commands for the bluetooth behavior must take that additional parameter, and ignore the value. To make this easier, +there are alias defines that add those default parameters for you: + +| Define | Action | +| --------------- | --------------------------------------------------------------------------------------- | +| `BT_IDENT_CLR` | Alias for `BT_IDENT_CLR_CMD 0` to clear paired keyboards (for the current identity)[^1] | +| `BT_IDENT_NEXT` | Alias for `BT_IDENT_NEXT_CMD 0` to switch to the next identity[^1] | +| `BT_IDENT_PREV` | Alias for `BT_IDENT_PREV_CMD 0` to switch to the previous identity | +| `BT_IDENT_SEL` | Alias for `BT_IDENT_SEL_CMD` to switch to a specific numbered identity | +| `BT_RST` | Alias for `BT_RST_CMD 0` to reset all bonds[^2] | + +[^1]: Multiple keyboard identities/profiles is only support on non-split keyboards as of this time. +[^2]: This may interrupt pairing between both halves of a split keyboard. For split keyboards, it is preferred to use the [/docs/bond-reset] combo to clear bonds on both devices + +## Bluetooth Behavior + +The bluetooth behavior completes an bluetooth action given on press. + +### Behavior Binding + +- Reference: `&bt` +- Parameter #1: The bluetooth command define, e.g. `BT_IDENT_CLR_CMD` or `BT_RST_CMD` +- Parameter #2: The parameter for the command, when used to identify an identity/profile to select, e.g. `0` + +### Examples + +1. Behavior to clear the paired host: + + ``` + &bt BT_IDENT_CLR + ``` + +1. Behavior to hard reset all bonded devices[^2]: + + ``` + &bt BT_IDENT_CLR + ``` + +Examples for non-split keyboards with multiple identities: + +1. Behavior to switch to the next identity: + + ``` + &bt BT_IDENT_NEXT + ``` + +1. Behavior to switch to the specific numbered identity: + + ``` + &bt BT_IDENT_SEL 1 + ``` diff --git a/docs/sidebars.js b/docs/sidebars.js index 6bd3aa40..ace7fa17 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -22,6 +22,7 @@ module.exports = { "behavior/hold-tap", "behavior/mod-tap", "behavior/reset", + "behavior/bluetooth", "behavior/lighting", ], Development: [ From a4d06f69ac9879618e91a9befac6f2e84ef37428 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 31 Aug 2020 16:56:05 -0400 Subject: [PATCH 049/227] fix(bluetooth): Fix max pair settings for non-split. --- app/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index b60db056..3640dc6b 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -107,9 +107,6 @@ config ZMK_SPLIT_BLE_ROLE_CENTRAL if ZMK_SPLIT_BLE_ROLE_CENTRAL -config BT_MAX_PAIRED - default 2 - config BT_MAX_CONN default 2 @@ -153,6 +150,9 @@ if ZMK_BLE && !ZMK_SPLIT_BLE config BT_ID_MAX default 5 +config BT_MAX_PAIRED + default 5 + # Used to update the name to include the identity used config BT_DEVICE_NAME_DYNAMIC default y From fc0812bd2eb08d66819f38bafd1f5d00b933c87b Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 1 Sep 2020 23:22:30 -0400 Subject: [PATCH 050/227] fix(bluetooth): Remove identity, minimal `bt`. * Simplify the `bt` behavior to one current command `BT_CLEAR_BONDS_CMD`. * Simplify BLE code for split and non-split keyboards. * Remove keymap processing from split peripheral side. --- app/CMakeLists.txt | 4 +- app/Kconfig | 23 +---- app/include/dt-bindings/zmk/bt.h | 17 ++-- app/include/zmk/ble.h | 7 +- app/src/behaviors/behavior_bt.c | 16 +--- app/src/ble.c | 158 +++++-------------------------- app/src/split_listener.c | 1 + docs/docs/behavior/bluetooth.md | 58 +++--------- 8 files changed, 52 insertions(+), 232 deletions(-) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 0f2d2ba7..ca2767fd 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -41,9 +41,7 @@ target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) -if(NOT CONFIG_ZMK_BLE_SPLIT_PERIPHERAL) - target_sources(app PRIVATE src/keymap.c) -endif() +target_sources(app PRIVATE src/keymap.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/behaviors/behavior_bt.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c) diff --git a/app/Kconfig b/app/Kconfig index 3640dc6b..11a3cc05 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -40,18 +40,14 @@ menuconfig ZMK_BLE select BT_PERIPHERAL select BT_GATT_DIS select BT_GATT_BAS + select BT_SETTINGS + select SETTINGS if ZMK_BLE config ZMK_BLE_INIT_PRIORITY int "Init Priority" default 50 - -config SETTINGS - default y - -config BT_SETTINGS - default y config SYSTEM_WORKQUEUE_STACK_SIZE default 2048 @@ -144,21 +140,6 @@ endif endmenu - -if ZMK_BLE && !ZMK_SPLIT_BLE - -config BT_ID_MAX - default 5 - -config BT_MAX_PAIRED - default 5 - -# Used to update the name to include the identity used -config BT_DEVICE_NAME_DYNAMIC - default y - -endif - config ZMK_KSCAN_MOCK_DRIVER bool "Enable mock kscan driver to simulate key presses" default n diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index 6b05ff0c..24d27ae6 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -4,14 +4,11 @@ * SPDX-License-Identifier: MIT */ -#define BT_RST_CMD 0 -#define BT_IDENT_NEXT_CMD 1 -#define BT_IDENT_PREV_CMD 2 -#define BT_IDENT_SEL_CMD 3 -#define BT_IDENT_CLR_CMD 4 +#define BT_CLEAR_BONDS_CMD 0 -#define BT_RST BT_RST_CMD 0 -#define BT_IDENT_NEXT BT_IDENT_NEXT_CMD 0 -#define BT_IDENT_PREV BT_IDENT_PREV_CMD 0 -#define BT_IDENT_SEL BT_IDENT_SEL_CMD -#define BT_IDENT_CLR BT_IDENT_CLR_CMD 0 \ No newline at end of file +/* +Note: Some future commands will include additional parameters, so we +defines these aliases up front. +*/ + +#define BT_CLEAR_BONDS BT_CLEAR_BONDS_CMD 0 \ No newline at end of file diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index b3762cd4..62d476ed 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -9,13 +9,8 @@ #include #include -int zmk_ble_adv_pause(); -int zmk_ble_adv_resume(); -int zmk_ble_identity_clear(); -int zmk_ble_identity_next(); -int zmk_ble_identity_prev(); -int zmk_ble_identity_select(u8_t index); +int zmk_ble_clear_bonds(); int zmk_ble_unpair_all(); bool zmk_ble_handle_key_user(struct zmk_key_event *key_event); diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 724d2457..63a1ef19 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -22,18 +22,10 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c { switch (command) { - case BT_RST_CMD: - return zmk_ble_unpair_all(); - case BT_IDENT_CLR_CMD: - return zmk_ble_identity_clear(); -#if CONFIG_BT_ID_MAX != 1 - case BT_IDENT_NEXT_CMD: - return zmk_ble_identity_next(); - case BT_IDENT_PREV_CMD: - return zmk_ble_identity_prev(); - case BT_IDENT_SEL_CMD: - return zmk_ble_identity_select(arg); -#endif /* BT_ID_MAX != 1 */ + case BT_CLEAR_BONDS_CMD: + return zmk_ble_clear_bonds(); + default: + LOG_ERR("Unknown BT command: %d", command); } return -ENOTSUP; diff --git a/app/src/ble.c b/app/src/ble.c index 97ff4619..0aba16c5 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -82,8 +82,6 @@ static const struct bt_data zmk_ble_ad[] = { #endif }; -#define IDENTITY_COUNT CONFIG_BT_ID_MAX - #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) static bt_addr_le_t peripheral_addr; @@ -91,8 +89,6 @@ static bt_addr_le_t peripheral_addr; #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ -static u8_t active_identity = 0; - int zmk_ble_adv_pause() { int err = bt_le_adv_stop(); @@ -106,7 +102,7 @@ int zmk_ble_adv_pause() int zmk_ble_adv_resume() { - struct bt_le_adv_param *adv_params = ZMK_ADV_PARAMS(active_identity); + struct bt_le_adv_param *adv_params = ZMK_ADV_PARAMS(BT_ID_DEFAULT); LOG_DBG(""); int err = bt_le_adv_start(adv_params, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); @@ -131,62 +127,6 @@ static void disconnect_host_connection(struct bt_conn *conn, void *arg) bt_conn_disconnect(conn, BT_HCI_ERR_LOCALHOST_TERM_CONN); }; -static int activate_profile(u8_t index) -{ - int err; - - if (index >= IDENTITY_COUNT) { - return -EINVAL; - } - - if (active_identity != index) { - LOG_DBG("Persisting new active identity"); - active_identity = index; - -#if IS_ENABLED(CONFIG_SETTINGS) - err = settings_save_one("ble/active_identity", &active_identity, sizeof(u8_t)); - if (err) { - LOG_WRN("Failed to persist active_identity (err %d)", err); - } -#endif - -#if IS_ENABLED(CONFIG_BT_DEVICE_NAME_DYNAMIC) - char name[CONFIG_BT_DEVICE_NAME_MAX]; - snprintf(name, sizeof(name), "%s (Profile %d)", CONFIG_ZMK_KEYBOARD_NAME, active_identity + 1); - bt_set_name(name); -#endif /* IS_ENABLED(CONFIG_BT_DEVICE_NAME_DYNAMIC) */ - } - - return zmk_ble_adv_resume(); -}; - -static int deactivate_profile(u8_t index) -{ - int err = zmk_ble_adv_pause(); - if (err) { - LOG_WRN("Failed to pause advertising %d", err); - } - - bt_conn_foreach(BT_CONN_TYPE_ALL, disconnect_host_connection, NULL); - - return 0; -}; - -int zmk_ble_identity_select(u8_t index) -{ - LOG_DBG("index %d", index); - if (index >= IDENTITY_COUNT) { - return -EINVAL; - } - - int err = deactivate_profile(active_identity); - if (err) { - LOG_WRN("Failed to deactivate profile"); - return err; - } - - return activate_profile(index); -}; static void unpair_non_peripheral_bonds(const struct bt_bond_info *info, void *user_data) { char addr[BT_ADDR_LE_STR_LEN]; @@ -200,34 +140,19 @@ static void unpair_non_peripheral_bonds(const struct bt_bond_info *info, void *u #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ LOG_DBG("Unpairing %s", log_strdup(addr)); - bt_unpair(active_identity, &info->addr); + bt_unpair(BT_ID_DEFAULT, &info->addr); } -int zmk_ble_identity_clear() +int zmk_ble_clear_bonds() { LOG_DBG(""); - int err = deactivate_profile(active_identity); - if (err) { - return err; - } + + bt_conn_foreach(BT_ID_DEFAULT, disconnect_host_connection, NULL); + bt_foreach_bond(BT_ID_DEFAULT, unpair_non_peripheral_bonds, NULL); - bt_foreach_bond(active_identity, unpair_non_peripheral_bonds, NULL); - - return activate_profile(active_identity); + return 0; }; -int zmk_ble_identity_next() -{ - LOG_DBG("active_identity %d IDENTITY_COUNT %d", active_identity, IDENTITY_COUNT); - return zmk_ble_identity_select((active_identity + 1) % IDENTITY_COUNT); -} - -int zmk_ble_identity_prev() -{ - LOG_DBG(""); - return zmk_ble_identity_select((active_identity + IDENTITY_COUNT - 1) % IDENTITY_COUNT); -} - #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) @@ -246,19 +171,8 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c LOG_DBG("Setting BLE value %s", log_strdup(name)); - if (settings_name_steq(name, "active_identity", &next) && !next) { - if (len != sizeof(active_identity)) { - return -EINVAL; - } - - int err = read_cb(cb_arg, &active_identity, sizeof(active_identity)); - if (err <= 0) { - LOG_ERR("Failed to handle profile from settings (err %d)", err); - return err; - } - LOG_DBG("Loaded active identity %d", active_identity); #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) - } else if (settings_name_steq(name, "peripheral_address", &next) && !next) { + if (settings_name_steq(name, "peripheral_address", &next) && !next) { if (len != sizeof(bt_addr_le_t)) { return -EINVAL; } @@ -268,8 +182,8 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c LOG_ERR("Failed to handle peripheral address from settings (err %d)", err); return err; } -#endif } +#endif return 0; }; @@ -318,6 +232,8 @@ static void disconnected(struct bt_conn *conn, u8_t reason) if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) { zmk_ble_adv_resume(); } +#else + zmk_ble_adv_resume(); #endif } @@ -404,42 +320,12 @@ static void zmk_ble_ready(int err) return; } - zmk_ble_identity_select(active_identity); + zmk_ble_adv_resume(); } -#if CONFIG_BT_ID_MAX != 1 -static int initialize_identities() -{ - bt_addr_le_t addrs[CONFIG_BT_ID_MAX]; - size_t count = CONFIG_BT_ID_MAX; - - LOG_DBG(""); - bt_id_get(addrs, &count); - - for (int i = 0; i < count; i++) { - char addr[BT_ADDR_LE_STR_LEN]; - bt_addr_le_to_str(&addrs[i], addr, sizeof(addr)); - LOG_DBG("Existing identity %s", log_strdup(addr)); - } - - for (int i = count; i < CONFIG_BT_ID_MAX; i++) { - LOG_DBG("Initializing identity %d", i); - int id = bt_id_create(NULL, NULL); - if (id < 0) { - LOG_ERR("Failed to create new identity with id %d", i); - return id; - } - } - - return 0; -}; -#endif /* CONFIG_BT_ID_MAX != 1 */ - static int zmk_ble_init(struct device *_arg) { - int err; - - err = bt_enable(NULL); + int err = bt_enable(NULL); if (err) { @@ -460,10 +346,6 @@ static int zmk_ble_init(struct device *_arg) #endif -#if CONFIG_BT_ID_MAX != 1 - initialize_identities(); -#endif /* CONFIG_BT_ID_MAX != 1 */ - bt_conn_cb_register(&conn_callbacks); bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); @@ -474,13 +356,17 @@ static int zmk_ble_init(struct device *_arg) int zmk_ble_unpair_all() { - LOG_DBG(""); - int err = bt_unpair(BT_ID_DEFAULT, NULL); - if (err) { - LOG_ERR("Failed to unpair devices (err %d)", err); + int resp = 0; + for (int i = BT_ID_DEFAULT; i < CONFIG_BT_ID_MAX; i++) { + + int err = bt_unpair(BT_ID_DEFAULT, NULL); + if (err) { + resp = err; + LOG_ERR("Failed to unpair devices (err %d)", err); + } } - return err; + return resp; }; bool zmk_ble_handle_key_user(struct zmk_key_event *key_event) diff --git a/app/src/split_listener.c b/app/src/split_listener.c index 46a95e14..ee59c484 100644 --- a/app/src/split_listener.c +++ b/app/src/split_listener.c @@ -21,6 +21,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); int split_listener(const struct zmk_event_header *eh) { + LOG_DBG(""); if (is_position_state_changed(eh)) { const struct position_state_changed *ev = cast_position_state_changed(eh); if (ev->state) { diff --git a/docs/docs/behavior/bluetooth.md b/docs/docs/behavior/bluetooth.md index df8ec26b..f605c962 100644 --- a/docs/docs/behavior/bluetooth.md +++ b/docs/docs/behavior/bluetooth.md @@ -6,7 +6,8 @@ sidebar_label: Bluetooth ## Summary The bluetooth behavior allows management of various settings and states related to the bluetooth connection(s) -between the keyboard and the host. +between the keyboard and the host. As of right now, there is only one such action support, but in the future +more will be added. ## Bluetooth Command Defines @@ -17,31 +18,20 @@ which is added at the top of the keymap file: #include ``` -This will allow you to reference the actions defined in this header such as `BT_IDENT_CLR_CMD`. +This will allow you to reference the actions defined in this header such as `BT_CLEAR_BONDS_CMD`. Here is a table describing the command for each define: -| Define | Action | -| ------------------- | ----------------------------------------------------- | -| `BT_IDENT_CLR_CMD` | Clear paired keyboards (for the current identity)[^1] | -| `BT_IDENT_NEXT_CMD` | Switch to the next identity[^1] | -| `BT_IDENT_PREV_CMD` | Switch to the previous identity | -| `BT_IDENT_SEL_CMD` | Switch to a specific numbered identity | -| `BT_RST_CMD` | Hard reset of all bluetooth bonds | +| Define | Action | +| -------------------- | --------------------------------------------------------- | +| `BT_CLEAR_BONDS_CMD` | Clear bond information between the keyboard and host [^1] | -Because the `BT_IDENT_SEL_CMD` command takes an additional parameter, the numeric index of the identity to select, _all_ the commands for the bluetooth behavior must take that additional parameter, and ignore the value. To make this easier, -there are alias defines that add those default parameters for you: +Because future bluetooth commands will take an additional parameter, it is recommended to use +the following alias in your keymap to avoid having to change it later. -| Define | Action | -| --------------- | --------------------------------------------------------------------------------------- | -| `BT_IDENT_CLR` | Alias for `BT_IDENT_CLR_CMD 0` to clear paired keyboards (for the current identity)[^1] | -| `BT_IDENT_NEXT` | Alias for `BT_IDENT_NEXT_CMD 0` to switch to the next identity[^1] | -| `BT_IDENT_PREV` | Alias for `BT_IDENT_PREV_CMD 0` to switch to the previous identity | -| `BT_IDENT_SEL` | Alias for `BT_IDENT_SEL_CMD` to switch to a specific numbered identity | -| `BT_RST` | Alias for `BT_RST_CMD 0` to reset all bonds[^2] | - -[^1]: Multiple keyboard identities/profiles is only support on non-split keyboards as of this time. -[^2]: This may interrupt pairing between both halves of a split keyboard. For split keyboards, it is preferred to use the [/docs/bond-reset] combo to clear bonds on both devices +| Define | Action | +| ---------------- | ---------------------------------------------------------------------- | +| `BT_CLEAR_BONDS` | Alias for `BT_CLEAR_BONDS_CMD 0` to clear the bond to the current host | ## Bluetooth Behavior @@ -50,33 +40,13 @@ The bluetooth behavior completes an bluetooth action given on press. ### Behavior Binding - Reference: `&bt` -- Parameter #1: The bluetooth command define, e.g. `BT_IDENT_CLR_CMD` or `BT_RST_CMD` -- Parameter #2: The parameter for the command, when used to identify an identity/profile to select, e.g. `0` +- Parameter #1: The bluetooth command define, e.g. `BT_CLEAR_BONDS_CMD` +- Parameter #2: (Reserved for future bluetooth command types) ### Examples 1. Behavior to clear the paired host: ``` - &bt BT_IDENT_CLR - ``` - -1. Behavior to hard reset all bonded devices[^2]: - - ``` - &bt BT_IDENT_CLR - ``` - -Examples for non-split keyboards with multiple identities: - -1. Behavior to switch to the next identity: - - ``` - &bt BT_IDENT_NEXT - ``` - -1. Behavior to switch to the specific numbered identity: - - ``` - &bt BT_IDENT_SEL 1 + &bt BT_CLEAR_BONDS ``` From 13842a8a1e45b399864ba1ae5a759c614313b4db Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 3 Sep 2020 13:21:01 -0400 Subject: [PATCH 051/227] fix(bluetooth): Kconfig to clear bonds on start --- app/Kconfig | 4 ++++ app/src/ble.c | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/app/Kconfig b/app/Kconfig index 11a3cc05..b9d05a99 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -52,6 +52,10 @@ config ZMK_BLE_INIT_PRIORITY config SYSTEM_WORKQUEUE_STACK_SIZE default 2048 +config ZMK_BLE_CLEAR_BONDS_ON_START + bool "Configuration that clears all bond information from the keyboard on startup." + default n + # HID GATT notifications sent this way are *not* picked up by Linux, and possibly others. config BT_GATT_NOTIFY_MULTIPLE default n diff --git a/app/src/ble.c b/app/src/ble.c index 0aba16c5..1e748edf 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -346,6 +346,12 @@ static int zmk_ble_init(struct device *_arg) #endif +#if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) + for (int i = 0; i < 10; i++) { + bt_unpair(i, NULL); + } +#endif + bt_conn_cb_register(&conn_callbacks); bt_conn_auth_cb_register(&zmk_ble_auth_cb_display); From b103eb4b059b60ebff81eb45db8405ed3a381257 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 3 Sep 2020 14:55:15 -0400 Subject: [PATCH 052/227] fix(bluetooth): Delete any previously stored name. --- app/src/ble.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/ble.c b/app/src/ble.c index 1e748edf..f7237625 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -347,6 +347,8 @@ static int zmk_ble_init(struct device *_arg) #endif #if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) + settings_delete("bt/name"); + for (int i = 0; i < 10; i++) { bt_unpair(i, NULL); } From e88d0833c5f8ddd2b8a9b93ab7b6d03c141f8463 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 3 Sep 2020 21:11:21 -0400 Subject: [PATCH 053/227] fix(bluetooth): Log when clearing on start. --- app/src/ble.c | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/ble.c b/app/src/ble.c index f7237625..7ef95ca0 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -347,6 +347,7 @@ static int zmk_ble_init(struct device *_arg) #endif #if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) + LOG_WRN("Clearing all existing BLE bond information from the keyboard"); settings_delete("bt/name"); for (int i = 0; i < 10; i++) { From 39f980a06dac1769e4f09abaf19d3ccbb4b34e67 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 8 Sep 2020 23:26:00 -0400 Subject: [PATCH 054/227] feat(bluetooth): Add back profiles, split fixes. * Add back in profiles, not using Zephyr BT identity infrastructure. * Restore additional `&bt` commands for profile operations. * Fix for split pairing and subscriptions, since Zephyr persists subscriptions across connects. * Remove keymap from peripheral builds, reduces firmware size, and avoids unneeded attempts to send HID data. --- app/CMakeLists.txt | 23 +- app/Kconfig | 26 +- app/include/dt-bindings/zmk/bt.h | 11 +- app/include/zmk/ble.h | 9 +- app/include/zmk/ble/profile.h | 16 ++ .../zmk/events/ble-active-profile-changed.h | 22 ++ app/src/behaviors/behavior_bt.c | 6 + app/src/ble.c | 248 +++++++++++++----- app/src/events/ble_active_profile_changed.c | 10 + app/src/hog.c | 36 ++- app/src/split/bluetooth/central.c | 41 +-- app/src/split/bluetooth/service.c | 6 + app/src/split_listener.c | 4 +- docs/docs/behavior/bluetooth.md | 46 +++- 14 files changed, 376 insertions(+), 128 deletions(-) create mode 100644 app/include/zmk/ble/profile.h create mode 100644 app/include/zmk/events/ble-active-profile-changed.h create mode 100644 app/src/events/ble_active_profile_changed.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index ca2767fd..3e0560b7 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -29,23 +29,26 @@ target_sources(app PRIVATE src/hid.c) target_sources(app PRIVATE src/sensors.c) target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c) target_sources(app PRIVATE src/event_manager.c) +target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c) target_sources(app PRIVATE src/events/position_state_changed.c) target_sources(app PRIVATE src/events/keycode_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/sensor_event.c) -target_sources(app PRIVATE src/behaviors/behavior_key_press.c) -target_sources(app PRIVATE src/behaviors/behavior_reset.c) -target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) -target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) -target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) -target_sources(app PRIVATE src/behaviors/behavior_transparent.c) -target_sources(app PRIVATE src/behaviors/behavior_none.c) -target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) -target_sources(app PRIVATE src/keymap.c) +target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c) +if (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) + target_sources(app PRIVATE src/behaviors/behavior_key_press.c) + target_sources(app PRIVATE src/behaviors/behavior_reset.c) + target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c) + target_sources(app PRIVATE src/behaviors/behavior_momentary_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_toggle_layer.c) + target_sources(app PRIVATE src/behaviors/behavior_transparent.c) + target_sources(app PRIVATE src/behaviors/behavior_none.c) + target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) + target_sources(app PRIVATE src/keymap.c) +endif() target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/behaviors/behavior_bt.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c) -target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c) target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split_listener.c) target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split/bluetooth/service.c) target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL app PRIVATE src/split/bluetooth/central.c) diff --git a/app/Kconfig b/app/Kconfig index b9d05a99..917674d6 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -37,6 +37,7 @@ menuconfig ZMK_BLE select BT select BT_SMP select BT_SMP_SC_PAIR_ONLY + select BT_SMP_APP_PAIRING_ACCEPT select BT_PERIPHERAL select BT_GATT_DIS select BT_GATT_BAS @@ -105,19 +106,9 @@ config ZMK_SPLIT_BLE_ROLE_CENTRAL select BT_CENTRAL select BT_GATT_CLIENT -if ZMK_SPLIT_BLE_ROLE_CENTRAL - -config BT_MAX_CONN - default 2 - -config BT_MAX_PAIRED - # Bump this everywhere once we support switching active connections! - default 2 - -endif - config ZMK_SPLIT_BLE_ROLE_PERIPHERAL bool "Peripheral" + select BT_KEYS_OVERWRITE_OLDEST if ZMK_SPLIT_BLE_ROLE_PERIPHERAL @@ -128,16 +119,25 @@ config BT_MAX_PAIRED default 1 config BT_MAX_CONN - default 2 + default 1 config BT_GAP_AUTO_UPDATE_CONN_PARAMS default n endif - endchoice +if ZMK_BLE && (!ZMK_SPLIT_BLE || ZMK_SPLIT_BLE_ROLE_CENTRAL) + +config BT_MAX_CONN + default 6 + +config BT_MAX_PAIRED + default 5 + +endif + endif endif diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index 24d27ae6..b2899ab4 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -4,11 +4,18 @@ * SPDX-License-Identifier: MIT */ -#define BT_CLEAR_BONDS_CMD 0 +#define BT_CLEAR_BONDS_CMD 0 +#define BT_PROF_NEXT_CMD 1 +#define BT_PROF_PREV_CMD 2 +#define BT_PROF_SEL_CMD 3 +// #define BT_FULL_RESET_CMD 4 /* Note: Some future commands will include additional parameters, so we defines these aliases up front. */ -#define BT_CLEAR_BONDS BT_CLEAR_BONDS_CMD 0 \ No newline at end of file +#define BT_CLEAR_BONDS BT_CLEAR_BONDS_CMD 0 +#define BT_PROF_NEXT BT_PROF_NEXT_CMD 0 +#define BT_PROF_PREV BT_PROF_PREV_CMD 0 +#define BT_PROF_SEL BT_PROF_SEL_CMD \ No newline at end of file diff --git a/app/include/zmk/ble.h b/app/include/zmk/ble.h index 62d476ed..1cf71a77 100644 --- a/app/include/zmk/ble.h +++ b/app/include/zmk/ble.h @@ -6,11 +6,16 @@ #pragma once -#include #include - +#include int zmk_ble_clear_bonds(); +int zmk_ble_prof_next(); +int zmk_ble_prof_prev(); +int zmk_ble_prof_select(u8_t index); + +bt_addr_le_t *zmk_ble_active_profile_addr(); +char *zmk_ble_active_profile_name(); int zmk_ble_unpair_all(); bool zmk_ble_handle_key_user(struct zmk_key_event *key_event); diff --git a/app/include/zmk/ble/profile.h b/app/include/zmk/ble/profile.h new file mode 100644 index 00000000..9a79c6d3 --- /dev/null +++ b/app/include/zmk/ble/profile.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 Peter Johanson + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include + +#define ZMK_BLE_PROFILE_NAME_MAX 15 + +struct zmk_ble_profile { + char name[ZMK_BLE_PROFILE_NAME_MAX]; + bt_addr_le_t peer; +}; diff --git a/app/include/zmk/events/ble-active-profile-changed.h b/app/include/zmk/events/ble-active-profile-changed.h new file mode 100644 index 00000000..c464236f --- /dev/null +++ b/app/include/zmk/events/ble-active-profile-changed.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Peter Johanson + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +#include + + +struct ble_active_profile_changed { + struct zmk_event_header header; + u8_t index; + struct zmk_ble_profile *profile; +}; + +ZMK_EVENT_DECLARE(ble_active_profile_changed); diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 63a1ef19..bf156833 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -24,6 +24,12 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c { case BT_CLEAR_BONDS_CMD: return zmk_ble_clear_bonds(); + case BT_PROF_NEXT_CMD: + return zmk_ble_prof_next(); + case BT_PROF_PREV_CMD: + return zmk_ble_prof_prev(); + case BT_PROF_SEL_CMD: + return zmk_ble_prof_select(arg); default: LOG_ERR("Unknown BT command: %d", command); } diff --git a/app/src/ble.c b/app/src/ble.c index 7ef95ca0..40e05a3a 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -25,49 +25,30 @@ #endif - #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); +#include #include #include +#include +#include static struct bt_conn *auth_passkey_entry_conn; static u8_t passkey_entries[6] = {0, 0, 0, 0, 0, 0}; static u8_t passkey_digit = 0; -#define ZMK_BT_LE_ADV_PARAM_INIT(_id, _options, _int_min, _int_max, _peer) \ -{ \ - .id = _id, \ - .sid = 0, \ - .secondary_max_skip = 0, \ - .options = (_options), \ - .interval_min = (_int_min), \ - .interval_max = (_int_max), \ - .peer = (_peer), \ -} - -#define ZMK_BT_LE_ADV_PARAM(_id, _options, _int_min, _int_max, _peer) \ - ((struct bt_le_adv_param[]) { \ - ZMK_BT_LE_ADV_PARAM_INIT(_id, _options, _int_min, _int_max, _peer) \ - }) - #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) -#define ZMK_ADV_PARAMS(_id) ZMK_BT_LE_ADV_PARAM(_id, \ - BT_LE_ADV_OPT_CONNECTABLE | \ - BT_LE_ADV_OPT_ONE_TIME | \ - BT_LE_ADV_OPT_USE_NAME, \ - BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) +#define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1) #else -#define ZMK_ADV_PARAMS(_id) ZMK_BT_LE_ADV_PARAM(_id, \ - BT_LE_ADV_OPT_CONNECTABLE | \ - BT_LE_ADV_OPT_USE_NAME, \ - BT_GAP_ADV_FAST_INT_MIN_2, \ - BT_GAP_ADV_FAST_INT_MAX_2, NULL) +#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED #endif + +static struct zmk_ble_profile profiles[PROFILE_COUNT]; +static u8_t active_profile; + static const struct bt_data zmk_ble_ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID16_SOME, @@ -88,6 +69,33 @@ static bt_addr_le_t peripheral_addr; #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ +static void raise_profile_changed_event() +{ + struct ble_active_profile_changed *ev = new_ble_active_profile_changed(); + ev->index = active_profile; + ev->profile = &profiles[active_profile]; + + ZMK_EVENT_RAISE(ev); +} + +static bool active_profile_is_open() +{ + return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY); +} + +void set_profile_address(u8_t index, const bt_addr_le_t *addr) +{ + char setting_name[15]; + char addr_str[BT_ADDR_LE_STR_LEN]; + + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + + memcpy(&profiles[index].peer, addr, sizeof(bt_addr_le_t)); + sprintf(setting_name, "ble/profiles/%d", index); + LOG_DBG("Setting profile addr for %s to %s", log_strdup(setting_name), log_strdup(addr_str)); + settings_save_one(setting_name, &profiles[index], sizeof(struct zmk_ble_profile)); + raise_profile_changed_event(); +} int zmk_ble_adv_pause() { @@ -102,10 +110,12 @@ int zmk_ble_adv_pause() int zmk_ble_adv_resume() { - struct bt_le_adv_param *adv_params = ZMK_ADV_PARAMS(BT_ID_DEFAULT); + LOG_DBG("active_profile %d, directed? %s", active_profile, active_profile_is_open() ? "no" : "yes"); - LOG_DBG(""); - int err = bt_le_adv_start(adv_params, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); + int err = bt_le_adv_start( + BT_LE_ADV_CONN_NAME, + zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), + NULL, 0); if (err) { LOG_ERR("Advertising failed to start (err %d)", err); @@ -115,44 +125,54 @@ int zmk_ble_adv_resume() return 0; }; -static void disconnect_host_connection(struct bt_conn *conn, void *arg) -{ - struct bt_conn_info info; - bt_conn_get_info(conn, &info); - - if (info.role != BT_CONN_ROLE_SLAVE) { - return; - } - - bt_conn_disconnect(conn, BT_HCI_ERR_LOCALHOST_TERM_CONN); -}; - - -static void unpair_non_peripheral_bonds(const struct bt_bond_info *info, void *user_data) { - char addr[BT_ADDR_LE_STR_LEN]; - bt_addr_le_to_str(&info->addr, addr, sizeof(addr)); - -#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) - if (!bt_addr_le_cmp(&info->addr, &peripheral_addr)) { - LOG_DBG("Skipping unpairing peripheral %s", log_strdup(addr)); - return; - } -#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ - - LOG_DBG("Unpairing %s", log_strdup(addr)); - bt_unpair(BT_ID_DEFAULT, &info->addr); -} - int zmk_ble_clear_bonds() { LOG_DBG(""); - bt_conn_foreach(BT_ID_DEFAULT, disconnect_host_connection, NULL); - bt_foreach_bond(BT_ID_DEFAULT, unpair_non_peripheral_bonds, NULL); + if (bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY)) { + LOG_DBG("Unpairing!"); + bt_unpair(BT_ID_DEFAULT, &profiles[active_profile].peer); + set_profile_address(active_profile, BT_ADDR_LE_ANY); + } return 0; }; +int zmk_ble_prof_select(u8_t index) +{ + LOG_DBG("profile %d", index); + if (active_profile == index) { + return 0; + } + + active_profile = index; + return settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); + + raise_profile_changed_event(); +}; + +int zmk_ble_prof_next() +{ + LOG_DBG(""); + return zmk_ble_prof_select((active_profile + 1) % PROFILE_COUNT); +}; + +int zmk_ble_prof_prev() +{ + LOG_DBG(""); + return zmk_ble_prof_select((active_profile + PROFILE_COUNT - 1) % PROFILE_COUNT); +}; + +bt_addr_le_t *zmk_ble_active_profile_addr() +{ + return &profiles[active_profile].peer; +} + +char *zmk_ble_active_profile_name() +{ + return profiles[active_profile].name; +} + #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) @@ -171,8 +191,47 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c LOG_DBG("Setting BLE value %s", log_strdup(name)); + if (settings_name_steq(name, "profiles", &next) && next) { + char *endptr; + u8_t idx = strtoul(next, &endptr, 10); + if (*endptr != '\0') { + LOG_WRN("Invalid profile index: %s", log_strdup(next)); + return -EINVAL; + } + + if (len != sizeof(struct zmk_ble_profile)) { + LOG_ERR("Invalid profile size (got %d expected %d)", len, sizeof(struct zmk_ble_profile)); + return -EINVAL; + } + + if (idx >= PROFILE_COUNT) { + LOG_WRN("Profile address for index %d is larger than max of %d", idx, PROFILE_COUNT); + return -EINVAL; + } + + int err = read_cb(cb_arg, &profiles[idx], sizeof(struct zmk_ble_profile)); + if (err <= 0) { + LOG_ERR("Failed to handle profile address from settings (err %d)", err); + return err; + } + + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(&profiles[idx].peer, addr_str, sizeof(addr_str)); + + LOG_DBG("Loaded %s address for profile %d", log_strdup(addr_str), idx); + } else if (settings_name_steq(name, "active_profile", &next) && !next) { + if (len != sizeof(active_profile)) { + return -EINVAL; + } + + int err = read_cb(cb_arg, &active_profile, sizeof(active_profile)); + if (err <= 0) { + LOG_ERR("Failed to handle active profile from settings (err %d)", err); + return err; + } + } #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) - if (settings_name_steq(name, "peripheral_address", &next) && !next) { + else if (settings_name_steq(name, "peripheral_address", &next) && !next) { if (len != sizeof(bt_addr_le_t)) { return -EINVAL; } @@ -197,7 +256,6 @@ struct settings_handler profiles_handler = { static void connected(struct bt_conn *conn, u8_t err) { char addr[BT_ADDR_LE_STR_LEN]; - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (err) @@ -229,11 +287,11 @@ static void disconnected(struct bt_conn *conn, u8_t reason) LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason); #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) - if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) { - zmk_ble_adv_resume(); - } + // if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) { + // zmk_ble_adv_resume(); + // } #else - zmk_ble_adv_resume(); + // zmk_ble_adv_resume(); #endif } @@ -301,7 +359,52 @@ static void auth_cancel(struct bt_conn *conn) LOG_DBG("Pairing cancelled: %s", log_strdup(addr)); } +#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) +static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, const struct bt_conn_pairing_feat *const feat) +{ + struct bt_conn_info info; + bt_conn_get_info(conn, &info); + + LOG_DBG("role %d, open? %s", info.role, active_profile_is_open() ? "yes" : "no"); + if (info.role != BT_CONN_ROLE_SLAVE && !active_profile_is_open()) { + LOG_WRN("Rejecting pairing request to taken profile %d", active_profile); + return BT_SECURITY_ERR_PAIR_NOT_ALLOWED; + } + + return BT_SECURITY_ERR_SUCCESS; +}; +#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */ + +static void auth_pairing_complete(struct bt_conn *conn, bool bonded) +{ + struct bt_conn_info info; + char addr[BT_ADDR_LE_STR_LEN]; + const bt_addr_le_t *dst = bt_conn_get_dst(conn); + + bt_addr_le_to_str(dst, addr, sizeof(addr)); + bt_conn_get_info(conn, &info); + + if (info.role != BT_CONN_ROLE_SLAVE) { + LOG_DBG("SKIPPING FOR ROLE %d", info.role); + return; + } + +#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) + if (!active_profile_is_open()) { + LOG_ERR("Pairing completed but current profile is not open: %s", log_strdup(addr)); + bt_unpair(BT_ID_DEFAULT, dst); + return; + } +#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */ + + set_profile_address(active_profile, dst); +}; + static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { +#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) + .pairing_accept = auth_pairing_accept, +#endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */ + .pairing_complete = auth_pairing_complete, // .passkey_display = auth_passkey_display, #ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY @@ -348,11 +451,20 @@ static int zmk_ble_init(struct device *_arg) #if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START) LOG_WRN("Clearing all existing BLE bond information from the keyboard"); - settings_delete("bt/name"); for (int i = 0; i < 10; i++) { bt_unpair(i, NULL); } + + for (int i = 0; i < PROFILE_COUNT; i++) { + char setting_name[15]; + sprintf(setting_name, "ble/profiles/%d", i); + + err = settings_delete(setting_name); + if (err) { + LOG_ERR("Failed to delete setting: %d", err); + } + } #endif bt_conn_cb_register(&conn_callbacks); diff --git a/app/src/events/ble_active_profile_changed.c b/app/src/events/ble_active_profile_changed.c new file mode 100644 index 00000000..a270a144 --- /dev/null +++ b/app/src/events/ble_active_profile_changed.c @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2020 Peter Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +ZMK_EVENT_IMPL(ble_active_profile_changed); \ No newline at end of file diff --git a/app/src/hog.c b/app/src/hog.c index 92858d56..93e6d9b3 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -6,6 +6,10 @@ #include +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + #include #include @@ -148,12 +152,40 @@ BT_GATT_SERVICE_DEFINE(hog_svc, BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point)); +struct bt_conn *destination_connection() { + struct bt_conn *conn; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + LOG_DBG("Address pointer %p", addr); + if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { + LOG_WRN("Not sending, no active address for current profile"); + return NULL; + } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + LOG_WRN("Not sending, not connected to active profile"); + return NULL; + } + + return conn; + +} + int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report) { - return bt_gatt_notify(NULL, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body)); + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return -ENOTCONN; + } + + LOG_DBG("Sending to NULL? %s", conn == NULL ? "yes" : "no"); + + return bt_gatt_notify(conn, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body)); }; int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { - return bt_gatt_notify(NULL, &hog_svc.attrs[10], report, sizeof(struct zmk_hid_consumer_report_body)); + struct bt_conn *conn = destination_connection(); + if (conn == NULL) { + return -ENOTCONN; + } + + return bt_gatt_notify(conn, &hog_svc.attrs[10], report, sizeof(struct zmk_hid_consumer_report_body)); }; diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index df8f34ec..6d8b4357 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -76,10 +76,19 @@ static u8_t split_central_notify_func(struct bt_conn *conn, static int split_central_subscribe(struct bt_conn *conn) { int err = bt_gatt_subscribe(conn, &subscribe_params); - if (err && err != -EALREADY) { - LOG_ERR("Subscribe failed (err %d)", err); - } else { + switch (err) { + case -EALREADY: + LOG_DBG("[ALREADY SUBSCRIBED]"); + break; + // break; + // bt_gatt_unsubscribe(conn, &subscribe_params); + // return split_central_subscribe(conn); + case 0: LOG_DBG("[SUBSCRIBED]"); + break; + default: + LOG_ERR("Subscribe failed (err %d)", err); + break; } return 0; @@ -145,21 +154,17 @@ static void split_central_process_connection(struct bt_conn *conn) { return; } - if (conn == default_conn) { - if (subscribe_params.value) { - split_central_subscribe(conn); - } else { - discover_params.uuid = &uuid.uuid; - discover_params.func = split_central_discovery_func; - discover_params.start_handle = 0x0001; - discover_params.end_handle = 0xffff; - discover_params.type = BT_GATT_DISCOVER_PRIMARY; + if (conn == default_conn && !subscribe_params.value) { + discover_params.uuid = &uuid.uuid; + discover_params.func = split_central_discovery_func; + discover_params.start_handle = 0x0001; + discover_params.end_handle = 0xffff; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; - err = bt_gatt_discover(default_conn, &discover_params); - if (err) { - LOG_ERR("Discover failed(err %d)", err); - return; - } + err = bt_gatt_discover(default_conn, &discover_params); + if (err) { + LOG_ERR("Discover failed(err %d)", err); + return; } } @@ -281,7 +286,7 @@ static void split_central_connected(struct bt_conn *conn, u8_t conn_err) if (conn_err) { - LOG_ERR("Failed to connect to %s (%u)", addr, conn_err); + LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err); bt_conn_unref(default_conn); default_conn = NULL; diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index 0a5ddb7a..c2f65d28 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -6,6 +6,11 @@ #include #include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + #include #include @@ -28,6 +33,7 @@ static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_ static void split_svc_pos_state_ccc(const struct bt_gatt_attr *attr, u16_t value) { + LOG_DBG("value %d", value); } diff --git a/app/src/split_listener.c b/app/src/split_listener.c index ee59c484..12638073 100644 --- a/app/src/split_listener.c +++ b/app/src/split_listener.c @@ -25,9 +25,9 @@ int split_listener(const struct zmk_event_header *eh) if (is_position_state_changed(eh)) { const struct position_state_changed *ev = cast_position_state_changed(eh); if (ev->state) { - zmk_split_bt_position_pressed(ev->position); + return zmk_split_bt_position_pressed(ev->position); } else { - zmk_split_bt_position_released(ev->position); + return zmk_split_bt_position_released(ev->position); } } return 0; diff --git a/docs/docs/behavior/bluetooth.md b/docs/docs/behavior/bluetooth.md index f605c962..4a121a31 100644 --- a/docs/docs/behavior/bluetooth.md +++ b/docs/docs/behavior/bluetooth.md @@ -6,8 +6,8 @@ sidebar_label: Bluetooth ## Summary The bluetooth behavior allows management of various settings and states related to the bluetooth connection(s) -between the keyboard and the host. As of right now, there is only one such action support, but in the future -more will be added. +between the keyboard and the host. By default, ZMK supports five "profiles" for selecting which bonded host +computer/laptop/keyboard should receive the keyboard input; many of the commands here operation on those profiles. ## Bluetooth Command Defines @@ -22,16 +22,22 @@ This will allow you to reference the actions defined in this header such as `BT_ Here is a table describing the command for each define: -| Define | Action | -| -------------------- | --------------------------------------------------------- | -| `BT_CLEAR_BONDS_CMD` | Clear bond information between the keyboard and host [^1] | +| Define | Action | +| -------------------- | ---------------------------------------------------------------------------------------------- | +| `BT_CLEAR_BONDS_CMD` | Clear bond information between the keyboard and host for the selected profile [^1] | +| `BT_PROF_NEXT_CMD` | Switch to the next profile, cycling through to the first one when the end is reached. | +| `BT_PROF_PREV_CMD` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | +| `BT_PROF_SEL_CMD` | Select the 0-indexed profile by number. | -Because future bluetooth commands will take an additional parameter, it is recommended to use -the following alias in your keymap to avoid having to change it later. +Because at least one bluetooth commands takes an additional parameter, it is recommended to use +the following aliases in your keymap to avoid having to specify an ignored second parameter: -| Define | Action | -| ---------------- | ---------------------------------------------------------------------- | -| `BT_CLEAR_BONDS` | Alias for `BT_CLEAR_BONDS_CMD 0` to clear the bond to the current host | +| Define | Action | +| ---------------- | ---------------------------------------------------------------------------------------- | +| `BT_CLEAR_BONDS` | Alias for `BT_CLEAR_BONDS_CMD 0` to clear the current profile's bond to the current host | +| `BT_PROF_NEXT` | Alias for `BT_PROF_NEXT_CMD 0` to select the next profile | +| `BT_PROF_PREV` | Alias for `BT_PROF_PREV_CMD 0` to select the previous profile | +| `BT_PROF_SEL` | Alias for `BT_PROF_SEL_CMD` to select the given profile, e.g. `&bt BT_PROF_SEL 1` | ## Bluetooth Behavior @@ -45,8 +51,26 @@ The bluetooth behavior completes an bluetooth action given on press. ### Examples -1. Behavior to clear the paired host: +1. Behavior binding to clear the paired host for the selected profile: ``` &bt BT_CLEAR_BONDS ``` + +1. Behavior binding to select the next profile: + + ``` + &bt BT_PROF_NEXT + ``` + +1. Behavior binding to select the previous profile: + + ``` + &bt BT_PROF_NEXT + ``` + +1. Behavior binding to select the 2nd profile (passed parameters are [zero based](https://en.wikipedia.org/wiki/Zero-based_numbering)): + + ``` + &bt BT_PROF_SEL 1 + ``` From fb91be5164a5b6ba78b19c7a2597c13ddd992f81 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Wed, 9 Sep 2020 14:33:09 -0400 Subject: [PATCH 055/227] fix(bluetooth): Configs for non-splits. --- app/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Kconfig b/app/Kconfig index 917674d6..61805656 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -128,6 +128,10 @@ endif endchoice +endif + +endif + if ZMK_BLE && (!ZMK_SPLIT_BLE || ZMK_SPLIT_BLE_ROLE_CENTRAL) config BT_MAX_CONN @@ -138,10 +142,6 @@ config BT_MAX_PAIRED endif -endif - -endif - endmenu config ZMK_KSCAN_MOCK_DRIVER From 652bb6ce05254f8168f279396a50b92d7a2182c3 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sat, 12 Sep 2020 23:48:44 -0400 Subject: [PATCH 056/227] feat(bluetooth): Add new settings_reset shield. * Easy to build board/image that will clear saved profile/bond information for a fresh start for keyboards. --- .github/workflows/build.yml | 1 + .../shields/settings_reset/Kconfig.defconfig | 10 ++++++++ .../shields/settings_reset/Kconfig.shield | 5 ++++ .../settings_reset/settings_reset.conf | 1 + .../settings_reset/settings_reset.keymap | 22 +++++++++++++++++ .../settings_reset/settings_reset.overlay | 24 +++++++++++++++++++ 6 files changed, 63 insertions(+) create mode 100644 app/boards/shields/settings_reset/Kconfig.defconfig create mode 100644 app/boards/shields/settings_reset/Kconfig.shield create mode 100644 app/boards/shields/settings_reset/settings_reset.conf create mode 100644 app/boards/shields/settings_reset/settings_reset.keymap create mode 100644 app/boards/shields/settings_reset/settings_reset.overlay diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c8a711c1..02657c0c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,7 @@ jobs: - lily58_left - lily58_right - romac + - settings_reset include: - board: proton_c shield: clueboard_california diff --git a/app/boards/shields/settings_reset/Kconfig.defconfig b/app/boards/shields/settings_reset/Kconfig.defconfig new file mode 100644 index 00000000..6d050cb4 --- /dev/null +++ b/app/boards/shields/settings_reset/Kconfig.defconfig @@ -0,0 +1,10 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_SETTINGS_RESET + +config ZMK_KEYBOARD_NAME + default "SETTINGS RESET" + +endif + diff --git a/app/boards/shields/settings_reset/Kconfig.shield b/app/boards/shields/settings_reset/Kconfig.shield new file mode 100644 index 00000000..b5ce97f9 --- /dev/null +++ b/app/boards/shields/settings_reset/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_SETTINGS_RESET + def_bool $(shields_list_contains,settings_reset) diff --git a/app/boards/shields/settings_reset/settings_reset.conf b/app/boards/shields/settings_reset/settings_reset.conf new file mode 100644 index 00000000..8052a6cf --- /dev/null +++ b/app/boards/shields/settings_reset/settings_reset.conf @@ -0,0 +1 @@ +CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START=y diff --git a/app/boards/shields/settings_reset/settings_reset.keymap b/app/boards/shields/settings_reset/settings_reset.keymap new file mode 100644 index 00000000..05236445 --- /dev/null +++ b/app/boards/shields/settings_reset/settings_reset.keymap @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &reset + >; + }; + }; +}; + + diff --git a/app/boards/shields/settings_reset/settings_reset.overlay b/app/boards/shields/settings_reset/settings_reset.overlay new file mode 100644 index 00000000..a2b5799b --- /dev/null +++ b/app/boards/shields/settings_reset/settings_reset.overlay @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + label = "KSCAN"; + + input-gpios + = <&pro_micro_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; + }; + +}; + From 6c8b0b53f0dbec695ab967ee947916875ed49352 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 13 Sep 2020 22:20:25 -0400 Subject: [PATCH 057/227] refactor(bluetooth): More concise names. --- app/include/dt-bindings/zmk/bt.h | 16 +++++++------- app/src/behaviors/behavior_bt.c | 8 +++---- docs/docs/behavior/bluetooth.md | 36 ++++++++++++++++---------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index b2899ab4..bf8b4f53 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -4,10 +4,10 @@ * SPDX-License-Identifier: MIT */ -#define BT_CLEAR_BONDS_CMD 0 -#define BT_PROF_NEXT_CMD 1 -#define BT_PROF_PREV_CMD 2 -#define BT_PROF_SEL_CMD 3 +#define BT_CLR_CMD 0 +#define BT_NXT_CMD 1 +#define BT_PRV_CMD 2 +#define BT_SEL_CMD 3 // #define BT_FULL_RESET_CMD 4 /* @@ -15,7 +15,7 @@ Note: Some future commands will include additional parameters, so we defines these aliases up front. */ -#define BT_CLEAR_BONDS BT_CLEAR_BONDS_CMD 0 -#define BT_PROF_NEXT BT_PROF_NEXT_CMD 0 -#define BT_PROF_PREV BT_PROF_PREV_CMD 0 -#define BT_PROF_SEL BT_PROF_SEL_CMD \ No newline at end of file +#define BT_CLR BT_CLR_CMD 0 +#define BT_NXT BT_NXT_CMD 0 +#define BT_PRV BT_PRV_CMD 0 +#define BT_SEL BT_SEL_CMD \ No newline at end of file diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index bf156833..3a5fbfbf 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -22,13 +22,13 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c { switch (command) { - case BT_CLEAR_BONDS_CMD: + case BT_CLR_CMD: return zmk_ble_clear_bonds(); - case BT_PROF_NEXT_CMD: + case BT_NXT_CMD: return zmk_ble_prof_next(); - case BT_PROF_PREV_CMD: + case BT_PRV_CMD: return zmk_ble_prof_prev(); - case BT_PROF_SEL_CMD: + case BT_SEL_CMD: return zmk_ble_prof_select(arg); default: LOG_ERR("Unknown BT command: %d", command); diff --git a/docs/docs/behavior/bluetooth.md b/docs/docs/behavior/bluetooth.md index 4a121a31..f802a9a2 100644 --- a/docs/docs/behavior/bluetooth.md +++ b/docs/docs/behavior/bluetooth.md @@ -18,26 +18,26 @@ which is added at the top of the keymap file: #include ``` -This will allow you to reference the actions defined in this header such as `BT_CLEAR_BONDS_CMD`. +This will allow you to reference the actions defined in this header such as `BT_CLR_CMD`. Here is a table describing the command for each define: -| Define | Action | -| -------------------- | ---------------------------------------------------------------------------------------------- | -| `BT_CLEAR_BONDS_CMD` | Clear bond information between the keyboard and host for the selected profile [^1] | -| `BT_PROF_NEXT_CMD` | Switch to the next profile, cycling through to the first one when the end is reached. | -| `BT_PROF_PREV_CMD` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | -| `BT_PROF_SEL_CMD` | Select the 0-indexed profile by number. | +| Define | Action | +| ------------ | ---------------------------------------------------------------------------------------------- | +| `BT_CLR_CMD` | Clear bond information between the keyboard and host for the selected profile [^1] | +| `BT_NXT_CMD` | Switch to the next profile, cycling through to the first one when the end is reached. | +| `BT_PRV_CMD` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | +| `BT_SEL_CMD` | Select the 0-indexed profile by number. | Because at least one bluetooth commands takes an additional parameter, it is recommended to use the following aliases in your keymap to avoid having to specify an ignored second parameter: -| Define | Action | -| ---------------- | ---------------------------------------------------------------------------------------- | -| `BT_CLEAR_BONDS` | Alias for `BT_CLEAR_BONDS_CMD 0` to clear the current profile's bond to the current host | -| `BT_PROF_NEXT` | Alias for `BT_PROF_NEXT_CMD 0` to select the next profile | -| `BT_PROF_PREV` | Alias for `BT_PROF_PREV_CMD 0` to select the previous profile | -| `BT_PROF_SEL` | Alias for `BT_PROF_SEL_CMD` to select the given profile, e.g. `&bt BT_PROF_SEL 1` | +| Define | Action | +| -------- | -------------------------------------------------------------------------------- | +| `BT_CLR` | Alias for `BT_CLR_CMD 0` to clear the current profile's bond to the current host | +| `BT_NXT` | Alias for `BT_NXT_CMD 0` to select the next profile | +| `BT_PRV` | Alias for `BT_PRV_CMD 0` to select the previous profile | +| `BT_SEL` | Alias for `BT_SEL_CMD` to select the given profile, e.g. `&bt BT_SEL 1` | ## Bluetooth Behavior @@ -46,7 +46,7 @@ The bluetooth behavior completes an bluetooth action given on press. ### Behavior Binding - Reference: `&bt` -- Parameter #1: The bluetooth command define, e.g. `BT_CLEAR_BONDS_CMD` +- Parameter #1: The bluetooth command define, e.g. `BT_CLR_CMD` - Parameter #2: (Reserved for future bluetooth command types) ### Examples @@ -54,23 +54,23 @@ The bluetooth behavior completes an bluetooth action given on press. 1. Behavior binding to clear the paired host for the selected profile: ``` - &bt BT_CLEAR_BONDS + &bt BT_CLR ``` 1. Behavior binding to select the next profile: ``` - &bt BT_PROF_NEXT + &bt BT_NXT ``` 1. Behavior binding to select the previous profile: ``` - &bt BT_PROF_NEXT + &bt BT_NXT ``` 1. Behavior binding to select the 2nd profile (passed parameters are [zero based](https://en.wikipedia.org/wiki/Zero-based_numbering)): ``` - &bt BT_PROF_SEL 1 + &bt BT_SEL 1 ``` From 4658999e31865e54d02955c500c716385e6c69d8 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 13 Sep 2020 22:22:12 -0400 Subject: [PATCH 058/227] fix(bluetooth): Reject pairing to taken profiles. --- app/src/ble.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/ble.c b/app/src/ble.c index 40e05a3a..a2a8207a 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -366,7 +366,7 @@ static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, const stru bt_conn_get_info(conn, &info); LOG_DBG("role %d, open? %s", info.role, active_profile_is_open() ? "yes" : "no"); - if (info.role != BT_CONN_ROLE_SLAVE && !active_profile_is_open()) { + if (info.role == BT_CONN_ROLE_SLAVE && !active_profile_is_open()) { LOG_WRN("Rejecting pairing request to taken profile %d", active_profile); return BT_SECURITY_ERR_PAIR_NOT_ALLOWED; } From 296a89ce6364fd97099d694dddcbb30e8b0925c0 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 10 Sep 2020 15:02:37 -0400 Subject: [PATCH 059/227] feat(ci): Run clang-format to check files. --- .clang-format | 4 ++++ .github/workflows/clang-format-lint.yml | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 .clang-format create mode 100644 .github/workflows/clang-format-lint.yml diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..3c29522a --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +ColumnLimit: 100 +SortIncludes: false diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml new file mode 100644 index 00000000..061bc3da --- /dev/null +++ b/.github/workflows/clang-format-lint.yml @@ -0,0 +1,25 @@ +name: clang-format-lint + +on: + push: + paths: + - "app/boards/**/*.c" + - "app/include/**/*.h" + - "app/src/**" + pull_request: + paths: + - "app/boards/**/*.c" + - "app/include/**/*.h" + - "app/src/**" + +jobs: + build: + runs-on: ubuntu-latest + name: clang-format lint + + steps: + - uses: actions/checkout@v2 + - uses: DoozyX/clang-format-lint-action@v0.9 + with: + source: "./app" + extensions: "h,c" From 191a2d755ad4761bd04a30a113e05119ad7aa61e Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 13 Sep 2020 22:53:24 -0400 Subject: [PATCH 060/227] chore: clang-format the codebase. * Use the LLVM style * Override indent width (8) and column limit (100) * Fixes #142. --- app/boards/arm/dz60rgb/pinmux.c | 54 +- app/boards/arm/nrfmicro/pinmux.c | 27 +- app/boards/arm/planck/pinmux.c | 52 +- app/boards/arm/proton_c/pinmux.c | 54 +- app/drivers/zephyr/ec11.c | 193 +++-- app/drivers/zephyr/ec11.h | 49 +- app/drivers/zephyr/ec11_trigger.c | 170 ++--- app/drivers/zephyr/kscan_gpio_direct.c | 351 ++++----- app/drivers/zephyr/kscan_gpio_matrix.c | 476 ++++++------ app/include/drivers/behavior.h | 69 +- app/include/dt-bindings/zmk/bt.h | 16 +- app/include/dt-bindings/zmk/keys.h | 6 +- app/include/dt-bindings/zmk/reset.h | 9 +- app/include/zmk/event-manager.h | 79 +- .../zmk/events/ble-active-profile-changed.h | 1 - .../zmk/events/keycode-state-changed.h | 6 +- .../zmk/events/modifiers-state-changed.h | 8 +- app/include/zmk/hid.h | 12 +- app/include/zmk/keys.h | 3 +- app/include/zmk/matrix.h | 18 +- app/include/zmk/split/bluetooth/uuid.h | 5 +- app/src/behaviors/behavior_bt.c | 23 +- app/src/behaviors/behavior_hold_tap.c | 714 +++++++++--------- app/src/behaviors/behavior_key_press.c | 48 +- app/src/behaviors/behavior_momentary_layer.c | 35 +- app/src/behaviors/behavior_none.c | 32 +- app/src/behaviors/behavior_reset.c | 40 +- app/src/behaviors/behavior_rgb_underglow.c | 45 +- .../behavior_sensor_rotate_key_press.c | 100 ++- app/src/behaviors/behavior_toggle_layer.c | 33 +- app/src/behaviors/behavior_transparent.c | 32 +- app/src/ble.c | 160 ++-- app/src/ble_unpair_combo.c | 17 +- app/src/display.c | 6 +- app/src/endpoints.c | 21 +- app/src/event_manager.c | 44 +- app/src/hid.c | 87 +-- app/src/hid_listener.c | 136 ++-- app/src/hog.c | 124 ++- app/src/keymap.c | 257 +++---- app/src/kscan.c | 78 +- app/src/kscan_composite.c | 63 +- app/src/kscan_mock.c | 119 ++- app/src/main.c | 20 +- app/src/matrix_transform.c | 11 +- app/src/rgb_underglow.c | 211 +++--- app/src/sensors.c | 32 +- app/src/split/bluetooth/central.c | 423 +++++------ app/src/split/bluetooth/service.c | 39 +- app/src/split_listener.c | 21 +- app/src/usb_hid.c | 89 +-- 51 files changed, 2171 insertions(+), 2547 deletions(-) diff --git a/app/boards/arm/dz60rgb/pinmux.c b/app/boards/arm/dz60rgb/pinmux.c index 60e231b6..f59a31bf 100644 --- a/app/boards/arm/dz60rgb/pinmux.c +++ b/app/boards/arm/dz60rgb/pinmux.c @@ -15,55 +15,53 @@ /* pin assignments for STM32F3DISCOVERY board */ static const struct pin_config pinconf[] = { #if DT_NODE_HAS_STATUS(DT_NODELABEL(usart1), okay) && CONFIG_SERIAL - {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, - {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, + {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, + {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(usart2), okay) && CONFIG_SERIAL - {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, - {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, + {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, + {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c1), okay) && CONFIG_I2C - {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, - {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, + {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, + {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c2), okay) && CONFIG_I2C - {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, - {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, + {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, + {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(spi1), okay) && CONFIG_SPI #ifdef CONFIG_SPI_STM32_USE_HW_SS - {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, + {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ - {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, - {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, - {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, + {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, + {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, + {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(spi2), okay) && CONFIG_SPI #ifdef CONFIG_SPI_STM32_USE_HW_SS - {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, + {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ - {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, - {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, - {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, + {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, + {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, + {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, #endif #ifdef CONFIG_USB_DC_STM32 - {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, - {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, -#endif /* CONFIG_USB_DC_STM32 */ + {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, + {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, +#endif /* CONFIG_USB_DC_STM32 */ #if DT_NODE_HAS_STATUS(DT_NODELABEL(can1), okay) && CONFIG_CAN - {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, - {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, + {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, + {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, #endif }; -static int pinmux_stm32_init(struct device *port) -{ - ARG_UNUSED(port); +static int pinmux_stm32_init(struct device *port) { + ARG_UNUSED(port); - stm32_setup_pins(pinconf, ARRAY_SIZE(pinconf)); + stm32_setup_pins(pinconf, ARRAY_SIZE(pinconf)); - return 0; + return 0; } -SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, - CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); \ No newline at end of file +SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); \ No newline at end of file diff --git a/app/boards/arm/nrfmicro/pinmux.c b/app/boards/arm/nrfmicro/pinmux.c index 0536fe0d..4e330b65 100644 --- a/app/boards/arm/nrfmicro/pinmux.c +++ b/app/boards/arm/nrfmicro/pinmux.c @@ -11,31 +11,30 @@ #include #include -static int pinmux_nrfmicro_init(struct device *port) -{ - ARG_UNUSED(port); +static int pinmux_nrfmicro_init(struct device *port) { + ARG_UNUSED(port); - struct device *p1 = device_get_binding("GPIO_1"); + struct device *p1 = device_get_binding("GPIO_1"); #if CONFIG_BOARD_NRFMICRO_13 - struct device *p0 = device_get_binding("GPIO_0"); - // enable EXT_VCC (use 0 for nRFMicro 1.3, use 1 for nRFMicro 1.1) - gpio_pin_configure(p1, 9, GPIO_OUTPUT); - gpio_pin_set(p1, 9, 0); + struct device *p0 = device_get_binding("GPIO_0"); + // enable EXT_VCC (use 0 for nRFMicro 1.3, use 1 for nRFMicro 1.1) + gpio_pin_configure(p1, 9, GPIO_OUTPUT); + gpio_pin_set(p1, 9, 0); #if CONFIG_BOARD_NRFMICRO_CHARGER - gpio_pin_configure(p0, 5, GPIO_OUTPUT); - gpio_pin_set(p0, 5, 0); + gpio_pin_configure(p0, 5, GPIO_OUTPUT); + gpio_pin_set(p0, 5, 0); #else - gpio_pin_configure(p0, 5, GPIO_INPUT); + gpio_pin_configure(p0, 5, GPIO_INPUT); #endif #else // enable EXT_VCC (use 0 for nRFMicro 1.3, use 1 for nRFMicro 1.1) - gpio_pin_configure(p1, 9, GPIO_OUTPUT); - gpio_pin_set(p1, 9, 1); + gpio_pin_configure(p1, 9, GPIO_OUTPUT); + gpio_pin_set(p1, 9, 1); #endif - return 0; + return 0; } SYS_INIT(pinmux_nrfmicro_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/boards/arm/planck/pinmux.c b/app/boards/arm/planck/pinmux.c index 5df5c90e..61cc16ae 100644 --- a/app/boards/arm/planck/pinmux.c +++ b/app/boards/arm/planck/pinmux.c @@ -15,55 +15,53 @@ /* pin assignments for STM32F3DISCOVERY board */ static const struct pin_config pinconf[] = { #ifdef CONFIG_UART_1 - {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, - {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, + {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, + {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, #endif /* CONFIG_UART_1 */ #ifdef CONFIG_UART_2 - {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, - {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, + {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, + {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, #endif /* CONFIG_UART_2 */ #ifdef CONFIG_I2C_1 - {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, - {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, + {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, + {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, #endif /* CONFIG_I2C_1 */ #ifdef CONFIG_I2C_2 - {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, - {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, + {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, + {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, #endif /* CONFIG_I2C_2 */ #ifdef CONFIG_SPI_1 #ifdef CONFIG_SPI_STM32_USE_HW_SS - {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, + {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ - {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, - {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, - {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, + {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, + {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, + {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, #endif /* CONFIG_SPI_1 */ #ifdef CONFIG_SPI_2 #ifdef CONFIG_SPI_STM32_USE_HW_SS - {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, + {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ - {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, - {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, - {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, + {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, + {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, + {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, #endif /* CONFIG_SPI_2 */ #ifdef CONFIG_USB_DC_STM32 - {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, - {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, + {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, + {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, #endif /* CONFIG_USB_DC_STM32 */ #ifdef CONFIG_CAN_1 - {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, - {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, + {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, + {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, #endif /* CONFIG_CAN_1 */ }; -static int pinmux_stm32_init(struct device *port) -{ - ARG_UNUSED(port); +static int pinmux_stm32_init(struct device *port) { + ARG_UNUSED(port); - stm32_setup_pins(pinconf, ARRAY_SIZE(pinconf)); + stm32_setup_pins(pinconf, ARRAY_SIZE(pinconf)); - return 0; + return 0; } -SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, - CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); +SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); diff --git a/app/boards/arm/proton_c/pinmux.c b/app/boards/arm/proton_c/pinmux.c index a6aaae0a..9ffabd73 100644 --- a/app/boards/arm/proton_c/pinmux.c +++ b/app/boards/arm/proton_c/pinmux.c @@ -15,55 +15,53 @@ /* pin assignments for STM32F3DISCOVERY board */ static const struct pin_config pinconf[] = { #if DT_NODE_HAS_STATUS(DT_NODELABEL(usart1), okay) && CONFIG_SERIAL - {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, - {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, + {STM32_PIN_PC4, STM32F3_PINMUX_FUNC_PC4_USART1_TX}, + {STM32_PIN_PC5, STM32F3_PINMUX_FUNC_PC5_USART1_RX}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(usart2), okay) && CONFIG_SERIAL - {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, - {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, + {STM32_PIN_PA2, STM32F3_PINMUX_FUNC_PA2_USART2_TX}, + {STM32_PIN_PA3, STM32F3_PINMUX_FUNC_PA3_USART2_RX}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c1), okay) && CONFIG_I2C - {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, - {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, + {STM32_PIN_PB6, STM32F3_PINMUX_FUNC_PB6_I2C1_SCL}, + {STM32_PIN_PB7, STM32F3_PINMUX_FUNC_PB7_I2C1_SDA}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(i2c2), okay) && CONFIG_I2C - {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, - {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, + {STM32_PIN_PA9, STM32F3_PINMUX_FUNC_PA9_I2C2_SCL}, + {STM32_PIN_PA10, STM32F3_PINMUX_FUNC_PA10_I2C2_SDA}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(spi1), okay) && CONFIG_SPI #ifdef CONFIG_SPI_STM32_USE_HW_SS - {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, + {STM32_PIN_PA4, STM32F3_PINMUX_FUNC_PA4_SPI1_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ - {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, - {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, - {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, + {STM32_PIN_PA5, STM32F3_PINMUX_FUNC_PA5_SPI1_SCK}, + {STM32_PIN_PA6, STM32F3_PINMUX_FUNC_PA6_SPI1_MISO}, + {STM32_PIN_PA7, STM32F3_PINMUX_FUNC_PA7_SPI1_MOSI}, #endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(spi2), okay) && CONFIG_SPI #ifdef CONFIG_SPI_STM32_USE_HW_SS - {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, + {STM32_PIN_PB12, STM32F3_PINMUX_FUNC_PB12_SPI2_NSS}, #endif /* CONFIG_SPI_STM32_USE_HW_SS */ - {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, - {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, - {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, + {STM32_PIN_PB13, STM32F3_PINMUX_FUNC_PB13_SPI2_SCK}, + {STM32_PIN_PB14, STM32F3_PINMUX_FUNC_PB14_SPI2_MISO}, + {STM32_PIN_PB15, STM32F3_PINMUX_FUNC_PB15_SPI2_MOSI}, #endif #ifdef CONFIG_USB_DC_STM32 - {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, - {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, -#endif /* CONFIG_USB_DC_STM32 */ + {STM32_PIN_PA11, STM32F3_PINMUX_FUNC_PA11_USB_DM}, + {STM32_PIN_PA12, STM32F3_PINMUX_FUNC_PA12_USB_DP}, +#endif /* CONFIG_USB_DC_STM32 */ #if DT_NODE_HAS_STATUS(DT_NODELABEL(can1), okay) && CONFIG_CAN - {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, - {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, + {STM32_PIN_PD0, STM32F3_PINMUX_FUNC_PD0_CAN1_RX}, + {STM32_PIN_PD1, STM32F3_PINMUX_FUNC_PD1_CAN1_TX}, #endif }; -static int pinmux_stm32_init(struct device *port) -{ - ARG_UNUSED(port); +static int pinmux_stm32_init(struct device *port) { + ARG_UNUSED(port); - stm32_setup_pins(pinconf, ARRAY_SIZE(pinconf)); + stm32_setup_pins(pinconf, ARRAY_SIZE(pinconf)); - return 0; + return 0; } -SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, - CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); +SYS_INIT(pinmux_stm32_init, PRE_KERNEL_1, CONFIG_PINMUX_STM32_DEVICE_INITIALIZATION_PRIORITY); diff --git a/app/drivers/zephyr/ec11.c b/app/drivers/zephyr/ec11.c index dfa86efd..a4e96c24 100644 --- a/app/drivers/zephyr/ec11.c +++ b/app/drivers/zephyr/ec11.c @@ -18,136 +18,131 @@ LOG_MODULE_REGISTER(EC11, CONFIG_SENSOR_LOG_LEVEL); -static int ec11_get_ab_state(struct device *dev) -{ - struct ec11_data *drv_data = dev->driver_data; - const struct ec11_config *drv_cfg = dev->config_info; +static int ec11_get_ab_state(struct device *dev) { + struct ec11_data *drv_data = dev->driver_data; + const struct ec11_config *drv_cfg = dev->config_info; - return (gpio_pin_get(drv_data->a, drv_cfg->a_pin) << 1) | gpio_pin_get(drv_data->b, drv_cfg->b_pin); + return (gpio_pin_get(drv_data->a, drv_cfg->a_pin) << 1) | + gpio_pin_get(drv_data->b, drv_cfg->b_pin); } -static int ec11_sample_fetch(struct device *dev, enum sensor_channel chan) -{ - struct ec11_data *drv_data = dev->driver_data; - const struct ec11_config *drv_cfg = dev->config_info; - u8_t val; - s8_t delta; +static int ec11_sample_fetch(struct device *dev, enum sensor_channel chan) { + struct ec11_data *drv_data = dev->driver_data; + const struct ec11_config *drv_cfg = dev->config_info; + u8_t val; + s8_t delta; - __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_ROTATION); + __ASSERT_NO_MSG(chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_ROTATION); - val = ec11_get_ab_state(dev); + val = ec11_get_ab_state(dev); - LOG_DBG("prev: %d, new: %d", drv_data->ab_state, val); + LOG_DBG("prev: %d, new: %d", drv_data->ab_state, val); - switch(val | (drv_data->ab_state << 2)) { - case 0b0010: case 0b0100: case 0b1101: case 0b1011: - delta = -1; - break; - case 0b0001: case 0b0111: case 0b1110: case 0b1000: - delta = 1; - break; - default: - delta = 0; - break; - } + switch (val | (drv_data->ab_state << 2)) { + case 0b0010: + case 0b0100: + case 0b1101: + case 0b1011: + delta = -1; + break; + case 0b0001: + case 0b0111: + case 0b1110: + case 0b1000: + delta = 1; + break; + default: + delta = 0; + break; + } - LOG_DBG("Delta: %d", delta); + LOG_DBG("Delta: %d", delta); - drv_data->pulses += delta; - drv_data->ab_state = val; + drv_data->pulses += delta; + drv_data->ab_state = val; - drv_data->ticks = drv_data->pulses / drv_cfg->resolution; - drv_data->delta = delta; - drv_data->pulses %= drv_cfg->resolution; - - return 0; + drv_data->ticks = drv_data->pulses / drv_cfg->resolution; + drv_data->delta = delta; + drv_data->pulses %= drv_cfg->resolution; + + return 0; } -static int ec11_channel_get(struct device *dev, - enum sensor_channel chan, - struct sensor_value *val) -{ - struct ec11_data *drv_data = dev->driver_data; - - if (chan != SENSOR_CHAN_ROTATION) { - return -ENOTSUP; - } +static int ec11_channel_get(struct device *dev, enum sensor_channel chan, + struct sensor_value *val) { + struct ec11_data *drv_data = dev->driver_data; - val->val1 = drv_data->ticks; - val->val2 = drv_data->delta; - - return 0; + if (chan != SENSOR_CHAN_ROTATION) { + return -ENOTSUP; + } + + val->val1 = drv_data->ticks; + val->val2 = drv_data->delta; + + return 0; } static const struct sensor_driver_api ec11_driver_api = { #ifdef CONFIG_EC11_TRIGGER - .trigger_set = ec11_trigger_set, + .trigger_set = ec11_trigger_set, #endif - .sample_fetch = ec11_sample_fetch, - .channel_get = ec11_channel_get, + .sample_fetch = ec11_sample_fetch, + .channel_get = ec11_channel_get, }; -int ec11_init(struct device *dev) -{ - struct ec11_data *drv_data = dev->driver_data; - const struct ec11_config *drv_cfg = dev->config_info; +int ec11_init(struct device *dev) { + struct ec11_data *drv_data = dev->driver_data; + const struct ec11_config *drv_cfg = dev->config_info; - LOG_DBG("A: %s %d B: %s %d resolution %d", drv_cfg->a_label, drv_cfg->a_pin, drv_cfg->b_label, drv_cfg->b_pin, drv_cfg->resolution); + LOG_DBG("A: %s %d B: %s %d resolution %d", drv_cfg->a_label, drv_cfg->a_pin, drv_cfg->b_label, + drv_cfg->b_pin, drv_cfg->resolution); - drv_data->a = device_get_binding(drv_cfg->a_label); - if (drv_data->a == NULL) { - LOG_ERR("Failed to get pointer to A GPIO device"); - return -EINVAL; - } + drv_data->a = device_get_binding(drv_cfg->a_label); + if (drv_data->a == NULL) { + LOG_ERR("Failed to get pointer to A GPIO device"); + return -EINVAL; + } - drv_data->b = device_get_binding(drv_cfg->b_label); - if (drv_data->b == NULL) { - LOG_ERR("Failed to get pointer to B GPIO device"); - return -EINVAL; - } - - if (gpio_pin_configure(drv_data->a, drv_cfg->a_pin, - drv_cfg->a_flags - | GPIO_INPUT)) { - LOG_DBG("Failed to configure A pin"); - return -EIO; - } - - if (gpio_pin_configure(drv_data->b, drv_cfg->b_pin, - drv_cfg->b_flags - | GPIO_INPUT)) { - LOG_DBG("Failed to configure B pin"); - return -EIO; - } + drv_data->b = device_get_binding(drv_cfg->b_label); + if (drv_data->b == NULL) { + LOG_ERR("Failed to get pointer to B GPIO device"); + return -EINVAL; + } + if (gpio_pin_configure(drv_data->a, drv_cfg->a_pin, drv_cfg->a_flags | GPIO_INPUT)) { + LOG_DBG("Failed to configure A pin"); + return -EIO; + } + if (gpio_pin_configure(drv_data->b, drv_cfg->b_pin, drv_cfg->b_flags | GPIO_INPUT)) { + LOG_DBG("Failed to configure B pin"); + return -EIO; + } #ifdef CONFIG_EC11_TRIGGER - if (ec11_init_interrupt(dev) < 0) { - LOG_DBG("Failed to initialize interrupt!"); - return -EIO; - } + if (ec11_init_interrupt(dev) < 0) { + LOG_DBG("Failed to initialize interrupt!"); + return -EIO; + } #endif - drv_data->ab_state = ec11_get_ab_state(dev); + drv_data->ab_state = ec11_get_ab_state(dev); - return 0; + return 0; } -#define EC11_INST(n) \ - struct ec11_data ec11_data_##n; \ - const struct ec11_config ec11_cfg_##n = { \ - .a_label = DT_INST_GPIO_LABEL(n, a_gpios), \ - .a_pin = DT_INST_GPIO_PIN(n, a_gpios), \ - .a_flags = DT_INST_GPIO_FLAGS(n, a_gpios), \ - .b_label = DT_INST_GPIO_LABEL(n, b_gpios), \ - .b_pin = DT_INST_GPIO_PIN(n, b_gpios), \ - .b_flags = DT_INST_GPIO_FLAGS(n, b_gpios), \ - COND_CODE_0(DT_INST_NODE_HAS_PROP(n, resolution), (1), (DT_INST_PROP(n, resolution))), \ - }; \ - DEVICE_AND_API_INIT(ec11, DT_INST_LABEL(n), ec11_init, \ - &ec11_data_##n, \ - &ec11_cfg_##n, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \ - &ec11_driver_api); +#define EC11_INST(n) \ + struct ec11_data ec11_data_##n; \ + const struct ec11_config ec11_cfg_##n = { \ + .a_label = DT_INST_GPIO_LABEL(n, a_gpios), \ + .a_pin = DT_INST_GPIO_PIN(n, a_gpios), \ + .a_flags = DT_INST_GPIO_FLAGS(n, a_gpios), \ + .b_label = DT_INST_GPIO_LABEL(n, b_gpios), \ + .b_pin = DT_INST_GPIO_PIN(n, b_gpios), \ + .b_flags = DT_INST_GPIO_FLAGS(n, b_gpios), \ + COND_CODE_0(DT_INST_NODE_HAS_PROP(n, resolution), (1), (DT_INST_PROP(n, resolution))), \ + }; \ + DEVICE_AND_API_INIT(ec11, DT_INST_LABEL(n), ec11_init, &ec11_data_##n, &ec11_cfg_##n, \ + POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &ec11_driver_api); DT_INST_FOREACH_STATUS_OKAY(EC11_INST) \ No newline at end of file diff --git a/app/drivers/zephyr/ec11.h b/app/drivers/zephyr/ec11.h index 27fed9bd..e62e7333 100644 --- a/app/drivers/zephyr/ec11.h +++ b/app/drivers/zephyr/ec11.h @@ -11,39 +11,39 @@ #include struct ec11_config { - const char *a_label; - const u8_t a_pin; - const u8_t a_flags; + const char *a_label; + const u8_t a_pin; + const u8_t a_flags; - const char *b_label; - const u8_t b_pin; - const u8_t b_flags; + const char *b_label; + const u8_t b_pin; + const u8_t b_flags; - const u8_t resolution; + const u8_t resolution; }; struct ec11_data { - struct device *a; - struct device *b; - u8_t ab_state; - s8_t pulses; - s8_t ticks; - s8_t delta; + struct device *a; + struct device *b; + u8_t ab_state; + s8_t pulses; + s8_t ticks; + s8_t delta; #ifdef CONFIG_EC11_TRIGGER - struct gpio_callback a_gpio_cb; - struct gpio_callback b_gpio_cb; - struct device *dev; + struct gpio_callback a_gpio_cb; + struct gpio_callback b_gpio_cb; + struct device *dev; - sensor_trigger_handler_t handler; - const struct sensor_trigger *trigger; + sensor_trigger_handler_t handler; + const struct sensor_trigger *trigger; #if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) - K_THREAD_STACK_MEMBER(thread_stack, CONFIG_EC11_THREAD_STACK_SIZE); - struct k_sem gpio_sem; - struct k_thread thread; + K_THREAD_STACK_MEMBER(thread_stack, CONFIG_EC11_THREAD_STACK_SIZE); + struct k_sem gpio_sem; + struct k_thread thread; #elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) - struct k_work work; + struct k_work work; #endif #endif /* CONFIG_EC11_TRIGGER */ @@ -51,9 +51,8 @@ struct ec11_data { #ifdef CONFIG_EC11_TRIGGER -int ec11_trigger_set(struct device *dev, - const struct sensor_trigger *trig, - sensor_trigger_handler_t handler); +int ec11_trigger_set(struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler); int ec11_init_interrupt(struct device *dev); #endif diff --git a/app/drivers/zephyr/ec11_trigger.c b/app/drivers/zephyr/ec11_trigger.c index a04a5610..248ac320 100644 --- a/app/drivers/zephyr/ec11_trigger.c +++ b/app/drivers/zephyr/ec11_trigger.c @@ -19,158 +19,130 @@ extern struct ec11_data ec11_driver; #include LOG_MODULE_DECLARE(EC11, CONFIG_SENSOR_LOG_LEVEL); -static inline void setup_int(struct device *dev, - bool enable) -{ - struct ec11_data *data = dev->driver_data; - const struct ec11_config *cfg = dev->config_info; +static inline void setup_int(struct device *dev, bool enable) { + struct ec11_data *data = dev->driver_data; + const struct ec11_config *cfg = dev->config_info; - LOG_DBG("enabled %s", (enable ? "true" : "false")); + LOG_DBG("enabled %s", (enable ? "true" : "false")); - if (gpio_pin_interrupt_configure(data->a, - cfg->a_pin, - enable - ? GPIO_INT_EDGE_BOTH - : GPIO_INT_DISABLE)) { - LOG_WRN("Unable to set A pin GPIO interrupt"); - } + if (gpio_pin_interrupt_configure(data->a, cfg->a_pin, + enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE)) { + LOG_WRN("Unable to set A pin GPIO interrupt"); + } - if (gpio_pin_interrupt_configure(data->b, - cfg->b_pin, - enable - ? GPIO_INT_EDGE_BOTH - : GPIO_INT_DISABLE)) { - LOG_WRN("Unable to set A pin GPIO interrupt"); - } + if (gpio_pin_interrupt_configure(data->b, cfg->b_pin, + enable ? GPIO_INT_EDGE_BOTH : GPIO_INT_DISABLE)) { + LOG_WRN("Unable to set A pin GPIO interrupt"); + } } -static void ec11_a_gpio_callback(struct device *dev, - struct gpio_callback *cb, u32_t pins) -{ - struct ec11_data *drv_data = - CONTAINER_OF(cb, struct ec11_data, a_gpio_cb); +static void ec11_a_gpio_callback(struct device *dev, struct gpio_callback *cb, u32_t pins) { + struct ec11_data *drv_data = CONTAINER_OF(cb, struct ec11_data, a_gpio_cb); - LOG_DBG(""); + LOG_DBG(""); - setup_int(drv_data->dev, false); + setup_int(drv_data->dev, false); #if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) - k_sem_give(&drv_data->gpio_sem); + k_sem_give(&drv_data->gpio_sem); #elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) - k_work_submit(&drv_data->work); + k_work_submit(&drv_data->work); #endif } -static void ec11_b_gpio_callback(struct device *dev, - struct gpio_callback *cb, u32_t pins) -{ - struct ec11_data *drv_data = - CONTAINER_OF(cb, struct ec11_data, b_gpio_cb); +static void ec11_b_gpio_callback(struct device *dev, struct gpio_callback *cb, u32_t pins) { + struct ec11_data *drv_data = CONTAINER_OF(cb, struct ec11_data, b_gpio_cb); - LOG_DBG(""); + LOG_DBG(""); - setup_int(drv_data->dev, false); + setup_int(drv_data->dev, false); #if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) - k_sem_give(&drv_data->gpio_sem); + k_sem_give(&drv_data->gpio_sem); #elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) - k_work_submit(&drv_data->work); + k_work_submit(&drv_data->work); #endif } -static void ec11_thread_cb(void *arg) -{ - struct device *dev = arg; - struct ec11_data *drv_data = dev->driver_data; +static void ec11_thread_cb(void *arg) { + struct device *dev = arg; + struct ec11_data *drv_data = dev->driver_data; - drv_data->handler(dev, drv_data->trigger); + drv_data->handler(dev, drv_data->trigger); - setup_int(dev, true); + setup_int(dev, true); } #ifdef CONFIG_EC11_TRIGGER_OWN_THREAD -static void ec11_thread(int dev_ptr, int unused) -{ - struct device *dev = INT_TO_POINTER(dev_ptr); - struct ec11_data *drv_data = dev->driver_data; +static void ec11_thread(int dev_ptr, int unused) { + struct device *dev = INT_TO_POINTER(dev_ptr); + struct ec11_data *drv_data = dev->driver_data; - ARG_UNUSED(unused); + ARG_UNUSED(unused); - while (1) { - k_sem_take(&drv_data->gpio_sem, K_FOREVER); - ec11_thread_cb(dev); - } + while (1) { + k_sem_take(&drv_data->gpio_sem, K_FOREVER); + ec11_thread_cb(dev); + } } #endif #ifdef CONFIG_EC11_TRIGGER_GLOBAL_THREAD -static void ec11_work_cb(struct k_work *work) -{ - struct ec11_data *drv_data = - CONTAINER_OF(work, struct ec11_data, work); +static void ec11_work_cb(struct k_work *work) { + struct ec11_data *drv_data = CONTAINER_OF(work, struct ec11_data, work); - LOG_DBG(""); + LOG_DBG(""); - ec11_thread_cb(drv_data->dev); + ec11_thread_cb(drv_data->dev); } #endif -int ec11_trigger_set(struct device *dev, - const struct sensor_trigger *trig, - sensor_trigger_handler_t handler) -{ - struct ec11_data *drv_data = dev->driver_data; +int ec11_trigger_set(struct device *dev, const struct sensor_trigger *trig, + sensor_trigger_handler_t handler) { + struct ec11_data *drv_data = dev->driver_data; - setup_int(dev, false); + setup_int(dev, false); - k_msleep(5); + k_msleep(5); - drv_data->trigger = trig; - drv_data->handler = handler; + drv_data->trigger = trig; + drv_data->handler = handler; - setup_int(dev, true); + setup_int(dev, true); - return 0; + return 0; } -int ec11_init_interrupt(struct device *dev) -{ - struct ec11_data *drv_data = dev->driver_data; - const struct ec11_config *drv_cfg = dev->config_info; +int ec11_init_interrupt(struct device *dev) { + struct ec11_data *drv_data = dev->driver_data; + const struct ec11_config *drv_cfg = dev->config_info; - drv_data->dev = dev; - /* setup gpio interrupt */ + drv_data->dev = dev; + /* setup gpio interrupt */ + gpio_init_callback(&drv_data->a_gpio_cb, ec11_a_gpio_callback, BIT(drv_cfg->a_pin)); - gpio_init_callback(&drv_data->a_gpio_cb, - ec11_a_gpio_callback, - BIT(drv_cfg->a_pin)); + if (gpio_add_callback(drv_data->a, &drv_data->a_gpio_cb) < 0) { + LOG_DBG("Failed to set A callback!"); + return -EIO; + } - if (gpio_add_callback(drv_data->a, &drv_data->a_gpio_cb) < 0) { - LOG_DBG("Failed to set A callback!"); - return -EIO; - } + gpio_init_callback(&drv_data->b_gpio_cb, ec11_b_gpio_callback, BIT(drv_cfg->b_pin)); - gpio_init_callback(&drv_data->b_gpio_cb, - ec11_b_gpio_callback, - BIT(drv_cfg->b_pin)); - - if (gpio_add_callback(drv_data->b, &drv_data->b_gpio_cb) < 0) { - LOG_DBG("Failed to set B callback!"); - return -EIO; - } + if (gpio_add_callback(drv_data->b, &drv_data->b_gpio_cb) < 0) { + LOG_DBG("Failed to set B callback!"); + return -EIO; + } #if defined(CONFIG_EC11_TRIGGER_OWN_THREAD) - k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX); + k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX); - k_thread_create(&drv_data->thread, drv_data->thread_stack, - CONFIG_EC11_THREAD_STACK_SIZE, - (k_thread_entry_t)ec11_thread, dev, - 0, NULL, K_PRIO_COOP(CONFIG_EC11_THREAD_PRIORITY), - 0, K_NO_WAIT); + k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_EC11_THREAD_STACK_SIZE, + (k_thread_entry_t)ec11_thread, dev, 0, NULL, + K_PRIO_COOP(CONFIG_EC11_THREAD_PRIORITY), 0, K_NO_WAIT); #elif defined(CONFIG_EC11_TRIGGER_GLOBAL_THREAD) - k_work_init(&drv_data->work, ec11_work_cb); + k_work_init(&drv_data->work, ec11_work_cb); #endif - return 0; + return 0; } diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c index 6e6a01f3..1e5ab59e 100644 --- a/app/drivers/zephyr/kscan_gpio_direct.c +++ b/app/drivers/zephyr/kscan_gpio_direct.c @@ -15,248 +15,215 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) -struct kscan_gpio_item_config -{ - char *label; - gpio_pin_t pin; - gpio_flags_t flags; +struct kscan_gpio_item_config { + char *label; + gpio_pin_t pin; + gpio_flags_t flags; }; union work_reference { - struct k_delayed_work delayed; - struct k_work direct; + struct k_delayed_work delayed; + struct k_work direct; }; -struct kscan_gpio_config -{ - u8_t num_of_inputs; - u8_t debounce_period; - struct kscan_gpio_item_config inputs[]; +struct kscan_gpio_config { + u8_t num_of_inputs; + u8_t debounce_period; + struct kscan_gpio_item_config inputs[]; }; -struct kscan_gpio_data -{ +struct kscan_gpio_data { #if defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) - struct k_timer poll_timer; + struct k_timer poll_timer; #endif /* defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ - kscan_callback_t callback; - union work_reference work; - struct device *dev; - u32_t pin_state; - struct device *inputs[]; + kscan_callback_t callback; + union work_reference work; + struct device *dev; + u32_t pin_state; + struct device *inputs[]; }; -static struct device **kscan_gpio_input_devices(struct device *dev) -{ - struct kscan_gpio_data *data = dev->driver_data; - return data->inputs; +static struct device **kscan_gpio_input_devices(struct device *dev) { + struct kscan_gpio_data *data = dev->driver_data; + return data->inputs; } -static const struct kscan_gpio_item_config *kscan_gpio_input_configs(struct device *dev) -{ - const struct kscan_gpio_config *cfg = dev->config_info; - return cfg->inputs; +static const struct kscan_gpio_item_config *kscan_gpio_input_configs(struct device *dev) { + const struct kscan_gpio_config *cfg = dev->config_info; + return cfg->inputs; } #if !defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) -struct kscan_gpio_irq_callback -{ - union work_reference *work; - u8_t debounce_period; - struct gpio_callback callback; +struct kscan_gpio_irq_callback { + union work_reference *work; + u8_t debounce_period; + struct gpio_callback callback; }; -static int kscan_gpio_config_interrupts(struct device *dev, gpio_flags_t flags) -{ - const struct kscan_gpio_config *cfg = dev->config_info; - struct device **devices = kscan_gpio_input_devices(dev); - const struct kscan_gpio_item_config *configs = kscan_gpio_input_configs(dev); - - for (int i = 0; i < cfg->num_of_inputs; i++) - { - struct device *dev = devices[i]; - const struct kscan_gpio_item_config *cfg = &configs[i]; +static int kscan_gpio_config_interrupts(struct device *dev, gpio_flags_t flags) { + const struct kscan_gpio_config *cfg = dev->config_info; + struct device **devices = kscan_gpio_input_devices(dev); + const struct kscan_gpio_item_config *configs = kscan_gpio_input_configs(dev); - int err = gpio_pin_interrupt_configure(dev, cfg->pin, flags); + for (int i = 0; i < cfg->num_of_inputs; i++) { + struct device *dev = devices[i]; + const struct kscan_gpio_item_config *cfg = &configs[i]; - if (err) - { - LOG_ERR("Unable to enable matrix GPIO interrupt"); - return err; - } - } + int err = gpio_pin_interrupt_configure(dev, cfg->pin, flags); - return 0; + if (err) { + LOG_ERR("Unable to enable matrix GPIO interrupt"); + return err; + } + } + + return 0; } -static int kscan_gpio_direct_enable(struct device *dev) -{ - return kscan_gpio_config_interrupts(dev, - GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); +static int kscan_gpio_direct_enable(struct device *dev) { + return kscan_gpio_config_interrupts(dev, GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); } -static int kscan_gpio_direct_disable(struct device *dev) -{ - return kscan_gpio_config_interrupts(dev, - GPIO_INT_DISABLE); +static int kscan_gpio_direct_disable(struct device *dev) { + return kscan_gpio_config_interrupts(dev, GPIO_INT_DISABLE); } -static void kscan_gpio_irq_callback_handler(struct device *dev, - struct gpio_callback *cb, gpio_port_pins_t pin) -{ - struct kscan_gpio_irq_callback *data = - CONTAINER_OF(cb, struct kscan_gpio_irq_callback, callback); - - if (data->debounce_period > 0) { - k_delayed_work_cancel(&data->work->delayed); - k_delayed_work_submit(&data->work->delayed, K_MSEC(data->debounce_period)); - } else { - k_work_submit(&data->work->direct); - } +static void kscan_gpio_irq_callback_handler(struct device *dev, struct gpio_callback *cb, + gpio_port_pins_t pin) { + struct kscan_gpio_irq_callback *data = + CONTAINER_OF(cb, struct kscan_gpio_irq_callback, callback); + + if (data->debounce_period > 0) { + k_delayed_work_cancel(&data->work->delayed); + k_delayed_work_submit(&data->work->delayed, K_MSEC(data->debounce_period)); + } else { + k_work_submit(&data->work->direct); + } } -#else /* !defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ +#else /* !defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ -static void kscan_gpio_timer_handler(struct k_timer *timer) -{ - struct kscan_gpio_data *data = - CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer); +static void kscan_gpio_timer_handler(struct k_timer *timer) { + struct kscan_gpio_data *data = CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer); - k_work_submit(&data->work.direct); + k_work_submit(&data->work.direct); } -static int kscan_gpio_direct_enable(struct device *dev) -{ - struct kscan_gpio_data *data = dev->driver_data; - k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); - return 0; +static int kscan_gpio_direct_enable(struct device *dev) { + struct kscan_gpio_data *data = dev->driver_data; + k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); + return 0; } -static int kscan_gpio_direct_disable(struct device *dev) -{ - struct kscan_gpio_data *data = dev->driver_data; - k_timer_stop(&data->poll_timer); - return 0; +static int kscan_gpio_direct_disable(struct device *dev) { + struct kscan_gpio_data *data = dev->driver_data; + k_timer_stop(&data->poll_timer); + return 0; } #endif /* defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ -static int kscan_gpio_direct_configure(struct device *dev, kscan_callback_t callback) -{ - struct kscan_gpio_data *data = dev->driver_data; - if (!callback) - { - return -EINVAL; - } - data->callback = callback; - return 0; +static int kscan_gpio_direct_configure(struct device *dev, kscan_callback_t callback) { + struct kscan_gpio_data *data = dev->driver_data; + if (!callback) { + return -EINVAL; + } + data->callback = callback; + return 0; } -static int kscan_gpio_read(struct device *dev) -{ - struct kscan_gpio_data *data = dev->driver_data; - const struct kscan_gpio_config *cfg = dev->config_info; - u32_t read_state = data->pin_state; - for (int i = 0; i < cfg->num_of_inputs; i++) - { - struct device *in_dev = kscan_gpio_input_devices(dev)[i]; - const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs(dev)[i]; - WRITE_BIT(read_state, i, gpio_pin_get(in_dev, in_cfg->pin) > 0); - } - for (int i = 0; i < cfg->num_of_inputs; i++) - { - bool prev_pressed = BIT(i) & data->pin_state; - bool pressed = BIT(i) & read_state; - if (pressed != prev_pressed) - { - LOG_DBG("Sending event at %d,%d state %s", - 0, i, (pressed ? "on" : "off")); - WRITE_BIT(data->pin_state, i, pressed); - data->callback(dev, 0, i, pressed); - } - } - return 0; +static int kscan_gpio_read(struct device *dev) { + struct kscan_gpio_data *data = dev->driver_data; + const struct kscan_gpio_config *cfg = dev->config_info; + u32_t read_state = data->pin_state; + for (int i = 0; i < cfg->num_of_inputs; i++) { + struct device *in_dev = kscan_gpio_input_devices(dev)[i]; + const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs(dev)[i]; + WRITE_BIT(read_state, i, gpio_pin_get(in_dev, in_cfg->pin) > 0); + } + for (int i = 0; i < cfg->num_of_inputs; i++) { + bool prev_pressed = BIT(i) & data->pin_state; + bool pressed = BIT(i) & read_state; + if (pressed != prev_pressed) { + LOG_DBG("Sending event at %d,%d state %s", 0, i, (pressed ? "on" : "off")); + WRITE_BIT(data->pin_state, i, pressed); + data->callback(dev, 0, i, pressed); + } + } + return 0; } -static void kscan_gpio_work_handler(struct k_work *work) -{ - struct kscan_gpio_data *data = - CONTAINER_OF(work, struct kscan_gpio_data, work); - kscan_gpio_read(data->dev); +static void kscan_gpio_work_handler(struct k_work *work) { + struct kscan_gpio_data *data = CONTAINER_OF(work, struct kscan_gpio_data, work); + kscan_gpio_read(data->dev); } static const struct kscan_driver_api gpio_driver_api = { - .config = kscan_gpio_direct_configure, - .enable_callback = kscan_gpio_direct_enable, - .disable_callback = kscan_gpio_direct_disable, + .config = kscan_gpio_direct_configure, + .enable_callback = kscan_gpio_direct_enable, + .disable_callback = kscan_gpio_direct_disable, }; -#define KSCAN_DIRECT_INPUT_ITEM(i,n) \ - { \ - .label = DT_INST_GPIO_LABEL_BY_IDX(n, input_gpios, i), \ - .pin = DT_INST_GPIO_PIN_BY_IDX(n, input_gpios, i), \ - .flags = DT_INST_GPIO_FLAGS_BY_IDX(n, input_gpios, i), \ - }, +#define KSCAN_DIRECT_INPUT_ITEM(i, n) \ + { \ + .label = DT_INST_GPIO_LABEL_BY_IDX(n, input_gpios, i), \ + .pin = DT_INST_GPIO_PIN_BY_IDX(n, input_gpios, i), \ + .flags = DT_INST_GPIO_FLAGS_BY_IDX(n, input_gpios, i), \ + }, #define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios) -#define GPIO_INST_INIT(n) \ - COND_CODE_0(CONFIG_ZMK_KSCAN_GPIO_POLLING, (static struct kscan_gpio_irq_callback \ - irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \ - static struct kscan_gpio_data kscan_gpio_data_##n = { \ - .inputs = { [INST_INPUT_LEN(n)-1] = NULL } \ - }; \ - static int kscan_gpio_init_##n(struct device *dev) \ - { \ - struct kscan_gpio_data *data = dev->driver_data; \ - const struct kscan_gpio_config *cfg = dev->config_info; \ - int err; \ - struct device **input_devices = kscan_gpio_input_devices(dev); \ - for (int i = 0; i < cfg->num_of_inputs; i++) \ - { \ - const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs(dev)[i]; \ - input_devices[i] = device_get_binding(in_cfg->label); \ - if (!input_devices[i]) \ - { \ - LOG_ERR("Unable to find input GPIO device"); \ - return -EINVAL; \ - } \ - err = gpio_pin_configure(input_devices[i], in_cfg->pin, GPIO_INPUT | in_cfg->flags); \ - if (err) \ - { \ - LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ - return err; \ - } \ - COND_CODE_0(CONFIG_ZMK_KSCAN_GPIO_POLLING, \ - ( \ - irq_callbacks_##n[i].work = &data->work; \ - irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \ - gpio_init_callback(&irq_callbacks_##n[i].callback, kscan_gpio_irq_callback_handler, BIT(in_cfg->pin)); \ - err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ - if (err) \ - { \ - LOG_ERR("Error adding the callback to the column device"); \ - return err; \ - } \ - ), ()) \ - } \ - data->dev = dev; \ - COND_CODE_1(CONFIG_ZMK_KSCAN_GPIO_POLLING, (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ( )) \ - if (cfg->debounce_period > 0) { \ - k_delayed_work_init(&data->work.delayed, kscan_gpio_work_handler); \ - } else { \ - k_work_init(&data->work.direct, kscan_gpio_work_handler); \ - } \ - return 0; \ - } \ - static const struct kscan_gpio_config kscan_gpio_config_##n = { \ - .inputs = { UTIL_LISTIFY(INST_INPUT_LEN(n), KSCAN_DIRECT_INPUT_ITEM, n) }, \ - .num_of_inputs = INST_INPUT_LEN(n), \ - .debounce_period = DT_INST_PROP(n, debounce_period) \ - }; \ - DEVICE_AND_API_INIT(kscan_gpio_##n, DT_INST_LABEL(n), kscan_gpio_init_##n, \ - &kscan_gpio_data_##n, &kscan_gpio_config_##n, \ - POST_KERNEL, CONFIG_ZMK_KSCAN_INIT_PRIORITY, \ - &gpio_driver_api); +#define GPIO_INST_INIT(n) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + (static struct kscan_gpio_irq_callback irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \ + static struct kscan_gpio_data kscan_gpio_data_##n = { \ + .inputs = {[INST_INPUT_LEN(n) - 1] = NULL}}; \ + static int kscan_gpio_init_##n(struct device *dev) { \ + struct kscan_gpio_data *data = dev->driver_data; \ + const struct kscan_gpio_config *cfg = dev->config_info; \ + int err; \ + struct device **input_devices = kscan_gpio_input_devices(dev); \ + for (int i = 0; i < cfg->num_of_inputs; i++) { \ + const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs(dev)[i]; \ + input_devices[i] = device_get_binding(in_cfg->label); \ + if (!input_devices[i]) { \ + LOG_ERR("Unable to find input GPIO device"); \ + return -EINVAL; \ + } \ + err = gpio_pin_configure(input_devices[i], in_cfg->pin, GPIO_INPUT | in_cfg->flags); \ + if (err) { \ + LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ + return err; \ + } \ + COND_CODE_0( \ + CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + (irq_callbacks_##n[i].work = &data->work; \ + irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \ + gpio_init_callback(&irq_callbacks_##n[i].callback, \ + kscan_gpio_irq_callback_handler, BIT(in_cfg->pin)); \ + err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ + if (err) { \ + LOG_ERR("Error adding the callback to the column device"); \ + return err; \ + }), \ + ()) \ + } \ + data->dev = dev; \ + COND_CODE_1(CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ + if (cfg->debounce_period > 0) { \ + k_delayed_work_init(&data->work.delayed, kscan_gpio_work_handler); \ + } else { \ + k_work_init(&data->work.direct, kscan_gpio_work_handler); \ + } \ + return 0; \ + } \ + static const struct kscan_gpio_config kscan_gpio_config_##n = { \ + .inputs = {UTIL_LISTIFY(INST_INPUT_LEN(n), KSCAN_DIRECT_INPUT_ITEM, n)}, \ + .num_of_inputs = INST_INPUT_LEN(n), \ + .debounce_period = DT_INST_PROP(n, debounce_period)}; \ + DEVICE_AND_API_INIT(kscan_gpio_##n, DT_INST_LABEL(n), kscan_gpio_init_##n, \ + &kscan_gpio_data_##n, &kscan_gpio_config_##n, POST_KERNEL, \ + CONFIG_ZMK_KSCAN_INIT_PRIORITY, &gpio_driver_api); DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT) diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index 079a8309..634f694c 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -15,266 +15,248 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) -struct kscan_gpio_item_config -{ - char *label; - gpio_pin_t pin; - gpio_flags_t flags; +struct kscan_gpio_item_config { + char *label; + gpio_pin_t pin; + gpio_flags_t flags; }; - -#define _KSCAN_GPIO_ITEM_CFG_INIT(n, prop, idx) \ - { \ - .label = DT_INST_GPIO_LABEL_BY_IDX(n, prop, idx), \ - .pin = DT_INST_GPIO_PIN_BY_IDX(n, prop, idx), \ - .flags = DT_INST_GPIO_FLAGS_BY_IDX(n, prop, idx), \ - }, +#define _KSCAN_GPIO_ITEM_CFG_INIT(n, prop, idx) \ + { \ + .label = DT_INST_GPIO_LABEL_BY_IDX(n, prop, idx), \ + .pin = DT_INST_GPIO_PIN_BY_IDX(n, prop, idx), \ + .flags = DT_INST_GPIO_FLAGS_BY_IDX(n, prop, idx), \ + }, #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) - + static int kscan_gpio_config_interrupts(struct device **devices, - const struct kscan_gpio_item_config *configs, - size_t len, gpio_flags_t flags) -{ - for (int i = 0; i < len; i++) - { - struct device *dev = devices[i]; - const struct kscan_gpio_item_config *cfg = &configs[i]; + const struct kscan_gpio_item_config *configs, size_t len, + gpio_flags_t flags) { + for (int i = 0; i < len; i++) { + struct device *dev = devices[i]; + const struct kscan_gpio_item_config *cfg = &configs[i]; - int err = gpio_pin_interrupt_configure(dev, cfg->pin, flags); + int err = gpio_pin_interrupt_configure(dev, cfg->pin, flags); - if (err) - { - LOG_ERR("Unable to enable matrix GPIO interrupt"); - return err; - } - } + if (err) { + LOG_ERR("Unable to enable matrix GPIO interrupt"); + return err; + } + } - return 0; + return 0; } #define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios) #define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios) -#define INST_OUTPUT_LEN(n) COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (INST_MATRIX_ROWS(n)), (INST_MATRIX_COLS(n))) -#define INST_INPUT_LEN(n) COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (INST_MATRIX_COLS(n)), (INST_MATRIX_ROWS(n))) +#define INST_OUTPUT_LEN(n) \ + COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (INST_MATRIX_ROWS(n)), \ + (INST_MATRIX_COLS(n))) +#define INST_INPUT_LEN(n) \ + COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (INST_MATRIX_COLS(n)), \ + (INST_MATRIX_ROWS(n))) -#define GPIO_INST_INIT(n) \ - struct kscan_gpio_irq_callback_##n \ - { \ - struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \ - struct gpio_callback callback; \ - }; \ - static struct kscan_gpio_irq_callback_##n \ - irq_callbacks_##n[INST_INPUT_LEN(n)]; \ - struct kscan_gpio_config_##n \ - { \ - struct kscan_gpio_item_config rows[INST_MATRIX_ROWS(n)]; \ - struct kscan_gpio_item_config cols[INST_MATRIX_COLS(n)]; \ - }; \ - struct kscan_gpio_data_##n \ - { \ - kscan_callback_t callback; \ - struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ - bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ - struct device *rows[INST_MATRIX_ROWS(n)]; \ - struct device *cols[INST_MATRIX_COLS(n)]; \ - struct device *dev; \ - }; \ - static struct device **kscan_gpio_input_devices_##n(struct device *dev) \ - { \ - struct kscan_gpio_data_##n *data = dev->driver_data; \ - return (COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (data->cols), (data->rows))); \ - } \ - static const struct kscan_gpio_item_config *kscan_gpio_input_configs_##n(struct device *dev) \ - { \ - const struct kscan_gpio_config_##n *cfg = dev->config_info; \ - return ((COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->cols), (cfg->rows)))); \ - } \ - static struct device **kscan_gpio_output_devices_##n(struct device *dev) \ - { \ - struct kscan_gpio_data_##n *data = dev->driver_data; \ - return (COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (data->rows), (data->cols))); \ - } \ - static const struct kscan_gpio_item_config *kscan_gpio_output_configs_##n(struct device *dev) \ - { \ - const struct kscan_gpio_config_##n *cfg = dev->config_info; \ - return (COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ - } \ - static int kscan_gpio_enable_interrupts_##n(struct device *dev) \ - { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ - } \ - static int kscan_gpio_disable_interrupts_##n(struct device *dev) \ - { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DISABLE); \ - } \ - static void kscan_gpio_set_output_state_##n(struct device *dev, int value) \ - { \ - for (int i = 0; i < INST_OUTPUT_LEN(n); i++) \ - { \ - struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ - const struct kscan_gpio_item_config *cfg = &kscan_gpio_output_configs_##n(dev)[i]; \ - gpio_pin_set(in_dev, cfg->pin, value); \ - } \ - } \ - static void kscan_gpio_set_matrix_state_##n(bool state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)], u32_t input_index, u32_t output_index, bool value) \ - { \ - state[COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (output_index), (input_index))][COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (input_index), (output_index))] = value; \ - } \ - static int kscan_gpio_read_##n(struct device *dev) \ - { \ - bool submit_follow_up_read = false; \ - struct kscan_gpio_data_##n *data = dev->driver_data; \ - static bool read_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ - /* Disable our interrupts temporarily while we scan, to avoid */ \ - /* re-entry while we iterate columns and set them active one by one */ \ - /* to get pressed state for each matrix cell. */ \ - kscan_gpio_disable_interrupts_##n(dev); \ - kscan_gpio_set_output_state_##n(dev, 0); \ - for (int o = 0; o < INST_OUTPUT_LEN(n); o++) \ - { \ - struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ - const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \ - gpio_pin_set(out_dev, out_cfg->pin, 1); \ - for (int i = 0; i < INST_INPUT_LEN(n); i++) \ - { \ - struct device *in_dev = kscan_gpio_input_devices_##n(dev)[i]; \ - const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs_##n(dev)[i]; \ - kscan_gpio_set_matrix_state_##n(read_state, i, o, gpio_pin_get(in_dev, in_cfg->pin) > 0); \ - } \ - gpio_pin_set(out_dev, out_cfg->pin, 0); \ - } \ - /* Set all our outputs as active again, then re-enable interrupts, */ \ - /* so we can trigger interrupts again for future press/release */ \ - kscan_gpio_set_output_state_##n(dev, 1); \ - kscan_gpio_enable_interrupts_##n(dev); \ - for (int r = 0; r < INST_MATRIX_ROWS(n); r++) \ - { \ - for (int c = 0; c < INST_MATRIX_COLS(n); c++) \ - { \ - bool pressed = read_state[r][c]; \ - /* Follow up reads needed because further interrupts won't fire on already tripped input GPIO pins */ \ - submit_follow_up_read = (submit_follow_up_read || pressed); \ - if (pressed != data->matrix_state[r][c]) \ - { \ - LOG_DBG("Sending event at %d,%d state %s", \ - r, c, (pressed ? "on" : "off")); \ - data->matrix_state[r][c] = pressed; \ - data->callback(dev, r, c, pressed); \ - } \ - } \ - } \ - if (submit_follow_up_read) { \ - COND_CODE_0(DT_INST_PROP(n, debounce_period), \ - ({ k_work_submit(&data->work); }), \ - ({ \ - k_delayed_work_cancel(&data->work); \ - k_delayed_work_submit(&data->work, K_MSEC(5)); })) \ - } \ - return 0; \ - } \ - static void kscan_gpio_work_handler_##n(struct k_work *work) \ - { \ - struct kscan_gpio_data_##n *data = \ - CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ - kscan_gpio_read_##n(data->dev); \ - } \ - static void kscan_gpio_irq_callback_handler_##n(struct device *dev, \ - struct gpio_callback *cb, gpio_port_pins_t pin) \ - { \ - struct kscan_gpio_irq_callback_##n *data = \ - CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ - COND_CODE_0(DT_INST_PROP(n, debounce_period), \ - ({ k_work_submit(data->work); }), \ - ({ \ - k_delayed_work_cancel(data->work); \ - k_delayed_work_submit(data->work, K_MSEC(DT_INST_PROP(n, debounce_period))); })) \ - } \ - static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \ - .rows = { [INST_MATRIX_ROWS(n)-1] = NULL}, \ - .cols = { [INST_MATRIX_COLS(n)-1] = NULL }\ - }; \ - static int kscan_gpio_configure_##n(struct device *dev, kscan_callback_t callback) \ - { \ - struct kscan_gpio_data_##n *data = dev->driver_data; \ - if (!callback) \ - { \ - return -EINVAL; \ - } \ - data->callback = callback; \ - return 0; \ - }; \ - static int kscan_gpio_enable_##n(struct device *dev) \ - { \ - int err = kscan_gpio_enable_interrupts_##n(dev); \ - if (err) { return err; } \ - return kscan_gpio_read_##n(dev); \ - }; \ - static int kscan_gpio_init_##n(struct device *dev) \ - { \ - struct kscan_gpio_data_##n *data = dev->driver_data; \ - int err; \ - struct device **input_devices = kscan_gpio_input_devices_##n(dev); \ - for (int i = 0; i < INST_INPUT_LEN(n); i++) \ - { \ - const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs_##n(dev)[i]; \ - input_devices[i] = device_get_binding(in_cfg->label); \ - if (!input_devices[i]) \ - { \ - LOG_ERR("Unable to find input GPIO device"); \ - return -EINVAL; \ - } \ - err = gpio_pin_configure(input_devices[i], in_cfg->pin, GPIO_INPUT | in_cfg->flags); \ - if (err) \ - { \ - LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ - return err; \ - } \ - irq_callbacks_##n[i].work = &data->work; \ - gpio_init_callback(&irq_callbacks_##n[i].callback, kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \ - err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ - if (err) \ - { \ - LOG_ERR("Error adding the callback to the column device"); \ - return err; \ - } \ - } \ - struct device **output_devices = kscan_gpio_output_devices_##n(dev); \ - for (int o = 0; o < INST_OUTPUT_LEN(n); o++) \ - { \ - const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \ - output_devices[o] = device_get_binding(out_cfg->label); \ - if (!output_devices[o]) \ - { \ - LOG_ERR("Unable to find output GPIO device"); \ - return -EINVAL; \ - } \ - err = gpio_pin_configure(output_devices[o], out_cfg->pin, GPIO_OUTPUT_ACTIVE | out_cfg->flags); \ - if (err) \ - { \ - LOG_ERR("Unable to configure pin %d on %s for output", out_cfg->pin, out_cfg->label); \ - return err; \ - } \ - } \ - data->dev = dev; \ - (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))(&data->work, kscan_gpio_work_handler_##n); \ - return 0; \ - } \ - static const struct kscan_driver_api gpio_driver_api_##n = { \ - .config = kscan_gpio_configure_##n, \ - .enable_callback = kscan_gpio_enable_##n, \ - .disable_callback = kscan_gpio_disable_interrupts_##n, \ - }; \ - static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ - .rows = { UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n) }, \ - .cols = { UTIL_LISTIFY(INST_MATRIX_COLS(n), _KSCAN_GPIO_COL_CFG_INIT, n) }, \ - }; \ - DEVICE_AND_API_INIT(kscan_gpio_##n, DT_INST_LABEL(n), kscan_gpio_init_##n, \ - &kscan_gpio_data_##n, &kscan_gpio_config_##n, \ - APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \ - &gpio_driver_api_##n); +#define GPIO_INST_INIT(n) \ + struct kscan_gpio_irq_callback_##n { \ + struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \ + struct gpio_callback callback; \ + }; \ + static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)]; \ + struct kscan_gpio_config_##n { \ + struct kscan_gpio_item_config rows[INST_MATRIX_ROWS(n)]; \ + struct kscan_gpio_item_config cols[INST_MATRIX_COLS(n)]; \ + }; \ + struct kscan_gpio_data_##n { \ + kscan_callback_t callback; \ + struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ + bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ + struct device *rows[INST_MATRIX_ROWS(n)]; \ + struct device *cols[INST_MATRIX_COLS(n)]; \ + struct device *dev; \ + }; \ + static struct device **kscan_gpio_input_devices_##n(struct device *dev) { \ + struct kscan_gpio_data_##n *data = dev->driver_data; \ + return (COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (data->cols), \ + (data->rows))); \ + } \ + static const struct kscan_gpio_item_config *kscan_gpio_input_configs_##n(struct device *dev) { \ + const struct kscan_gpio_config_##n *cfg = dev->config_info; \ + return (( \ + COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->cols), (cfg->rows)))); \ + } \ + static struct device **kscan_gpio_output_devices_##n(struct device *dev) { \ + struct kscan_gpio_data_##n *data = dev->driver_data; \ + return (COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (data->rows), \ + (data->cols))); \ + } \ + static const struct kscan_gpio_item_config *kscan_gpio_output_configs_##n( \ + struct device *dev) { \ + const struct kscan_gpio_config_##n *cfg = dev->config_info; \ + return ( \ + COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ + } \ + static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ + GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ + } \ + static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ + GPIO_INT_DISABLE); \ + } \ + static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ + for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ + struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ + const struct kscan_gpio_item_config *cfg = &kscan_gpio_output_configs_##n(dev)[i]; \ + gpio_pin_set(in_dev, cfg->pin, value); \ + } \ + } \ + static void kscan_gpio_set_matrix_state_##n( \ + bool state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)], u32_t input_index, \ + u32_t output_index, bool value) { \ + state[COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (output_index), \ + (input_index))] \ + [COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (input_index), \ + (output_index))] = value; \ + } \ + static int kscan_gpio_read_##n(struct device *dev) { \ + bool submit_follow_up_read = false; \ + struct kscan_gpio_data_##n *data = dev->driver_data; \ + static bool read_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ + /* Disable our interrupts temporarily while we scan, to avoid */ \ + /* re-entry while we iterate columns and set them active one by one */ \ + /* to get pressed state for each matrix cell. */ \ + kscan_gpio_disable_interrupts_##n(dev); \ + kscan_gpio_set_output_state_##n(dev, 0); \ + for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ + struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ + const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \ + gpio_pin_set(out_dev, out_cfg->pin, 1); \ + for (int i = 0; i < INST_INPUT_LEN(n); i++) { \ + struct device *in_dev = kscan_gpio_input_devices_##n(dev)[i]; \ + const struct kscan_gpio_item_config *in_cfg = \ + &kscan_gpio_input_configs_##n(dev)[i]; \ + kscan_gpio_set_matrix_state_##n(read_state, i, o, \ + gpio_pin_get(in_dev, in_cfg->pin) > 0); \ + } \ + gpio_pin_set(out_dev, out_cfg->pin, 0); \ + } \ + /* Set all our outputs as active again, then re-enable interrupts, */ \ + /* so we can trigger interrupts again for future press/release */ \ + kscan_gpio_set_output_state_##n(dev, 1); \ + kscan_gpio_enable_interrupts_##n(dev); \ + for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ + for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ + bool pressed = read_state[r][c]; \ + /* Follow up reads needed because further interrupts won't fire on already tripped \ + * input GPIO pins */ \ + submit_follow_up_read = (submit_follow_up_read || pressed); \ + if (pressed != data->matrix_state[r][c]) { \ + LOG_DBG("Sending event at %d,%d state %s", r, c, (pressed ? "on" : "off")); \ + data->matrix_state[r][c] = pressed; \ + data->callback(dev, r, c, pressed); \ + } \ + } \ + } \ + if (submit_follow_up_read) { \ + COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(&data->work); }), ({ \ + k_delayed_work_cancel(&data->work); \ + k_delayed_work_submit(&data->work, K_MSEC(5)); \ + })) \ + } \ + return 0; \ + } \ + static void kscan_gpio_work_handler_##n(struct k_work *work) { \ + struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ + kscan_gpio_read_##n(data->dev); \ + } \ + static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \ + gpio_port_pins_t pin) { \ + struct kscan_gpio_irq_callback_##n *data = \ + CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ + COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ + k_delayed_work_cancel(data->work); \ + k_delayed_work_submit(data->work, \ + K_MSEC(DT_INST_PROP(n, debounce_period))); \ + })) \ + } \ + static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \ + .rows = {[INST_MATRIX_ROWS(n) - 1] = NULL}, .cols = {[INST_MATRIX_COLS(n) - 1] = NULL}}; \ + static int kscan_gpio_configure_##n(struct device *dev, kscan_callback_t callback) { \ + struct kscan_gpio_data_##n *data = dev->driver_data; \ + if (!callback) { \ + return -EINVAL; \ + } \ + data->callback = callback; \ + return 0; \ + }; \ + static int kscan_gpio_enable_##n(struct device *dev) { \ + int err = kscan_gpio_enable_interrupts_##n(dev); \ + if (err) { \ + return err; \ + } \ + return kscan_gpio_read_##n(dev); \ + }; \ + static int kscan_gpio_init_##n(struct device *dev) { \ + struct kscan_gpio_data_##n *data = dev->driver_data; \ + int err; \ + struct device **input_devices = kscan_gpio_input_devices_##n(dev); \ + for (int i = 0; i < INST_INPUT_LEN(n); i++) { \ + const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs_##n(dev)[i]; \ + input_devices[i] = device_get_binding(in_cfg->label); \ + if (!input_devices[i]) { \ + LOG_ERR("Unable to find input GPIO device"); \ + return -EINVAL; \ + } \ + err = gpio_pin_configure(input_devices[i], in_cfg->pin, GPIO_INPUT | in_cfg->flags); \ + if (err) { \ + LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ + return err; \ + } \ + irq_callbacks_##n[i].work = &data->work; \ + gpio_init_callback(&irq_callbacks_##n[i].callback, \ + kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \ + err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ + if (err) { \ + LOG_ERR("Error adding the callback to the column device"); \ + return err; \ + } \ + } \ + struct device **output_devices = kscan_gpio_output_devices_##n(dev); \ + for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ + const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \ + output_devices[o] = device_get_binding(out_cfg->label); \ + if (!output_devices[o]) { \ + LOG_ERR("Unable to find output GPIO device"); \ + return -EINVAL; \ + } \ + err = gpio_pin_configure(output_devices[o], out_cfg->pin, \ + GPIO_OUTPUT_ACTIVE | out_cfg->flags); \ + if (err) { \ + LOG_ERR("Unable to configure pin %d on %s for output", out_cfg->pin, \ + out_cfg->label); \ + return err; \ + } \ + } \ + data->dev = dev; \ + (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \ + &data->work, kscan_gpio_work_handler_##n); \ + return 0; \ + } \ + static const struct kscan_driver_api gpio_driver_api_##n = { \ + .config = kscan_gpio_configure_##n, \ + .enable_callback = kscan_gpio_enable_##n, \ + .disable_callback = kscan_gpio_disable_interrupts_##n, \ + }; \ + static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ + .rows = {UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n)}, \ + .cols = {UTIL_LISTIFY(INST_MATRIX_COLS(n), _KSCAN_GPIO_COL_CFG_INIT, n)}, \ + }; \ + DEVICE_AND_API_INIT(kscan_gpio_##n, DT_INST_LABEL(n), kscan_gpio_init_##n, \ + &kscan_gpio_data_##n, &kscan_gpio_config_##n, APPLICATION, \ + CONFIG_APPLICATION_INIT_PRIORITY, &gpio_driver_api_##n); DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT) diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index 617b5ab5..45b8bea7 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -19,19 +19,20 @@ * (Internal use only.) */ -typedef int (*behavior_keymap_binding_callback_t)(struct device *dev, u32_t position, u32_t param1, u32_t param2); -typedef int (*behavior_sensor_keymap_binding_callback_t)(struct device *dev, struct device *sensor, u32_t param1, u32_t param2); +typedef int (*behavior_keymap_binding_callback_t)(struct device *dev, u32_t position, u32_t param1, + u32_t param2); +typedef int (*behavior_sensor_keymap_binding_callback_t)(struct device *dev, struct device *sensor, + u32_t param1, u32_t param2); __subsystem struct behavior_driver_api { - behavior_keymap_binding_callback_t binding_pressed; - behavior_keymap_binding_callback_t binding_released; - behavior_sensor_keymap_binding_callback_t sensor_binding_triggered; + behavior_keymap_binding_callback_t binding_pressed; + behavior_keymap_binding_callback_t binding_released; + behavior_sensor_keymap_binding_callback_t sensor_binding_triggered; }; /** * @endcond */ - /** * @brief Handle the keymap binding being pressed * @param dev Pointer to the device structure for the driver instance. @@ -41,18 +42,18 @@ __subsystem struct behavior_driver_api { * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_keymap_binding_pressed(struct device *dev, u32_t position, u32_t param1, u32_t param2); +__syscall int behavior_keymap_binding_pressed(struct device *dev, u32_t position, u32_t param1, + u32_t param2); -static inline int z_impl_behavior_keymap_binding_pressed(struct device *dev, u32_t position, u32_t param1, u32_t param2) -{ - const struct behavior_driver_api *api = - (const struct behavior_driver_api *)dev->driver_api; +static inline int z_impl_behavior_keymap_binding_pressed(struct device *dev, u32_t position, + u32_t param1, u32_t param2) { + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; - if (api->binding_pressed == NULL) { - return -ENOTSUP; - } + if (api->binding_pressed == NULL) { + return -ENOTSUP; + } - return api->binding_pressed(dev, position, param1, param2); + return api->binding_pressed(dev, position, param1, param2); } /** @@ -63,18 +64,18 @@ static inline int z_impl_behavior_keymap_binding_pressed(struct device *dev, u32 * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_keymap_binding_released(struct device *dev, u32_t position, u32_t param1, u32_t param2); +__syscall int behavior_keymap_binding_released(struct device *dev, u32_t position, u32_t param1, + u32_t param2); -static inline int z_impl_behavior_keymap_binding_released(struct device *dev, u32_t position, u32_t param1, u32_t param2) -{ - const struct behavior_driver_api *api = - (const struct behavior_driver_api *)dev->driver_api; +static inline int z_impl_behavior_keymap_binding_released(struct device *dev, u32_t position, + u32_t param1, u32_t param2) { + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; - if (api->binding_released == NULL) { - return -ENOTSUP; - } + if (api->binding_released == NULL) { + return -ENOTSUP; + } - return api->binding_released(dev, position, param1, param2); + return api->binding_released(dev, position, param1, param2); } /** @@ -87,21 +88,21 @@ static inline int z_impl_behavior_keymap_binding_released(struct device *dev, u3 * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_sensor_keymap_binding_triggered(struct device *dev, struct device *sensor, u32_t param1, u32_t param2); +__syscall int behavior_sensor_keymap_binding_triggered(struct device *dev, struct device *sensor, + u32_t param1, u32_t param2); -static inline int z_impl_behavior_sensor_keymap_binding_triggered(struct device *dev, struct device *sensor, u32_t param1, u32_t param2) -{ - const struct behavior_driver_api *api = - (const struct behavior_driver_api *)dev->driver_api; +static inline int z_impl_behavior_sensor_keymap_binding_triggered(struct device *dev, + struct device *sensor, + u32_t param1, u32_t param2) { + const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; - if (api->sensor_binding_triggered == NULL) { - return -ENOTSUP; - } + if (api->sensor_binding_triggered == NULL) { + return -ENOTSUP; + } - return api->sensor_binding_triggered(dev, sensor, param1, param2); + return api->sensor_binding_triggered(dev, sensor, param1, param2); } - /** * @} */ diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index bf8b4f53..05fd65c8 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -4,10 +4,10 @@ * SPDX-License-Identifier: MIT */ -#define BT_CLR_CMD 0 -#define BT_NXT_CMD 1 -#define BT_PRV_CMD 2 -#define BT_SEL_CMD 3 +#define BT_CLR_CMD 0 +#define BT_NXT_CMD 1 +#define BT_PRV_CMD 2 +#define BT_SEL_CMD 3 // #define BT_FULL_RESET_CMD 4 /* @@ -15,7 +15,7 @@ Note: Some future commands will include additional parameters, so we defines these aliases up front. */ -#define BT_CLR BT_CLR_CMD 0 -#define BT_NXT BT_NXT_CMD 0 -#define BT_PRV BT_PRV_CMD 0 -#define BT_SEL BT_SEL_CMD \ No newline at end of file +#define BT_CLR BT_CLR_CMD 0 +#define BT_NXT BT_NXT_CMD 0 +#define BT_PRV BT_PRV_CMD 0 +#define BT_SEL BT_SEL_CMD \ No newline at end of file diff --git a/app/include/dt-bindings/zmk/keys.h b/app/include/dt-bindings/zmk/keys.h index cd9261d9..d3dd6341 100644 --- a/app/include/dt-bindings/zmk/keys.h +++ b/app/include/dt-bindings/zmk/keys.h @@ -55,7 +55,7 @@ #define QUOT 0x34 #define GRAV 0x35 #define CMMA 0x36 -#define DOT 0x37 +#define DOT 0x37 #define FSLH 0x38 #define CLCK 0x39 #define F1 0x3A @@ -77,8 +77,8 @@ #define INS 0x49 #define HOME 0x4A #define PGUP 0x4B -#define DEL 0x4C -#define END 0x4D +#define DEL 0x4C +#define END 0x4D #define PGDN 0x4E #define RARW 0x4F #define LARW 0x50 diff --git a/app/include/dt-bindings/zmk/reset.h b/app/include/dt-bindings/zmk/reset.h index 683f9658..2b3d8760 100644 --- a/app/include/dt-bindings/zmk/reset.h +++ b/app/include/dt-bindings/zmk/reset.h @@ -4,9 +4,10 @@ * SPDX-License-Identifier: MIT */ -#define RST_WARM 0x00 -#define RST_COLD 0x01 +#define RST_WARM 0x00 +#define RST_COLD 0x01 -// AdaFruit nrf52 Bootloader Specific. See https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/d6b28e66053eea467166f44875e3c7ec741cb471/src/main.c#L107 +// AdaFruit nrf52 Bootloader Specific. See +// https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/d6b28e66053eea467166f44875e3c7ec741cb471/src/main.c#L107 -#define RST_UF2 0x57 \ No newline at end of file +#define RST_UF2 0x57 \ No newline at end of file diff --git a/app/include/zmk/event-manager.h b/app/include/zmk/event-manager.h index 9da66029..4b8f72c0 100644 --- a/app/include/zmk/event-manager.h +++ b/app/include/zmk/event-manager.h @@ -3,20 +3,19 @@ * * SPDX-License-Identifier: MIT */ - + #pragma once #include #include #include -struct zmk_event_type -{ +struct zmk_event_type { const char *name; }; struct zmk_event_header { - const struct zmk_event_type* event; + const struct zmk_event_type *event; u8_t last_listener_index; }; @@ -24,8 +23,7 @@ struct zmk_event_header { #define ZMK_EV_EVENT_CAPTURED 2 typedef int (*zmk_listener_callback_t)(const struct zmk_event_header *eh); -struct zmk_listener -{ +struct zmk_listener { zmk_listener_callback_t callback; }; @@ -34,55 +32,50 @@ struct zmk_event_subscription { const struct zmk_listener *listener; }; -#define ZMK_EVENT_DECLARE(event_type) \ - struct event_type* new_##event_type(); \ - bool is_##event_type(const struct zmk_event_header *eh); \ - struct event_type* cast_##event_type(const struct zmk_event_header *eh); \ +#define ZMK_EVENT_DECLARE(event_type) \ + struct event_type *new_##event_type(); \ + bool is_##event_type(const struct zmk_event_header *eh); \ + struct event_type *cast_##event_type(const struct zmk_event_header *eh); \ extern const struct zmk_event_type zmk_event_##event_type; -#define ZMK_EVENT_IMPL(event_type) \ - const struct zmk_event_type zmk_event_##event_type = { \ - .name = STRINGIFY(event_type) \ - }; \ - const struct zmk_event_type* zmk_event_ref_##event_type __used __attribute__((__section__(".event_type"))) = &zmk_event_##event_type; \ - struct event_type* new_##event_type() { \ - struct event_type* ev = (struct event_type *) k_malloc(sizeof(struct event_type)); \ - ev->header.event = &zmk_event_##event_type; \ - return ev; \ - }; \ - bool is_##event_type(const struct zmk_event_header *eh) { \ - return eh->event == &zmk_event_##event_type; \ - }; \ - struct event_type* cast_##event_type(const struct zmk_event_header *eh) {\ - return (struct event_type*)eh; \ - }; - - -#define ZMK_LISTENER(mod, cb) \ - const struct zmk_listener zmk_listener_##mod = { \ - .callback = cb \ +#define ZMK_EVENT_IMPL(event_type) \ + const struct zmk_event_type zmk_event_##event_type = {.name = STRINGIFY(event_type)}; \ + const struct zmk_event_type *zmk_event_ref_##event_type __used \ + __attribute__((__section__(".event_type"))) = &zmk_event_##event_type; \ + struct event_type *new_##event_type() { \ + struct event_type *ev = (struct event_type *)k_malloc(sizeof(struct event_type)); \ + ev->header.event = &zmk_event_##event_type; \ + return ev; \ + }; \ + bool is_##event_type(const struct zmk_event_header *eh) { \ + return eh->event == &zmk_event_##event_type; \ + }; \ + struct event_type *cast_##event_type(const struct zmk_event_header *eh) { \ + return (struct event_type *)eh; \ }; -#define ZMK_SUBSCRIPTION(mod, ev_type) \ - const Z_DECL_ALIGN(struct zmk_event_subscription) _CONCAT(_CONCAT(zmk_event_sub_,mod),ev_type) __used __attribute__((__section__(".event_subscription"))) = { \ - .event_type = &zmk_event_##ev_type, \ - .listener = &zmk_listener_##mod, \ +#define ZMK_LISTENER(mod, cb) const struct zmk_listener zmk_listener_##mod = {.callback = cb}; + +#define ZMK_SUBSCRIPTION(mod, ev_type) \ + const Z_DECL_ALIGN(struct zmk_event_subscription) \ + _CONCAT(_CONCAT(zmk_event_sub_, mod), ev_type) __used \ + __attribute__((__section__(".event_subscription"))) = { \ + .event_type = &zmk_event_##ev_type, \ + .listener = &zmk_listener_##mod, \ }; -#define ZMK_EVENT_RAISE(ev) \ - zmk_event_manager_raise((struct zmk_event_header *)ev); +#define ZMK_EVENT_RAISE(ev) zmk_event_manager_raise((struct zmk_event_header *)ev); -#define ZMK_EVENT_RAISE_AFTER(ev, mod) \ +#define ZMK_EVENT_RAISE_AFTER(ev, mod) \ zmk_event_manager_raise_after((struct zmk_event_header *)ev, &zmk_listener_##mod); - -#define ZMK_EVENT_RAISE_AT(ev, mod) \ +#define ZMK_EVENT_RAISE_AT(ev, mod) \ zmk_event_manager_raise_at((struct zmk_event_header *)ev, &zmk_listener_##mod); -#define ZMK_EVENT_RELEASE(ev) \ - zmk_event_manager_release((struct zmk_event_header *)ev); +#define ZMK_EVENT_RELEASE(ev) zmk_event_manager_release((struct zmk_event_header *)ev); int zmk_event_manager_raise(struct zmk_event_header *event); -int zmk_event_manager_raise_after(struct zmk_event_header *event, const struct zmk_listener *listener); +int zmk_event_manager_raise_after(struct zmk_event_header *event, + const struct zmk_listener *listener); int zmk_event_manager_raise_at(struct zmk_event_header *event, const struct zmk_listener *listener); int zmk_event_manager_release(struct zmk_event_header *event); diff --git a/app/include/zmk/events/ble-active-profile-changed.h b/app/include/zmk/events/ble-active-profile-changed.h index c464236f..66f40c77 100644 --- a/app/include/zmk/events/ble-active-profile-changed.h +++ b/app/include/zmk/events/ble-active-profile-changed.h @@ -12,7 +12,6 @@ #include - struct ble_active_profile_changed { struct zmk_event_header header; u8_t index; diff --git a/app/include/zmk/events/keycode-state-changed.h b/app/include/zmk/events/keycode-state-changed.h index fc37946b..4c006543 100644 --- a/app/include/zmk/events/keycode-state-changed.h +++ b/app/include/zmk/events/keycode-state-changed.h @@ -18,9 +18,9 @@ struct keycode_state_changed { ZMK_EVENT_DECLARE(keycode_state_changed); -inline struct keycode_state_changed* create_keycode_state_changed(u8_t usage_page, u32_t keycode, bool state) -{ - struct keycode_state_changed* ev = new_keycode_state_changed(); +inline struct keycode_state_changed *create_keycode_state_changed(u8_t usage_page, u32_t keycode, + bool state) { + struct keycode_state_changed *ev = new_keycode_state_changed(); ev->usage_page = usage_page; ev->keycode = keycode; ev->state = state; diff --git a/app/include/zmk/events/modifiers-state-changed.h b/app/include/zmk/events/modifiers-state-changed.h index b39e11e0..d2e02f82 100644 --- a/app/include/zmk/events/modifiers-state-changed.h +++ b/app/include/zmk/events/modifiers-state-changed.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT */ - + #pragma once #include @@ -18,9 +18,9 @@ struct modifiers_state_changed { ZMK_EVENT_DECLARE(modifiers_state_changed); -inline struct modifiers_state_changed* create_modifiers_state_changed(zmk_mod_flags modifiers, bool state) -{ - struct modifiers_state_changed* ev = new_modifiers_state_changed(); +inline struct modifiers_state_changed *create_modifiers_state_changed(zmk_mod_flags modifiers, + bool state) { + struct modifiers_state_changed *ev = new_modifiers_state_changed(); ev->modifiers = modifiers; ev->state = state; diff --git a/app/include/zmk/hid.h b/app/include/zmk/hid.h index a945e729..744de98e 100644 --- a/app/include/zmk/hid.h +++ b/app/include/zmk/hid.h @@ -140,25 +140,21 @@ static const u8_t zmk_hid_report_desc[] = { // u8_t keys[6]; // } __packed; -struct zmk_hid_keypad_report_body -{ +struct zmk_hid_keypad_report_body { zmk_mod_flags modifiers; u8_t keys[13]; } __packed; -struct zmk_hid_keypad_report -{ +struct zmk_hid_keypad_report { u8_t report_id; struct zmk_hid_keypad_report_body body; } __packed; -struct zmk_hid_consumer_report_body -{ +struct zmk_hid_consumer_report_body { u8_t keys[6]; } __packed; -struct zmk_hid_consumer_report -{ +struct zmk_hid_consumer_report { u8_t report_id; struct zmk_hid_consumer_report_body body; } __packed; diff --git a/app/include/zmk/keys.h b/app/include/zmk/keys.h index ee9c3d93..af474b1f 100644 --- a/app/include/zmk/keys.h +++ b/app/include/zmk/keys.h @@ -14,8 +14,7 @@ typedef u8_t zmk_action; typedef u8_t zmk_mod; typedef u8_t zmk_mod_flags; -struct zmk_key_event -{ +struct zmk_key_event { u32_t column; u32_t row; zmk_key key; diff --git a/app/include/zmk/matrix.h b/app/include/zmk/matrix.h index 16143176..b3e2323b 100644 --- a/app/include/zmk/matrix.h +++ b/app/include/zmk/matrix.h @@ -15,20 +15,20 @@ #define ZMK_KEYMAP_TRANSFORM_NODE DT_CHOSEN(zmk_matrix_transform) #define ZMK_KEYMAP_LEN DT_PROP_LEN(ZMK_KEYMAP_TRANSFORM_NODE, map) -#define ZMK_MATRIX_ROWS DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE,rows) -#define ZMK_MATRIX_COLS DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE,columns) +#define ZMK_MATRIX_ROWS DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE, rows) +#define ZMK_MATRIX_COLS DT_PROP(ZMK_KEYMAP_TRANSFORM_NODE, columns) #else /* DT_HAS_CHOSEN(zmk_matrix_transform) */ -#if DT_NODE_HAS_PROP(ZMK_MATRIX_NODE_ID,row_gpios) -#define ZMK_MATRIX_ROWS DT_PROP_LEN(ZMK_MATRIX_NODE_ID,row_gpios) -#define ZMK_MATRIX_COLS DT_PROP_LEN(ZMK_MATRIX_NODE_ID,col_gpios) -#elif DT_NODE_HAS_PROP(ZMK_MATRIX_NODE_ID,input_gpios) +#if DT_NODE_HAS_PROP(ZMK_MATRIX_NODE_ID, row_gpios) +#define ZMK_MATRIX_ROWS DT_PROP_LEN(ZMK_MATRIX_NODE_ID, row_gpios) +#define ZMK_MATRIX_COLS DT_PROP_LEN(ZMK_MATRIX_NODE_ID, col_gpios) +#elif DT_NODE_HAS_PROP(ZMK_MATRIX_NODE_ID, input_gpios) #define ZMK_MATRIX_ROWS 1 -#define ZMK_MATRIX_COLS DT_PROP_LEN(ZMK_MATRIX_NODE_ID,input_gpios) +#define ZMK_MATRIX_COLS DT_PROP_LEN(ZMK_MATRIX_NODE_ID, input_gpios) #else -#define ZMK_MATRIX_ROWS DT_PROP(ZMK_MATRIX_NODE_ID,rows) -#define ZMK_MATRIX_COLS DT_PROP(ZMK_MATRIX_NODE_ID,columns) +#define ZMK_MATRIX_ROWS DT_PROP(ZMK_MATRIX_NODE_ID, rows) +#define ZMK_MATRIX_COLS DT_PROP(ZMK_MATRIX_NODE_ID, columns) #endif #define ZMK_KEYMAP_LEN (ZMK_MATRIX_COLS * ZMK_MATRIX_ROWS) diff --git a/app/include/zmk/split/bluetooth/uuid.h b/app/include/zmk/split/bluetooth/uuid.h index 59f2f712..a8dfbf62 100644 --- a/app/include/zmk/split/bluetooth/uuid.h +++ b/app/include/zmk/split/bluetooth/uuid.h @@ -3,10 +3,9 @@ #include #ifndef BT_UUID_NUM_OF_DIGITALS -#define BT_UUID_NUM_OF_DIGITALS BT_UUID_DECLARE_16(0x2909) +#define BT_UUID_NUM_OF_DIGITALS BT_UUID_DECLARE_16(0x2909) #endif -#define ZMK_BT_SPLIT_UUID(num) BT_UUID_128_ENCODE(num, 0x0096, 0x7107, 0xc967, 0xc5cfb1c2482a) +#define ZMK_BT_SPLIT_UUID(num) BT_UUID_128_ENCODE(num, 0x0096, 0x7107, 0xc967, 0xc5cfb1c2482a) #define ZMK_SPLIT_BT_SERVICE_UUID ZMK_BT_SPLIT_UUID(0x00000000) #define ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID ZMK_BT_SPLIT_UUID(0x00000001) - diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 3a5fbfbf..09fadba2 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -18,10 +18,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t command, u32_t arg) -{ - switch (command) - { +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t command, u32_t arg) { + switch (command) { case BT_CLR_CMD: return zmk_ble_clear_bonds(); case BT_NXT_CMD: @@ -37,13 +35,10 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c return -ENOTSUP; } -static int behavior_bt_init(struct device *dev) -{ - return 0; -}; +static int behavior_bt_init(struct device *dev) { return 0; }; -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, u32_t arg) -{ +static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, + u32_t arg) { return 0; } @@ -52,9 +47,5 @@ static const struct behavior_driver_api behavior_bt_driver_api = { .binding_released = on_keymap_binding_released, }; -DEVICE_AND_API_INIT(behavior_bt, DT_INST_LABEL(0), - behavior_bt_init, - NULL, - NULL, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, - &behavior_bt_driver_api); +DEVICE_AND_API_INIT(behavior_bt, DT_INST_LABEL(0), behavior_bt_init, NULL, NULL, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_bt_driver_api); diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index dce724d9..8f307a6b 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -29,36 +29,35 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); // increase if you have keyboard with more keys. #define ZMK_BHV_HOLD_TAP_POSITION_NOT_USED 9999 - enum flavor { - ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0, - ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1, - ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED = 2, + ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED = 0, + ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED = 1, + ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED = 2, }; struct behavior_hold_tap_behaviors { - struct zmk_behavior_binding tap; - struct zmk_behavior_binding hold; + struct zmk_behavior_binding tap; + struct zmk_behavior_binding hold; }; typedef k_timeout_t (*timer_func)(); struct behavior_hold_tap_config { - timer_func tapping_term_ms; - struct behavior_hold_tap_behaviors *behaviors; - enum flavor flavor; + timer_func tapping_term_ms; + struct behavior_hold_tap_behaviors *behaviors; + enum flavor flavor; }; // this data is specific for each hold-tap struct active_hold_tap { - s32_t position; - u32_t param_hold; - u32_t param_tap; - bool is_decided; - bool is_hold; - const struct behavior_hold_tap_config *config; - struct k_delayed_work work; - bool work_is_cancelled; + s32_t position; + u32_t param_hold; + u32_t param_tap; + bool is_decided; + bool is_hold; + const struct behavior_hold_tap_config *config; + struct k_delayed_work work; + bool work_is_cancelled; }; // The undecided hold tap is the hold tap that needs to be decided before @@ -71,371 +70,366 @@ struct active_hold_tap active_hold_taps[ZMK_BHV_HOLD_TAP_MAX_HELD] = {}; // We capture most position_state_changed events and some modifiers_state_changed events. const struct zmk_event_header *captured_events[ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS] = {}; -static int capture_event(const struct zmk_event_header *event) -{ - for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { - if (captured_events[i] == NULL) { - captured_events[i] = event; - return 0; - } - } - return -ENOMEM; +static int capture_event(const struct zmk_event_header *event) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { + if (captured_events[i] == NULL) { + captured_events[i] = event; + return 0; + } + } + return -ENOMEM; } -static struct position_state_changed *find_captured_keydown_event(u32_t position) -{ - struct position_state_changed *last_match = NULL; - for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { - const struct zmk_event_header *eh = captured_events[i]; - if (eh == NULL) { - return last_match; - } - if (!is_position_state_changed(eh)) { - continue; - } - struct position_state_changed *position_event = cast_position_state_changed(eh); - if (position_event->position == position && position_event->state) { - last_match = position_event; - } - } - return last_match; +static struct position_state_changed *find_captured_keydown_event(u32_t position) { + struct position_state_changed *last_match = NULL; + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { + const struct zmk_event_header *eh = captured_events[i]; + if (eh == NULL) { + return last_match; + } + if (!is_position_state_changed(eh)) { + continue; + } + struct position_state_changed *position_event = cast_position_state_changed(eh); + if (position_event->position == position && position_event->state) { + last_match = position_event; + } + } + return last_match; } const struct zmk_listener zmk_listener_behavior_hold_tap; -static void release_captured_events() -{ - if (undecided_hold_tap != NULL) { - return; - } +static void release_captured_events() { + if (undecided_hold_tap != NULL) { + return; + } - // We use a trick to prevent copying the captured_events array. - // - // Events for different mod-tap instances are separated by a NULL pointer. - // - // The first event popped will never be catched by the next active hold-tap - // because to start capturing a mod-tap-key-down event must first completely - // go through the events queue. - // - // Example of this release process; - // [mt2_down, k1_down, k1_up, mt2_up, null, ...] - // ^ - // mt2_down position event isn't captured because no hold-tap is active. - // mt2_down behavior event is handled, now we have an undecided hold-tap - // [null, k1_down, k1_up, mt2_up, null, ...] - // ^ - // k1_down is captured by the mt2 mod-tap - // !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the first null encountered - // [mt1_down, null, k1_up, mt2_up, null, ...] - // ^ - // k1_up event is captured by the new hold-tap: - // [k1_down, k1_up, null, mt2_up, null, ...] - // ^ - // mt2_up event is not captured but causes release of mt2 behavior - // [k1_down, k1_up, null, null, null, ...] - // now mt2 will start releasing it's own captured positions. - for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { - const struct zmk_event_header *captured_event = captured_events[i]; - if (captured_event == NULL) { - return; - } - captured_events[i] = NULL; - if (undecided_hold_tap != NULL) { - k_msleep(10); - } - if (is_position_state_changed(captured_event)) { - struct position_state_changed *position_event = cast_position_state_changed(captured_event); - LOG_DBG("Releasing key position event for position %d %s", position_event->position, (position_event->state ? "pressed" : "released")); - } else { - struct keycode_state_changed *modifier_event = cast_keycode_state_changed(captured_event); - LOG_DBG("Releasing mods changed event 0x%02X %s", modifier_event->keycode, (modifier_event->state ? "pressed" : "released")); - } - ZMK_EVENT_RAISE_AT(captured_event, behavior_hold_tap); - } + // We use a trick to prevent copying the captured_events array. + // + // Events for different mod-tap instances are separated by a NULL pointer. + // + // The first event popped will never be catched by the next active hold-tap + // because to start capturing a mod-tap-key-down event must first completely + // go through the events queue. + // + // Example of this release process; + // [mt2_down, k1_down, k1_up, mt2_up, null, ...] + // ^ + // mt2_down position event isn't captured because no hold-tap is active. + // mt2_down behavior event is handled, now we have an undecided hold-tap + // [null, k1_down, k1_up, mt2_up, null, ...] + // ^ + // k1_down is captured by the mt2 mod-tap + // !note that searches for find_captured_keydown_event by the mt2 behavior will stop at the + // first null encountered [mt1_down, null, k1_up, mt2_up, null, ...] + // ^ + // k1_up event is captured by the new hold-tap: + // [k1_down, k1_up, null, mt2_up, null, ...] + // ^ + // mt2_up event is not captured but causes release of mt2 behavior + // [k1_down, k1_up, null, null, null, ...] + // now mt2 will start releasing it's own captured positions. + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_CAPTURED_EVENTS; i++) { + const struct zmk_event_header *captured_event = captured_events[i]; + if (captured_event == NULL) { + return; + } + captured_events[i] = NULL; + if (undecided_hold_tap != NULL) { + k_msleep(10); + } + if (is_position_state_changed(captured_event)) { + struct position_state_changed *position_event = + cast_position_state_changed(captured_event); + LOG_DBG("Releasing key position event for position %d %s", position_event->position, + (position_event->state ? "pressed" : "released")); + } else { + struct keycode_state_changed *modifier_event = + cast_keycode_state_changed(captured_event); + LOG_DBG("Releasing mods changed event 0x%02X %s", modifier_event->keycode, + (modifier_event->state ? "pressed" : "released")); + } + ZMK_EVENT_RAISE_AT(captured_event, behavior_hold_tap); + } } -static struct active_hold_tap *find_hold_tap(u32_t position) -{ - for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { - if (active_hold_taps[i].position == position) { - return &active_hold_taps[i]; - } - } - return NULL; +static struct active_hold_tap *find_hold_tap(u32_t position) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { + if (active_hold_taps[i].position == position) { + return &active_hold_taps[i]; + } + } + return NULL; } -static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, u32_t param_tap, const struct behavior_hold_tap_config *config) -{ - for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { - if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) { - continue; - } - active_hold_taps[i].position = position; - active_hold_taps[i].is_decided = false; - active_hold_taps[i].is_hold = false; - active_hold_taps[i].config = config; - active_hold_taps[i].param_hold = param_hold; - active_hold_taps[i].param_tap = param_tap; - return &active_hold_taps[i]; - } - return NULL; +static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, u32_t param_tap, + const struct behavior_hold_tap_config *config) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { + if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) { + continue; + } + active_hold_taps[i].position = position; + active_hold_taps[i].is_decided = false; + active_hold_taps[i].is_hold = false; + active_hold_taps[i].config = config; + active_hold_taps[i].param_hold = param_hold; + active_hold_taps[i].param_tap = param_tap; + return &active_hold_taps[i]; + } + return NULL; } -static void clear_hold_tap(struct active_hold_tap *hold_tap) -{ - hold_tap->position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; - hold_tap->is_decided = false; - hold_tap->is_hold = false; - hold_tap->work_is_cancelled = false; +static void clear_hold_tap(struct active_hold_tap *hold_tap) { + hold_tap->position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; + hold_tap->is_decided = false; + hold_tap->is_hold = false; + hold_tap->work_is_cancelled = false; } enum decision_moment { - HT_KEY_UP = 0, - HT_OTHER_KEY_DOWN = 1, - HT_OTHER_KEY_UP = 2, - HT_TIMER_EVENT = 3, + HT_KEY_UP = 0, + HT_OTHER_KEY_DOWN = 1, + HT_OTHER_KEY_UP = 2, + HT_TIMER_EVENT = 3, }; -static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event) -{ - switch (event) { - case HT_KEY_UP: - hold_tap->is_hold = 0; - hold_tap->is_decided = true; - break; - case HT_OTHER_KEY_UP: - case HT_TIMER_EVENT: - hold_tap->is_hold = 1; - hold_tap->is_decided = true; - break; - default: return; - } +static void decide_balanced(struct active_hold_tap *hold_tap, enum decision_moment event) { + switch (event) { + case HT_KEY_UP: + hold_tap->is_hold = 0; + hold_tap->is_decided = true; + break; + case HT_OTHER_KEY_UP: + case HT_TIMER_EVENT: + hold_tap->is_hold = 1; + hold_tap->is_decided = true; + break; + default: + return; + } } -static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) -{ - switch (event) { - case HT_KEY_UP: - hold_tap->is_hold = 0; - hold_tap->is_decided = true; - break; - case HT_TIMER_EVENT: - hold_tap->is_hold = 1; - hold_tap->is_decided = true; - break; - default: return; - } +static void decide_tap_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) { + switch (event) { + case HT_KEY_UP: + hold_tap->is_hold = 0; + hold_tap->is_decided = true; + break; + case HT_TIMER_EVENT: + hold_tap->is_hold = 1; + hold_tap->is_decided = true; + break; + default: + return; + } } -static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) -{ - switch (event) { - case HT_KEY_UP: - hold_tap->is_hold = 0; - hold_tap->is_decided = true; - break; - case HT_OTHER_KEY_DOWN: - case HT_TIMER_EVENT: - hold_tap->is_hold = 1; - hold_tap->is_decided = true; - break; - default: return; - } +static void decide_hold_preferred(struct active_hold_tap *hold_tap, enum decision_moment event) { + switch (event) { + case HT_KEY_UP: + hold_tap->is_hold = 0; + hold_tap->is_decided = true; + break; + case HT_OTHER_KEY_DOWN: + case HT_TIMER_EVENT: + hold_tap->is_hold = 1; + hold_tap->is_decided = true; + break; + default: + return; + } } -static inline char* flavor_str(enum flavor flavor) { - switch(flavor) { - case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED: - return "hold-preferred"; - case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED: - return "balanced"; - case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED: - return "tap-preferred"; - } - return "UNKNOWN FLAVOR"; +static inline char *flavor_str(enum flavor flavor) { + switch (flavor) { + case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED: + return "hold-preferred"; + case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED: + return "balanced"; + case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED: + return "tap-preferred"; + } + return "UNKNOWN FLAVOR"; } -static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event) -{ - if (hold_tap->is_decided) { - return; - } +static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event) { + if (hold_tap->is_decided) { + return; + } - if (hold_tap != undecided_hold_tap) { - LOG_DBG("ERROR found undecided tap hold that is not the active tap hold"); - return; - } + if (hold_tap != undecided_hold_tap) { + LOG_DBG("ERROR found undecided tap hold that is not the active tap hold"); + return; + } - switch(hold_tap->config->flavor) { - case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED: - decide_hold_preferred(hold_tap, event); - case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED: - decide_balanced(hold_tap, event); - case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED: - decide_tap_preferred(hold_tap, event); - } + switch (hold_tap->config->flavor) { + case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED: + decide_hold_preferred(hold_tap, event); + case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED: + decide_balanced(hold_tap, event); + case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED: + decide_tap_preferred(hold_tap, event); + } - if (!hold_tap->is_decided) { - return; - } + if (!hold_tap->is_decided) { + return; + } - LOG_DBG("%d decided %s (%s event %d)", - hold_tap->position, - hold_tap->is_hold ? "hold" : "tap", - flavor_str(hold_tap->config->flavor), - event); - undecided_hold_tap = NULL; + LOG_DBG("%d decided %s (%s event %d)", hold_tap->position, hold_tap->is_hold ? "hold" : "tap", + flavor_str(hold_tap->config->flavor), event); + undecided_hold_tap = NULL; - struct zmk_behavior_binding *behavior; - if (hold_tap->is_hold) { - behavior = &hold_tap->config->behaviors->hold; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_hold, 0); - } else { - behavior = &hold_tap->config->behaviors->tap; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_tap, 0); - } - release_captured_events(); + struct zmk_behavior_binding *behavior; + if (hold_tap->is_hold) { + behavior = &hold_tap->config->behaviors->hold; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_hold, + 0); + } else { + behavior = &hold_tap->config->behaviors->tap; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_tap, + 0); + } + release_captured_events(); } -static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t param_hold, u32_t param_tap) -{ - const struct behavior_hold_tap_config *cfg = dev->config_info; +static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t param_hold, + u32_t param_tap) { + const struct behavior_hold_tap_config *cfg = dev->config_info; - if (undecided_hold_tap != NULL) { - LOG_DBG("ERROR another hold-tap behavior is undecided."); - // if this happens, make sure the behavior events occur AFTER other position events. - return 0; - } + if (undecided_hold_tap != NULL) { + LOG_DBG("ERROR another hold-tap behavior is undecided."); + // if this happens, make sure the behavior events occur AFTER other position events. + return 0; + } - struct active_hold_tap *hold_tap = store_hold_tap(position, param_hold, param_tap, cfg); - if (hold_tap == NULL) { - LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", ZMK_BHV_HOLD_TAP_MAX_HELD); - return 0; - } + struct active_hold_tap *hold_tap = store_hold_tap(position, param_hold, param_tap, cfg); + if (hold_tap == NULL) { + LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", + ZMK_BHV_HOLD_TAP_MAX_HELD); + return 0; + } - LOG_DBG("%d new undecided hold_tap", position); - undecided_hold_tap = hold_tap; - k_delayed_work_submit(&hold_tap->work, cfg->tapping_term_ms()); + LOG_DBG("%d new undecided hold_tap", position); + undecided_hold_tap = hold_tap; + k_delayed_work_submit(&hold_tap->work, cfg->tapping_term_ms()); - // todo: once we get timing info for keypresses, start the timer relative to the original keypress - // don't forget to simulate a timer-event before the event after that time was handled. + // todo: once we get timing info for keypresses, start the timer relative to the original + // keypress don't forget to simulate a timer-event before the event after that time was handled. - return 0; + return 0; } -static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_t _, u32_t __) -{ - struct active_hold_tap *hold_tap = find_hold_tap(position); +static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_t _, u32_t __) { + struct active_hold_tap *hold_tap = find_hold_tap(position); - if (hold_tap == NULL) { - LOG_ERR("ACTIVE_HOLD_TAP_CLEANED_UP_TOO_EARLY"); - return 0; - } + if (hold_tap == NULL) { + LOG_ERR("ACTIVE_HOLD_TAP_CLEANED_UP_TOO_EARLY"); + return 0; + } - int work_cancel_result = k_delayed_work_cancel(&hold_tap->work); - decide_hold_tap(hold_tap, HT_KEY_UP); + int work_cancel_result = k_delayed_work_cancel(&hold_tap->work); + decide_hold_tap(hold_tap, HT_KEY_UP); - struct zmk_behavior_binding *behavior; - if (hold_tap->is_hold) { - behavior = &hold_tap->config->behaviors->hold; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_hold, 0); - } else { - behavior = &hold_tap->config->behaviors->tap; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_tap, 0); - } + struct zmk_behavior_binding *behavior; + if (hold_tap->is_hold) { + behavior = &hold_tap->config->behaviors->hold; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_hold, + 0); + } else { + behavior = &hold_tap->config->behaviors->tap; + struct device *behavior_device = device_get_binding(behavior->behavior_dev); + behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_tap, + 0); + } + if (work_cancel_result == -EINPROGRESS) { + // let the timer handler clean up + // if we'd clear now, the timer may call back for an uninitialized active_hold_tap. + LOG_DBG("%d hold-tap timer work in event queue", position); + hold_tap->work_is_cancelled = true; + } else { + LOG_DBG("%d cleaning up hold-tap", position); + clear_hold_tap(hold_tap); + } - if (work_cancel_result == -EINPROGRESS) { - // let the timer handler clean up - // if we'd clear now, the timer may call back for an uninitialized active_hold_tap. - LOG_DBG("%d hold-tap timer work in event queue", position); - hold_tap->work_is_cancelled = true; - } else { - LOG_DBG("%d cleaning up hold-tap", position); - clear_hold_tap(hold_tap); - } - - return 0; + return 0; } static const struct behavior_driver_api behavior_hold_tap_driver_api = { - .binding_pressed = on_hold_tap_binding_pressed, - .binding_released = on_hold_tap_binding_released, + .binding_pressed = on_hold_tap_binding_pressed, + .binding_released = on_hold_tap_binding_released, }; +static int position_state_changed_listener(const struct zmk_event_header *eh) { + struct position_state_changed *ev = cast_position_state_changed(eh); -static int position_state_changed_listener(const struct zmk_event_header *eh) -{ - struct position_state_changed *ev = cast_position_state_changed(eh); + if (undecided_hold_tap == NULL) { + LOG_DBG("%d bubble (no undecided hold_tap active)", ev->position); + return 0; + } - if (undecided_hold_tap == NULL) { - LOG_DBG("%d bubble (no undecided hold_tap active)", ev->position); - return 0; - } + if (undecided_hold_tap->position == ev->position) { + if (ev->state) { // keydown + LOG_ERR("hold-tap listener should be called before before most other listeners!"); + return 0; + } else { // keyup + LOG_DBG("%d bubble undecided hold-tap keyrelease event", undecided_hold_tap->position); + return 0; + } + } - if (undecided_hold_tap->position == ev->position) { - if (ev->state) { // keydown - LOG_ERR("hold-tap listener should be called before before most other listeners!"); - return 0; - } else { // keyup - LOG_DBG("%d bubble undecided hold-tap keyrelease event", undecided_hold_tap->position); - return 0; - } - } + if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { + // no keydown event has been captured, let it bubble. + // we'll catch modifiers later in modifier_state_changed_listener + LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position, + ev->state ? "down" : "up"); + return 0; + } - if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { - // no keydown event has been captured, let it bubble. - // we'll catch modifiers later in modifier_state_changed_listener - LOG_DBG("%d bubbling %d %s event", undecided_hold_tap->position, ev->position, ev->state ? "down" : "up"); - return 0; - } - - LOG_DBG("%d capturing %d %s event", undecided_hold_tap->position, ev->position, ev->state ? "down" : "up"); - capture_event(eh); - decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP); - return ZMK_EV_EVENT_CAPTURED; + LOG_DBG("%d capturing %d %s event", undecided_hold_tap->position, ev->position, + ev->state ? "down" : "up"); + capture_event(eh); + decide_hold_tap(undecided_hold_tap, ev->state ? HT_OTHER_KEY_DOWN : HT_OTHER_KEY_UP); + return ZMK_EV_EVENT_CAPTURED; } -static bool is_mod(struct keycode_state_changed *ev) -{ - return ev->usage_page == USAGE_KEYPAD && ev->keycode >= LCTL && ev->keycode <= RGUI; +static bool is_mod(struct keycode_state_changed *ev) { + return ev->usage_page == USAGE_KEYPAD && ev->keycode >= LCTL && ev->keycode <= RGUI; } -static int keycode_state_changed_listener(const struct zmk_event_header *eh) -{ - // we want to catch layer-up events too... how? - struct keycode_state_changed *ev = cast_keycode_state_changed(eh); +static int keycode_state_changed_listener(const struct zmk_event_header *eh) { + // we want to catch layer-up events too... how? + struct keycode_state_changed *ev = cast_keycode_state_changed(eh); - if (undecided_hold_tap == NULL) { - // LOG_DBG("0x%02X bubble (no undecided hold_tap active)", ev->keycode); - return 0; - } + if (undecided_hold_tap == NULL) { + // LOG_DBG("0x%02X bubble (no undecided hold_tap active)", ev->keycode); + return 0; + } - if (!is_mod(ev)) { - // LOG_DBG("0x%02X bubble (not a mod)", ev->keycode); - return 0; - } + if (!is_mod(ev)) { + // LOG_DBG("0x%02X bubble (not a mod)", ev->keycode); + return 0; + } - // only key-up events will bubble through position_state_changed_listener - // if a undecided_hold_tap is active. - LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode, ev->state ? "down" : "up"); - capture_event(eh); - return ZMK_EV_EVENT_CAPTURED; + // only key-up events will bubble through position_state_changed_listener + // if a undecided_hold_tap is active. + LOG_DBG("%d capturing 0x%02X %s event", undecided_hold_tap->position, ev->keycode, + ev->state ? "down" : "up"); + capture_event(eh); + return ZMK_EV_EVENT_CAPTURED; } - -int behavior_hold_tap_listener(const struct zmk_event_header *eh) -{ - if (is_position_state_changed(eh)) { - return position_state_changed_listener(eh); - } else if (is_keycode_state_changed(eh)) { - return keycode_state_changed_listener(eh); - } - return 0; +int behavior_hold_tap_listener(const struct zmk_event_header *eh) { + if (is_position_state_changed(eh)) { + return position_state_changed_listener(eh); + } else if (is_keycode_state_changed(eh)) { + return keycode_state_changed_listener(eh); + } + return 0; } ZMK_LISTENER(behavior_hold_tap, behavior_hold_tap_listener); @@ -443,60 +437,56 @@ ZMK_SUBSCRIPTION(behavior_hold_tap, position_state_changed); // this should be modifiers_state_changed, but unfrotunately that's not implemented yet. ZMK_SUBSCRIPTION(behavior_hold_tap, keycode_state_changed); -void behavior_hold_tap_timer_work_handler(struct k_work *item) -{ - struct active_hold_tap *hold_tap = CONTAINER_OF(item, struct active_hold_tap, work); +void behavior_hold_tap_timer_work_handler(struct k_work *item) { + struct active_hold_tap *hold_tap = CONTAINER_OF(item, struct active_hold_tap, work); - if (hold_tap->work_is_cancelled) { - clear_hold_tap(hold_tap); - } else { - decide_hold_tap(hold_tap, HT_TIMER_EVENT); - } + if (hold_tap->work_is_cancelled) { + clear_hold_tap(hold_tap); + } else { + decide_hold_tap(hold_tap, HT_TIMER_EVENT); + } } -static int behavior_hold_tap_init(struct device *dev) -{ - static bool init_first_run = true; +static int behavior_hold_tap_init(struct device *dev) { + static bool init_first_run = true; - if (init_first_run) { - for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { - k_delayed_work_init(&active_hold_taps[i].work, behavior_hold_tap_timer_work_handler); - active_hold_taps[i].position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; - } - } - init_first_run = false; - return 0; + if (init_first_run) { + for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { + k_delayed_work_init(&active_hold_taps[i].work, behavior_hold_tap_timer_work_handler); + active_hold_taps[i].position = ZMK_BHV_HOLD_TAP_POSITION_NOT_USED; + } + } + init_first_run = false; + return 0; } struct behavior_hold_tap_data {}; static struct behavior_hold_tap_data behavior_hold_tap_data; -#define _TRANSFORM_ENTRY(idx, node) \ - { \ - .behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \ - .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \ - .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), (DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \ - }, +#define _TRANSFORM_ENTRY(idx, node) \ + { \ + .behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \ + .param1 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param1), (0), \ + (DT_INST_PHA_BY_IDX(node, bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_INST_PHA_HAS_CELL_AT_IDX(node, bindings, idx, param2), (0), \ + (DT_INST_PHA_BY_IDX(node, bindings, idx, param2))), \ + }, -#define KP_INST(n) \ - static k_timeout_t behavior_hold_tap_config_##n##_gettime() { return K_MSEC(DT_INST_PROP(n, tapping_term_ms)); } \ - static struct behavior_hold_tap_behaviors behavior_hold_tap_behaviors_##n = { \ - .hold = _TRANSFORM_ENTRY(0, n) \ - .tap = _TRANSFORM_ENTRY(1, n) \ - }; \ - static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \ - .behaviors = &behavior_hold_tap_behaviors_##n, \ - .tapping_term_ms = &behavior_hold_tap_config_##n##_gettime, \ - .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ - }; \ - DEVICE_AND_API_INIT( \ - behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \ - &behavior_hold_tap_data, \ - &behavior_hold_tap_config_##n, \ - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_hold_tap_driver_api); +#define KP_INST(n) \ + static k_timeout_t behavior_hold_tap_config_##n##_gettime() { \ + return K_MSEC(DT_INST_PROP(n, tapping_term_ms)); \ + } \ + static struct behavior_hold_tap_behaviors behavior_hold_tap_behaviors_##n = { \ + .hold = _TRANSFORM_ENTRY(0, n).tap = _TRANSFORM_ENTRY(1, n)}; \ + static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \ + .behaviors = &behavior_hold_tap_behaviors_##n, \ + .tapping_term_ms = &behavior_hold_tap_config_##n##_gettime, \ + .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ + }; \ + DEVICE_AND_API_INIT(behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \ + &behavior_hold_tap_data, &behavior_hold_tap_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_hold_tap_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) - #endif \ No newline at end of file diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c index 42becf50..bbfbe369 100644 --- a/app/src/behaviors/behavior_key_press.c +++ b/app/src/behaviors/behavior_key_press.c @@ -16,45 +16,35 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); struct behavior_key_press_config { - u8_t usage_page; + u8_t usage_page; }; -struct behavior_key_press_data { }; +struct behavior_key_press_data {}; -static int behavior_key_press_init(struct device *dev) -{ - return 0; -}; +static int behavior_key_press_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t keycode, u32_t _) -{ - const struct behavior_key_press_config *cfg = dev->config_info; - LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t keycode, u32_t _) { + const struct behavior_key_press_config *cfg = dev->config_info; + LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); - return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, true)); + return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, true)); } -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t keycode, u32_t _) -{ - const struct behavior_key_press_config *cfg = dev->config_info; - LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); +static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t keycode, u32_t _) { + const struct behavior_key_press_config *cfg = dev->config_info; + LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); - return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, false)); + return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, false)); } static const struct behavior_driver_api behavior_key_press_driver_api = { - .binding_pressed = on_keymap_binding_pressed, - .binding_released = on_keymap_binding_released -}; + .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released}; -#define KP_INST(n) \ - static const struct behavior_key_press_config behavior_key_press_config_##n = { \ - .usage_page = DT_INST_PROP(n, usage_page) \ - }; \ - static struct behavior_key_press_data behavior_key_press_data_##n; \ - DEVICE_AND_API_INIT(behavior_key_press_##n, DT_INST_LABEL(n), behavior_key_press_init, \ - &behavior_key_press_data_##n, \ - &behavior_key_press_config_##n, \ - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_key_press_driver_api); +#define KP_INST(n) \ + static const struct behavior_key_press_config behavior_key_press_config_##n = { \ + .usage_page = DT_INST_PROP(n, usage_page)}; \ + static struct behavior_key_press_data behavior_key_press_data_##n; \ + DEVICE_AND_API_INIT(behavior_key_press_##n, DT_INST_LABEL(n), behavior_key_press_init, \ + &behavior_key_press_data_##n, &behavior_key_press_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_press_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) \ No newline at end of file diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c index 7d651354..80b7165b 100644 --- a/app/src/behaviors/behavior_momentary_layer.c +++ b/app/src/behaviors/behavior_momentary_layer.c @@ -14,41 +14,30 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -struct behavior_mo_config { }; -struct behavior_mo_data { }; +struct behavior_mo_config {}; +struct behavior_mo_data {}; -static int behavior_mo_init(struct device *dev) -{ - return 0; -}; +static int behavior_mo_init(struct device *dev) { return 0; }; +static int mo_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) { + LOG_DBG("position %d layer %d", position, layer); -static int mo_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) -{ - LOG_DBG("position %d layer %d", position, layer); - - return zmk_keymap_layer_activate(layer); + return zmk_keymap_layer_activate(layer); } -static int mo_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) -{ - LOG_DBG("position %d layer %d", position, layer); +static int mo_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) { + LOG_DBG("position %d layer %d", position, layer); - return zmk_keymap_layer_deactivate(layer); + return zmk_keymap_layer_deactivate(layer); } static const struct behavior_driver_api behavior_mo_driver_api = { - .binding_pressed = mo_keymap_binding_pressed, - .binding_released = mo_keymap_binding_released -}; - + .binding_pressed = mo_keymap_binding_pressed, .binding_released = mo_keymap_binding_released}; static const struct behavior_mo_config behavior_mo_config = {}; static struct behavior_mo_data behavior_mo_data; -DEVICE_AND_API_INIT(behavior_mo, DT_INST_LABEL(0), behavior_mo_init, - &behavior_mo_data, - &behavior_mo_config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, +DEVICE_AND_API_INIT(behavior_mo, DT_INST_LABEL(0), behavior_mo_init, &behavior_mo_data, + &behavior_mo_config, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_mo_driver_api); diff --git a/app/src/behaviors/behavior_none.c b/app/src/behaviors/behavior_none.c index c4649882..b548e6f7 100644 --- a/app/src/behaviors/behavior_none.c +++ b/app/src/behaviors/behavior_none.c @@ -13,36 +13,30 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -struct behavior_none_config { }; -struct behavior_none_data { }; +struct behavior_none_config {}; +struct behavior_none_data {}; -static int behavior_none_init(struct device *dev) -{ - return 0; -}; +static int behavior_none_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, u32_t _param2) -{ - return 0; +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, + u32_t _param2) { + return 0; } -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, u32_t _param2) -{ - return 0; +static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, + u32_t _param2) { + return 0; } static const struct behavior_driver_api behavior_none_driver_api = { - .binding_pressed = on_keymap_binding_pressed, - .binding_released = on_keymap_binding_released, + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, }; - static const struct behavior_none_config behavior_none_config = {}; static struct behavior_none_data behavior_none_data; -DEVICE_AND_API_INIT(behavior_none, DT_INST_LABEL(0), behavior_none_init, - &behavior_none_data, - &behavior_none_config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, +DEVICE_AND_API_INIT(behavior_none, DT_INST_LABEL(0), behavior_none_init, &behavior_none_data, + &behavior_none_config, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_none_driver_api); \ No newline at end of file diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c index b5692b50..90de20b0 100644 --- a/app/src/behaviors/behavior_reset.c +++ b/app/src/behaviors/behavior_reset.c @@ -14,37 +14,31 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); struct behavior_reset_config { - int type; + int type; }; -static int behavior_reset_init(struct device *dev) -{ - return 0; -}; +static int behavior_reset_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, u32_t _param2) -{ - const struct behavior_reset_config *cfg = dev->config_info; +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, + u32_t _param2) { + const struct behavior_reset_config *cfg = dev->config_info; - // TODO: Correct magic code for going into DFU? - // See https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/d6b28e66053eea467166f44875e3c7ec741cb471/src/main.c#L107 - sys_reboot(cfg->type); - return 0; + // TODO: Correct magic code for going into DFU? + // See + // https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/d6b28e66053eea467166f44875e3c7ec741cb471/src/main.c#L107 + sys_reboot(cfg->type); + return 0; } static const struct behavior_driver_api behavior_reset_driver_api = { - .binding_pressed = on_keymap_binding_pressed, + .binding_pressed = on_keymap_binding_pressed, }; +#define RST_INST(n) \ + static const struct behavior_reset_config behavior_reset_config_##n = { \ + .type = DT_INST_PROP(n, type)}; \ + DEVICE_AND_API_INIT(behavior_reset_##n, DT_INST_LABEL(n), behavior_reset_init, NULL, \ + &behavior_reset_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_reset_driver_api); -#define RST_INST(n) \ - static const struct behavior_reset_config behavior_reset_config_##n = { \ - .type = DT_INST_PROP(n, type) \ - }; \ - DEVICE_AND_API_INIT(behavior_reset_##n, DT_INST_LABEL(n), behavior_reset_init, \ - NULL, \ - &behavior_reset_config_##n, \ - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_reset_driver_api); - DT_INST_FOREACH_STATUS_OKAY(RST_INST) \ No newline at end of file diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index f0a35ef8..621eab5e 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -15,48 +15,41 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -static int behavior_rgb_underglow_init(struct device *dev) -{ - return 0; -} +static int behavior_rgb_underglow_init(struct device *dev) { return 0; } -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t action, u32_t _) -{ - switch (action) - { +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t action, u32_t _) { + switch (action) { case RGB_TOG: - return zmk_rgb_underglow_toggle(); + return zmk_rgb_underglow_toggle(); case RGB_HUI: - return zmk_rgb_underglow_change_hue(1); + return zmk_rgb_underglow_change_hue(1); case RGB_HUD: - return zmk_rgb_underglow_change_hue(-1); + return zmk_rgb_underglow_change_hue(-1); case RGB_SAI: - return zmk_rgb_underglow_change_sat(1); + return zmk_rgb_underglow_change_sat(1); case RGB_SAD: - return zmk_rgb_underglow_change_sat(-1); + return zmk_rgb_underglow_change_sat(-1); case RGB_BRI: - return zmk_rgb_underglow_change_brt(1); + return zmk_rgb_underglow_change_brt(1); case RGB_BRD: - return zmk_rgb_underglow_change_brt(-1); + return zmk_rgb_underglow_change_brt(-1); case RGB_SPI: - return zmk_rgb_underglow_change_spd(1); + return zmk_rgb_underglow_change_spd(1); case RGB_SPD: - return zmk_rgb_underglow_change_spd(-1); + return zmk_rgb_underglow_change_spd(-1); case RGB_EFF: - return zmk_rgb_underglow_cycle_effect(1); + return zmk_rgb_underglow_cycle_effect(1); case RGB_EFR: - return zmk_rgb_underglow_cycle_effect(-1); - } + return zmk_rgb_underglow_cycle_effect(-1); + } - return -ENOTSUP; + return -ENOTSUP; } static const struct behavior_driver_api behavior_rgb_underglow_driver_api = { - .binding_pressed = on_keymap_binding_pressed, + .binding_pressed = on_keymap_binding_pressed, }; -DEVICE_AND_API_INIT(behavior_rgb_underglow, DT_INST_LABEL(0), behavior_rgb_underglow_init, - NULL, - NULL, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, +DEVICE_AND_API_INIT(behavior_rgb_underglow, DT_INST_LABEL(0), behavior_rgb_underglow_init, NULL, + NULL, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_rgb_underglow_driver_api); \ No newline at end of file diff --git a/app/src/behaviors/behavior_sensor_rotate_key_press.c b/app/src/behaviors/behavior_sensor_rotate_key_press.c index fa555752..1a0bf03a 100644 --- a/app/src/behaviors/behavior_sensor_rotate_key_press.c +++ b/app/src/behaviors/behavior_sensor_rotate_key_press.c @@ -17,75 +17,69 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); struct behavior_sensor_rotate_key_press_config { - u8_t usage_page; + u8_t usage_page; }; -struct behavior_sensor_rotate_key_press_data { }; +struct behavior_sensor_rotate_key_press_data {}; -static int behavior_sensor_rotate_key_press_init(struct device *dev) -{ - return 0; -}; +static int behavior_sensor_rotate_key_press_init(struct device *dev) { return 0; }; +static int on_sensor_binding_triggered(struct device *dev, struct device *sensor, + u32_t increment_keycode, u32_t decrement_keycode) { + const struct behavior_sensor_rotate_key_press_config *cfg = dev->config_info; + struct sensor_value value; + int err; + u32_t keycode; + struct keycode_state_changed *ev; + LOG_DBG("usage_page 0x%02X inc keycode 0x%02X dec keycode 0x%02X", cfg->usage_page, + increment_keycode, decrement_keycode); -static int on_sensor_binding_triggered(struct device *dev, struct device *sensor, u32_t increment_keycode, u32_t decrement_keycode) -{ - const struct behavior_sensor_rotate_key_press_config *cfg = dev->config_info; - struct sensor_value value; - int err; - u32_t keycode; - struct keycode_state_changed *ev; - LOG_DBG("usage_page 0x%02X inc keycode 0x%02X dec keycode 0x%02X", cfg->usage_page, increment_keycode, decrement_keycode); + err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value); - err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value); + if (err) { + LOG_WRN("Failed to ge sensor rotation value: %d", err); + return err; + } - if (err) { - LOG_WRN("Failed to ge sensor rotation value: %d", err); - return err; - } - - switch (value.val1) { + switch (value.val1) { case 1: - keycode = increment_keycode; - break; + keycode = increment_keycode; + break; case -1: - keycode = decrement_keycode; - break; + keycode = decrement_keycode; + break; default: - return -ENOTSUP; - } + return -ENOTSUP; + } - LOG_DBG("SEND %d", keycode); + LOG_DBG("SEND %d", keycode); + ev = new_keycode_state_changed(); + ev->usage_page = cfg->usage_page; + ev->keycode = keycode; + ev->state = true; + ZMK_EVENT_RAISE(ev); - ev = new_keycode_state_changed(); - ev->usage_page = cfg->usage_page; - ev->keycode = keycode; - ev->state = true; - ZMK_EVENT_RAISE(ev); + // TODO: Better way to do this? + k_msleep(5); - // TODO: Better way to do this? - k_msleep(5); - - ev = new_keycode_state_changed(); - ev->usage_page = cfg->usage_page; - ev->keycode = keycode; - ev->state = false; - return ZMK_EVENT_RAISE(ev); + ev = new_keycode_state_changed(); + ev->usage_page = cfg->usage_page; + ev->keycode = keycode; + ev->state = false; + return ZMK_EVENT_RAISE(ev); } static const struct behavior_driver_api behavior_sensor_rotate_key_press_driver_api = { - .sensor_binding_triggered = on_sensor_binding_triggered -}; + .sensor_binding_triggered = on_sensor_binding_triggered}; -#define KP_INST(n) \ - static const struct behavior_sensor_rotate_key_press_config behavior_sensor_rotate_key_press_config_##n = { \ - .usage_page = DT_INST_PROP(n, usage_page) \ - }; \ - static struct behavior_sensor_rotate_key_press_data behavior_sensor_rotate_key_press_data_##n; \ - DEVICE_AND_API_INIT(behavior_sensor_rotate_key_press_##n, DT_INST_LABEL(n), behavior_sensor_rotate_key_press_init, \ - &behavior_sensor_rotate_key_press_data_##n, \ - &behavior_sensor_rotate_key_press_config_##n, \ - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &behavior_sensor_rotate_key_press_driver_api); +#define KP_INST(n) \ + static const struct behavior_sensor_rotate_key_press_config \ + behavior_sensor_rotate_key_press_config_##n = {.usage_page = DT_INST_PROP(n, usage_page)}; \ + static struct behavior_sensor_rotate_key_press_data behavior_sensor_rotate_key_press_data_##n; \ + DEVICE_AND_API_INIT( \ + behavior_sensor_rotate_key_press_##n, DT_INST_LABEL(n), \ + behavior_sensor_rotate_key_press_init, &behavior_sensor_rotate_key_press_data_##n, \ + &behavior_sensor_rotate_key_press_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_sensor_rotate_key_press_driver_api); DT_INST_FOREACH_STATUS_OKAY(KP_INST) \ No newline at end of file diff --git a/app/src/behaviors/behavior_toggle_layer.c b/app/src/behaviors/behavior_toggle_layer.c index c6d52251..28194519 100644 --- a/app/src/behaviors/behavior_toggle_layer.c +++ b/app/src/behaviors/behavior_toggle_layer.c @@ -14,30 +14,21 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -struct behavior_tog_config -{ -}; -struct behavior_tog_data -{ -}; +struct behavior_tog_config {}; +struct behavior_tog_data {}; -static int behavior_tog_init(struct device *dev) -{ - return 0; -}; +static int behavior_tog_init(struct device *dev) { return 0; }; -static int tog_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) -{ - LOG_DBG("position %d layer %d", position, layer); +static int tog_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) { + LOG_DBG("position %d layer %d", position, layer); - return zmk_keymap_layer_toggle(layer); + return zmk_keymap_layer_toggle(layer); } -static int tog_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) -{ - LOG_DBG("position %d layer %d", position, layer); +static int tog_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) { + LOG_DBG("position %d layer %d", position, layer); - return 0; + return 0; } static const struct behavior_driver_api behavior_tog_driver_api = { @@ -49,8 +40,6 @@ static const struct behavior_tog_config behavior_tog_config = {}; static struct behavior_tog_data behavior_tog_data; -DEVICE_AND_API_INIT(behavior_tog, DT_INST_LABEL(0), behavior_tog_init, - &behavior_tog_data, - &behavior_tog_config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, +DEVICE_AND_API_INIT(behavior_tog, DT_INST_LABEL(0), behavior_tog_init, &behavior_tog_data, + &behavior_tog_config, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_tog_driver_api); diff --git a/app/src/behaviors/behavior_transparent.c b/app/src/behaviors/behavior_transparent.c index 51f682b5..f7852f39 100644 --- a/app/src/behaviors/behavior_transparent.c +++ b/app/src/behaviors/behavior_transparent.c @@ -13,36 +13,30 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -struct behavior_transparent_config { }; -struct behavior_transparent_data { }; +struct behavior_transparent_config {}; +struct behavior_transparent_data {}; -static int behavior_transparent_init(struct device *dev) -{ - return 0; -}; +static int behavior_transparent_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, u32_t _param2) -{ - return 1; +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, + u32_t _param2) { + return 1; } -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, u32_t _param2) -{ - return 1; +static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, + u32_t _param2) { + return 1; } static const struct behavior_driver_api behavior_transparent_driver_api = { - .binding_pressed = on_keymap_binding_pressed, - .binding_released = on_keymap_binding_released, + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, }; - static const struct behavior_transparent_config behavior_transparent_config = {}; static struct behavior_transparent_data behavior_transparent_data; DEVICE_AND_API_INIT(behavior_transparent, DT_INST_LABEL(0), behavior_transparent_init, - &behavior_transparent_data, - &behavior_transparent_config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, - &behavior_transparent_driver_api); \ No newline at end of file + &behavior_transparent_data, &behavior_transparent_config, APPLICATION, + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_transparent_driver_api); \ No newline at end of file diff --git a/app/src/ble.c b/app/src/ble.c index a2a8207a..49e2b3b0 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -45,7 +45,6 @@ static u8_t passkey_digit = 0; #define PROFILE_COUNT CONFIG_BT_MAX_PAIRED #endif - static struct zmk_ble_profile profiles[PROFILE_COUNT]; static u8_t active_profile; @@ -53,13 +52,12 @@ static const struct bt_data zmk_ble_ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID16_SOME, #if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) - 0x12, 0x18, /* HID Service */ + 0x12, 0x18, /* HID Service */ #endif 0x0f, 0x18 /* Battery Service */ - ), + ), #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) - BT_DATA_BYTES(BT_DATA_UUID128_ALL, - ZMK_SPLIT_BT_SERVICE_UUID) + BT_DATA_BYTES(BT_DATA_UUID128_ALL, ZMK_SPLIT_BT_SERVICE_UUID) #endif }; @@ -69,8 +67,7 @@ static bt_addr_le_t peripheral_addr; #endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */ -static void raise_profile_changed_event() -{ +static void raise_profile_changed_event() { struct ble_active_profile_changed *ev = new_ble_active_profile_changed(); ev->index = active_profile; ev->profile = &profiles[active_profile]; @@ -78,13 +75,11 @@ static void raise_profile_changed_event() ZMK_EVENT_RAISE(ev); } -static bool active_profile_is_open() -{ +static bool active_profile_is_open() { return !bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY); } -void set_profile_address(u8_t index, const bt_addr_le_t *addr) -{ +void set_profile_address(u8_t index, const bt_addr_le_t *addr) { char setting_name[15]; char addr_str[BT_ADDR_LE_STR_LEN]; @@ -97,8 +92,7 @@ void set_profile_address(u8_t index, const bt_addr_le_t *addr) raise_profile_changed_event(); } -int zmk_ble_adv_pause() -{ +int zmk_ble_adv_pause() { int err = bt_le_adv_stop(); if (err) { LOG_ERR("Failed to stop advertising (err %d)", err); @@ -108,16 +102,12 @@ int zmk_ble_adv_pause() return 0; }; -int zmk_ble_adv_resume() -{ - LOG_DBG("active_profile %d, directed? %s", active_profile, active_profile_is_open() ? "no" : "yes"); +int zmk_ble_adv_resume() { + LOG_DBG("active_profile %d, directed? %s", active_profile, + active_profile_is_open() ? "no" : "yes"); - int err = bt_le_adv_start( - BT_LE_ADV_CONN_NAME, - zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), - NULL, 0); - if (err) - { + int err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); + if (err) { LOG_ERR("Advertising failed to start (err %d)", err); return err; } @@ -125,10 +115,9 @@ int zmk_ble_adv_resume() return 0; }; -int zmk_ble_clear_bonds() -{ +int zmk_ble_clear_bonds() { LOG_DBG(""); - + if (bt_addr_le_cmp(&profiles[active_profile].peer, BT_ADDR_LE_ANY)) { LOG_DBG("Unpairing!"); bt_unpair(BT_ID_DEFAULT, &profiles[active_profile].peer); @@ -138,8 +127,7 @@ int zmk_ble_clear_bonds() return 0; }; -int zmk_ble_prof_select(u8_t index) -{ +int zmk_ble_prof_select(u8_t index) { LOG_DBG("profile %d", index); if (active_profile == index) { return 0; @@ -148,35 +136,26 @@ int zmk_ble_prof_select(u8_t index) active_profile = index; return settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); - raise_profile_changed_event(); + raise_profile_changed_event(); }; -int zmk_ble_prof_next() -{ +int zmk_ble_prof_next() { LOG_DBG(""); return zmk_ble_prof_select((active_profile + 1) % PROFILE_COUNT); }; -int zmk_ble_prof_prev() -{ +int zmk_ble_prof_prev() { LOG_DBG(""); return zmk_ble_prof_select((active_profile + PROFILE_COUNT - 1) % PROFILE_COUNT); }; -bt_addr_le_t *zmk_ble_active_profile_addr() -{ - return &profiles[active_profile].peer; -} +bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].peer; } -char *zmk_ble_active_profile_name() -{ - return profiles[active_profile].name; -} +char *zmk_ble_active_profile_name() { return profiles[active_profile].name; } #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) -void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) -{ +void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) { memcpy(&peripheral_addr, addr, sizeof(bt_addr_le_t)); settings_save_one("ble/peripheral_address", addr, sizeof(bt_addr_le_t)); } @@ -185,8 +164,8 @@ void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) #if IS_ENABLED(CONFIG_SETTINGS) -static int ble_profiles_handle_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) -{ +static int ble_profiles_handle_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { const char *next; LOG_DBG("Setting BLE value %s", log_strdup(name)); @@ -200,7 +179,8 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c } if (len != sizeof(struct zmk_ble_profile)) { - LOG_ERR("Invalid profile size (got %d expected %d)", len, sizeof(struct zmk_ble_profile)); + LOG_ERR("Invalid profile size (got %d expected %d)", len, + sizeof(struct zmk_ble_profile)); return -EINVAL; } @@ -247,19 +227,14 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c return 0; }; -struct settings_handler profiles_handler = { - .name = "ble", - .h_set = ble_profiles_handle_set -}; +struct settings_handler profiles_handler = {.name = "ble", .h_set = ble_profiles_handle_set}; #endif /* IS_ENABLED(CONFIG_SETTINGS) */ -static void connected(struct bt_conn *conn, u8_t err) -{ +static void connected(struct bt_conn *conn, u8_t err) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - if (err) - { + if (err) { LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr), err); return; } @@ -272,14 +247,12 @@ static void connected(struct bt_conn *conn, u8_t err) bt_conn_le_phy_update(conn, BT_CONN_LE_PHY_PARAM_2M); #endif - if (bt_conn_set_security(conn, BT_SECURITY_L2)) - { + if (bt_conn_set_security(conn, BT_SECURITY_L2)) { LOG_ERR("Failed to set security"); } } -static void disconnected(struct bt_conn *conn, u8_t reason) -{ +static void disconnected(struct bt_conn *conn, u8_t reason) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); @@ -287,29 +260,24 @@ static void disconnected(struct bt_conn *conn, u8_t reason) LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason); #if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) - // if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, bt_conn_get_dst(conn))) { + // if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, + // bt_conn_get_dst(conn))) { // zmk_ble_adv_resume(); // } -#else +#else // zmk_ble_adv_resume(); #endif } -static void security_changed(struct bt_conn *conn, bt_security_t level, - enum bt_security_err err) -{ +static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - if (!err) - { + if (!err) { LOG_DBG("Security changed: %s level %u", log_strdup(addr), level); - } - else - { - LOG_ERR("Security failed: %s level %u err %d", log_strdup(addr), level, - err); + } else { + LOG_ERR("Security failed: %s level %u err %d", log_strdup(addr), level, err); } } @@ -319,8 +287,7 @@ static struct bt_conn_cb conn_callbacks = { .security_changed = security_changed, }; -static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) -{ +static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); @@ -330,8 +297,7 @@ static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) #ifdef CONFIG_ZMK_BLE_PASSKEY_ENTRY -static void auth_passkey_entry(struct bt_conn *conn) -{ +static void auth_passkey_entry(struct bt_conn *conn) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); @@ -342,14 +308,12 @@ static void auth_passkey_entry(struct bt_conn *conn) #endif -static void auth_cancel(struct bt_conn *conn) -{ +static void auth_cancel(struct bt_conn *conn) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - if (auth_passkey_entry_conn) - { + if (auth_passkey_entry_conn) { bt_conn_unref(auth_passkey_entry_conn); auth_passkey_entry_conn = NULL; } @@ -360,8 +324,8 @@ static void auth_cancel(struct bt_conn *conn) } #if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) -static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, const struct bt_conn_pairing_feat *const feat) -{ +static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, + const struct bt_conn_pairing_feat *const feat) { struct bt_conn_info info; bt_conn_get_info(conn, &info); @@ -375,8 +339,7 @@ static enum bt_security_err auth_pairing_accept(struct bt_conn *conn, const stru }; #endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */ -static void auth_pairing_complete(struct bt_conn *conn, bool bonded) -{ +static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { struct bt_conn_info info; char addr[BT_ADDR_LE_STR_LEN]; const bt_addr_le_t *dst = bt_conn_get_dst(conn); @@ -413,12 +376,9 @@ static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { .cancel = auth_cancel, }; - -static void zmk_ble_ready(int err) -{ +static void zmk_ble_ready(int err) { LOG_DBG("ready? %d", err); - if (err) - { + if (err) { LOG_ERR("Bluetooth init failed (err %d)", err); return; } @@ -426,12 +386,10 @@ static void zmk_ble_ready(int err) zmk_ble_adv_resume(); } -static int zmk_ble_init(struct device *_arg) -{ +static int zmk_ble_init(struct device *_arg) { int err = bt_enable(NULL); - if (err) - { + if (err) { LOG_ERR("BLUETOOTH FAILED (%d)", err); return err; } @@ -475,8 +433,7 @@ static int zmk_ble_init(struct device *_arg) return 0; } -int zmk_ble_unpair_all() -{ +int zmk_ble_unpair_all() { int resp = 0; for (int i = BT_ID_DEFAULT; i < CONFIG_BT_ID_MAX; i++) { @@ -490,17 +447,14 @@ int zmk_ble_unpair_all() return resp; }; -bool zmk_ble_handle_key_user(struct zmk_key_event *key_event) -{ +bool zmk_ble_handle_key_user(struct zmk_key_event *key_event) { zmk_key key = key_event->key; - if (!auth_passkey_entry_conn) - { + if (!auth_passkey_entry_conn) { return true; } - if (key < NUM_1 || key > NUM_0) - { + if (key < NUM_1 || key > NUM_0) { return true; } @@ -508,11 +462,9 @@ bool zmk_ble_handle_key_user(struct zmk_key_event *key_event) passkey_entries[passkey_digit++] = val; - if (passkey_digit == 6) - { + if (passkey_digit == 6) { u32_t passkey = 0; - for (int i = 5; i >= 0; i--) - { + for (int i = 5; i >= 0; i--) { passkey = (passkey * 10) + val; } bt_conn_auth_passkey_entry(auth_passkey_entry_conn, passkey); @@ -523,6 +475,4 @@ bool zmk_ble_handle_key_user(struct zmk_key_event *key_event) return false; } -SYS_INIT(zmk_ble_init, - APPLICATION, - CONFIG_ZMK_BLE_INIT_PRIORITY); +SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); diff --git a/app/src/ble_unpair_combo.c b/app/src/ble_unpair_combo.c index 3633a5b0..b6e542de 100644 --- a/app/src/ble_unpair_combo.c +++ b/app/src/ble_unpair_combo.c @@ -18,14 +18,12 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include - static u8_t combo_state; const u32_t key_positions[] = DT_INST_PROP(0, key_positions); #define KP_LEN DT_INST_PROP_LEN(0, key_positions) -int index_for_key_position(u32_t kp) -{ +int index_for_key_position(u32_t kp) { for (int i = 0; i < KP_LEN; i++) { if (key_positions[i] == kp) { return i; @@ -35,8 +33,7 @@ int index_for_key_position(u32_t kp) return -1; } -int unpair_combo_listener(const struct zmk_event_header *eh) -{ +int unpair_combo_listener(const struct zmk_event_header *eh) { if (is_position_state_changed(eh)) { const struct position_state_changed *psc = cast_position_state_changed(eh); @@ -51,8 +48,7 @@ int unpair_combo_listener(const struct zmk_event_header *eh) return 0; }; -void unpair_combo_work_handler(struct k_work *work) -{ +void unpair_combo_work_handler(struct k_work *work) { for (int i = 0; i < KP_LEN; i++) { if (!(combo_state & BIT(i))) { LOG_DBG("Key position %d not held, skipping unpair combo", key_positions[i]); @@ -65,8 +61,7 @@ void unpair_combo_work_handler(struct k_work *work) struct k_delayed_work unpair_combo_work; -int zmk_ble_unpair_combo_init(struct device *_unused) -{ +int zmk_ble_unpair_combo_init(struct device *_unused) { k_delayed_work_init(&unpair_combo_work, unpair_combo_work_handler); k_delayed_work_submit(&unpair_combo_work, K_SECONDS(2)); @@ -76,8 +71,6 @@ int zmk_ble_unpair_combo_init(struct device *_unused) ZMK_LISTENER(zmk_ble_unpair_combo, unpair_combo_listener); ZMK_SUBSCRIPTION(zmk_ble_unpair_combo, position_state_changed); -SYS_INIT(zmk_ble_unpair_combo_init, - APPLICATION, - CONFIG_APPLICATION_INIT_PRIORITY); +SYS_INIT(zmk_ble_unpair_combo_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/display.c b/app/src/display.c index dca462e4..ecd19086 100644 --- a/app/src/display.c +++ b/app/src/display.c @@ -20,8 +20,7 @@ static struct device *display; static lv_obj_t *screen; -int zmk_display_init() -{ +int zmk_display_init() { lv_obj_t *hello_world_label; lv_obj_t *count_label; @@ -48,8 +47,7 @@ int zmk_display_init() return 0; } -void zmk_display_task_handler() -{ +void zmk_display_task_handler() { lv_tick_inc(10); lv_task_handler(); k_sleep(K_MSEC(10)); diff --git a/app/src/endpoints.c b/app/src/endpoints.c index 61e86cee..ae785870 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -12,27 +12,24 @@ #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -int zmk_endpoints_send_report(u8_t usage_page) -{ +int zmk_endpoints_send_report(u8_t usage_page) { int err; struct zmk_hid_keypad_report *keypad_report; struct zmk_hid_consumer_report *consumer_report; LOG_DBG("usage page 0x%02X", usage_page); - switch (usage_page) - { + switch (usage_page) { case USAGE_KEYPAD: keypad_report = zmk_hid_get_keypad_report(); #ifdef CONFIG_ZMK_USB - if (zmk_usb_hid_send_report((u8_t *)keypad_report, sizeof(struct zmk_hid_keypad_report)) != 0) - { + if (zmk_usb_hid_send_report((u8_t *)keypad_report, sizeof(struct zmk_hid_keypad_report)) != + 0) { LOG_DBG("USB Send Failed"); } #endif /* CONFIG_ZMK_USB */ #ifdef CONFIG_ZMK_BLE err = zmk_hog_send_keypad_report(&keypad_report->body); - if (err) - { + if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); } #endif /* CONFIG_ZMK_BLE */ @@ -41,16 +38,15 @@ int zmk_endpoints_send_report(u8_t usage_page) case USAGE_CONSUMER: consumer_report = zmk_hid_get_consumer_report(); #ifdef CONFIG_ZMK_USB - if (zmk_usb_hid_send_report((u8_t *)consumer_report, sizeof(struct zmk_hid_consumer_report)) != 0) - { + if (zmk_usb_hid_send_report((u8_t *)consumer_report, + sizeof(struct zmk_hid_consumer_report)) != 0) { LOG_DBG("USB Send Failed"); } #endif /* CONFIG_ZMK_USB */ #ifdef CONFIG_ZMK_BLE err = zmk_hog_send_consumer_report(&consumer_report->body); - if (err) - { + if (err) { LOG_ERR("FAILED TO SEND OVER HOG: %d", err); } #endif /* CONFIG_ZMK_BLE */ @@ -63,4 +59,3 @@ int zmk_endpoints_send_report(u8_t usage_page) return 0; } - diff --git a/app/src/event_manager.c b/app/src/event_manager.c index 6d37e4e6..226f3ce8 100644 --- a/app/src/event_manager.c +++ b/app/src/event_manager.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: MIT */ - + #include #include @@ -11,15 +11,13 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include -extern struct zmk_event_type* __event_type_start[]; -extern struct zmk_event_type* __event_type_end[]; +extern struct zmk_event_type *__event_type_start[]; +extern struct zmk_event_type *__event_type_end[]; extern struct zmk_event_subscription __event_subscriptions_start[]; extern struct zmk_event_subscription __event_subscriptions_end[]; - -int zmk_event_manager_handle_from(struct zmk_event_header *event, u8_t start_index) -{ +int zmk_event_manager_handle_from(struct zmk_event_header *event, u8_t start_index) { int ret = 0; u8_t len = __event_subscriptions_end - __event_subscriptions_start; for (int i = start_index; i < len; i++) { @@ -31,15 +29,15 @@ int zmk_event_manager_handle_from(struct zmk_event_header *event, u8_t start_ind goto release; } else if (ret > 0) { switch (ret) { - case ZMK_EV_EVENT_HANDLED: - LOG_DBG("Listener handled the event"); - ret = 0; - goto release; - case ZMK_EV_EVENT_CAPTURED: - LOG_DBG("Listener captured the event"); - event->last_listener_index = i; - // Listeners are expected to free events they capture - return 0; + case ZMK_EV_EVENT_HANDLED: + LOG_DBG("Listener handled the event"); + ret = 0; + goto release; + case ZMK_EV_EVENT_CAPTURED: + LOG_DBG("Listener captured the event"); + event->last_listener_index = i; + // Listeners are expected to free events they capture + return 0; } } } @@ -50,19 +48,18 @@ release: return ret; } -int zmk_event_manager_raise(struct zmk_event_header *event) -{ +int zmk_event_manager_raise(struct zmk_event_header *event) { return zmk_event_manager_handle_from(event, 0); } -int zmk_event_manager_raise_after(struct zmk_event_header *event, const struct zmk_listener *listener) -{ +int zmk_event_manager_raise_after(struct zmk_event_header *event, + const struct zmk_listener *listener) { u8_t len = __event_subscriptions_end - __event_subscriptions_start; for (int i = 0; i < len; i++) { struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i; if (ev_sub->event_type == event->event && ev_sub->listener == listener) { - return zmk_event_manager_handle_from(event, i+1); + return zmk_event_manager_handle_from(event, i + 1); } } @@ -71,8 +68,8 @@ int zmk_event_manager_raise_after(struct zmk_event_header *event, const struct z return -EINVAL; } -int zmk_event_manager_raise_at(struct zmk_event_header *event, const struct zmk_listener *listener) -{ +int zmk_event_manager_raise_at(struct zmk_event_header *event, + const struct zmk_listener *listener) { u8_t len = __event_subscriptions_end - __event_subscriptions_start; for (int i = 0; i < len; i++) { struct zmk_event_subscription *ev_sub = __event_subscriptions_start + i; @@ -87,7 +84,6 @@ int zmk_event_manager_raise_at(struct zmk_event_header *event, const struct zmk_ return -EINVAL; } -int zmk_event_manager_release(struct zmk_event_header *event) -{ +int zmk_event_manager_release(struct zmk_event_header *event) { return zmk_event_manager_handle_from(event, event->last_listener_index + 1); } diff --git a/app/src/hid.c b/app/src/hid.c index 07fc3a0b..f80906cc 100644 --- a/app/src/hid.c +++ b/app/src/hid.c @@ -10,41 +10,27 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include static struct zmk_hid_keypad_report kp_report = { - .report_id = 1, - .body = { - .modifiers = 0, - .keys = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}; + .report_id = 1, .body = {.modifiers = 0, .keys = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}; -static struct zmk_hid_consumer_report consumer_report = { - .report_id = 2, - .body = { - .keys = {0,0,0,0,0,0}}}; +static struct zmk_hid_consumer_report consumer_report = {.report_id = 2, + .body = {.keys = {0, 0, 0, 0, 0, 0}}}; -#define _TOGGLE_MOD(mod, state) \ - if (modifier > MOD_RGUI) \ - { \ - return -EINVAL; \ - } \ - WRITE_BIT(kp_report.body.modifiers, mod, state); \ +#define _TOGGLE_MOD(mod, state) \ + if (modifier > MOD_RGUI) { \ + return -EINVAL; \ + } \ + WRITE_BIT(kp_report.body.modifiers, mod, state); \ return 0; -int zmk_hid_register_mod(zmk_mod modifier) -{ - _TOGGLE_MOD(modifier, true); -} -int zmk_hid_unregister_mod(zmk_mod modifier) -{ - _TOGGLE_MOD(modifier, false); -} +int zmk_hid_register_mod(zmk_mod modifier) { _TOGGLE_MOD(modifier, true); } +int zmk_hid_unregister_mod(zmk_mod modifier) { _TOGGLE_MOD(modifier, false); } -int zmk_hid_register_mods(zmk_mod_flags modifiers) -{ +int zmk_hid_register_mods(zmk_mod_flags modifiers) { kp_report.body.modifiers |= modifiers; return 0; } -int zmk_hid_unregister_mods(zmk_mod_flags modifiers) -{ +int zmk_hid_unregister_mods(zmk_mod_flags modifiers) { kp_report.body.modifiers &= ~modifiers; return 0; } @@ -67,28 +53,21 @@ int zmk_hid_unregister_mods(zmk_mod_flags modifiers) #define TOGGLE_KEY(code, val) WRITE_BIT(kp_report.body.keys[code / 8], code % 8, val) -#define TOGGLE_CONSUMER(match, val) \ - for (int idx = 0; idx < MAX_KEYS; idx++) \ - { \ - if (consumer_report.body.keys[idx] != match) \ - { \ - continue; \ - } \ - consumer_report.body.keys[idx] = val; \ - break; \ +#define TOGGLE_CONSUMER(match, val) \ + for (int idx = 0; idx < MAX_KEYS; idx++) { \ + if (consumer_report.body.keys[idx] != match) { \ + continue; \ + } \ + consumer_report.body.keys[idx] = val; \ + break; \ } - -int zmk_hid_keypad_press(zmk_key code) -{ - if (code >= LCTL && code <= RGUI) - { +int zmk_hid_keypad_press(zmk_key code) { + if (code >= LCTL && code <= RGUI) { return zmk_hid_register_mod(code - LCTL); } - - if (code > ZMK_HID_MAX_KEYCODE) - { + if (code > ZMK_HID_MAX_KEYCODE) { return -EINVAL; } @@ -99,15 +78,12 @@ int zmk_hid_keypad_press(zmk_key code) return 0; }; -int zmk_hid_keypad_release(zmk_key code) -{ - if (code >= LCTL && code <= RGUI) - { +int zmk_hid_keypad_release(zmk_key code) { + if (code >= LCTL && code <= RGUI) { return zmk_hid_unregister_mod(code - LCTL); } - if (code > ZMK_HID_MAX_KEYCODE) - { + if (code > ZMK_HID_MAX_KEYCODE) { return -EINVAL; } @@ -118,25 +94,20 @@ int zmk_hid_keypad_release(zmk_key code) return 0; }; -int zmk_hid_consumer_press(zmk_key code) -{ +int zmk_hid_consumer_press(zmk_key code) { TOGGLE_CONSUMER(0U, code); return 0; }; - -int zmk_hid_consumer_release(zmk_key code) -{ +int zmk_hid_consumer_release(zmk_key code) { TOGGLE_CONSUMER(code, 0U); return 0; }; -struct zmk_hid_keypad_report *zmk_hid_get_keypad_report() -{ +struct zmk_hid_keypad_report *zmk_hid_get_keypad_report() { return &kp_report; } -struct zmk_hid_consumer_report *zmk_hid_get_consumer_report() -{ +struct zmk_hid_consumer_report *zmk_hid_get_consumer_report() { return &consumer_report; } diff --git a/app/src/hid_listener.c b/app/src/hid_listener.c index 9f68ca20..4467e6d4 100644 --- a/app/src/hid_listener.c +++ b/app/src/hid_listener.c @@ -15,90 +15,84 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +static int hid_listener_keycode_pressed(u8_t usage_page, u32_t keycode) { + int err; + LOG_DBG("usage_page 0x%02X keycode 0x%02X", usage_page, keycode); -static int hid_listener_keycode_pressed(u8_t usage_page, u32_t keycode) -{ - int err; - LOG_DBG("usage_page 0x%02X keycode 0x%02X", usage_page, keycode); - - switch (usage_page) { - case USAGE_KEYPAD: - err = zmk_hid_keypad_press(keycode); - if (err) { - LOG_ERR("Unable to press keycode"); - return err; + switch (usage_page) { + case USAGE_KEYPAD: + err = zmk_hid_keypad_press(keycode); + if (err) { + LOG_ERR("Unable to press keycode"); + return err; + } + break; + case USAGE_CONSUMER: + err = zmk_hid_consumer_press(keycode); + if (err) { + LOG_ERR("Unable to press keycode"); + return err; + } + break; } - break; - case USAGE_CONSUMER: - err = zmk_hid_consumer_press(keycode); - if (err) { - LOG_ERR("Unable to press keycode"); - return err; - } - break; - } - return zmk_endpoints_send_report(usage_page); + return zmk_endpoints_send_report(usage_page); } -static int hid_listener_keycode_released(u8_t usage_page, u32_t keycode) -{ - int err; - LOG_DBG("usage_page 0x%02X keycode 0x%02X", usage_page, keycode); - - switch (usage_page) { - case USAGE_KEYPAD: - err = zmk_hid_keypad_release(keycode); - if (err) { - LOG_ERR("Unable to release keycode"); - return err; +static int hid_listener_keycode_released(u8_t usage_page, u32_t keycode) { + int err; + LOG_DBG("usage_page 0x%02X keycode 0x%02X", usage_page, keycode); + + switch (usage_page) { + case USAGE_KEYPAD: + err = zmk_hid_keypad_release(keycode); + if (err) { + LOG_ERR("Unable to release keycode"); + return err; + } + break; + case USAGE_CONSUMER: + err = zmk_hid_consumer_release(keycode); + if (err) { + LOG_ERR("Unable to release keycode"); + return err; + } + break; } - break; - case USAGE_CONSUMER: - err = zmk_hid_consumer_release(keycode); - if (err) { - LOG_ERR("Unable to release keycode"); - return err; - } - break; - } - return zmk_endpoints_send_report(usage_page); + return zmk_endpoints_send_report(usage_page); } -static int hid_listener_modifiers_pressed(zmk_mod_flags modifiers) -{ - LOG_DBG("modifiers %d", modifiers); - - zmk_hid_register_mods(modifiers); - return zmk_endpoints_send_report(USAGE_KEYPAD); +static int hid_listener_modifiers_pressed(zmk_mod_flags modifiers) { + LOG_DBG("modifiers %d", modifiers); + + zmk_hid_register_mods(modifiers); + return zmk_endpoints_send_report(USAGE_KEYPAD); } -static int hid_listener_modifiers_released(zmk_mod_flags modifiers) -{ - LOG_DBG("modifiers %d", modifiers); - - zmk_hid_unregister_mods(modifiers); - return zmk_endpoints_send_report(USAGE_KEYPAD); +static int hid_listener_modifiers_released(zmk_mod_flags modifiers) { + LOG_DBG("modifiers %d", modifiers); + + zmk_hid_unregister_mods(modifiers); + return zmk_endpoints_send_report(USAGE_KEYPAD); } -int hid_listener(const struct zmk_event_header *eh) -{ - if (is_keycode_state_changed(eh)) { - const struct keycode_state_changed *ev = cast_keycode_state_changed(eh); - if (ev->state) { - hid_listener_keycode_pressed(ev->usage_page, ev->keycode); - } else { - hid_listener_keycode_released(ev->usage_page, ev->keycode); +int hid_listener(const struct zmk_event_header *eh) { + if (is_keycode_state_changed(eh)) { + const struct keycode_state_changed *ev = cast_keycode_state_changed(eh); + if (ev->state) { + hid_listener_keycode_pressed(ev->usage_page, ev->keycode); + } else { + hid_listener_keycode_released(ev->usage_page, ev->keycode); + } + } else if (is_modifiers_state_changed(eh)) { + const struct modifiers_state_changed *ev = cast_modifiers_state_changed(eh); + if (ev->state) { + hid_listener_modifiers_pressed(ev->modifiers); + } else { + hid_listener_modifiers_released(ev->modifiers); + } } - } else if (is_modifiers_state_changed(eh)) { - const struct modifiers_state_changed *ev = cast_modifiers_state_changed(eh); - if (ev->state) { - hid_listener_modifiers_pressed(ev->modifiers); - } else { - hid_listener_modifiers_released(ev->modifiers); - } - } - return 0; + return 0; } ZMK_LISTENER(hid_listener, hid_listener); diff --git a/app/src/hog.c b/app/src/hog.c index 93e6d9b3..11349acd 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -17,21 +17,18 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include -enum -{ +enum { HIDS_REMOTE_WAKE = BIT(0), HIDS_NORMALLY_CONNECTABLE = BIT(1), }; -struct hids_info -{ +struct hids_info { u16_t version; /* version number of base USB HID Specification */ u8_t code; /* country HID Device hardware is localized for. */ u8_t flags; } __packed; -struct hids_report -{ +struct hids_report { u8_t id; /* report id */ u8_t type; /* report type */ } __packed; @@ -42,8 +39,7 @@ static struct hids_info info = { .flags = HIDS_NORMALLY_CONNECTABLE & HIDS_REMOTE_WAKE, }; -enum -{ +enum { HIDS_INPUT = 0x01, HIDS_OUTPUT = 0x02, HIDS_FEATURE = 0x03, @@ -63,31 +59,37 @@ static bool host_requests_notification = false; static u8_t ctrl_point; // static u8_t proto_mode; -static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) -{ - return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, sizeof(struct hids_info)); +static ssize_t read_hids_info(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, + u16_t len, u16_t offset) { + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, + sizeof(struct hids_info)); } -static ssize_t read_hids_report_ref(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) -{ - return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, sizeof(struct hids_report)); +static ssize_t read_hids_report_ref(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, u16_t len, u16_t offset) { + return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data, + sizeof(struct hids_report)); } -static ssize_t read_hids_report_map(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) -{ - return bt_gatt_attr_read(conn, attr, buf, len, offset, zmk_hid_report_desc, sizeof(zmk_hid_report_desc)); +static ssize_t read_hids_report_map(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, u16_t len, u16_t offset) { + return bt_gatt_attr_read(conn, attr, buf, len, offset, zmk_hid_report_desc, + sizeof(zmk_hid_report_desc)); } -static ssize_t read_hids_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) -{ +static ssize_t read_hids_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, + void *buf, u16_t len, u16_t offset) { struct zmk_hid_keypad_report_body *report_body = &zmk_hid_get_keypad_report()->body; - return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, sizeof(struct zmk_hid_keypad_report_body)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_keypad_report_body)); } -static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) -{ +static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, + u16_t len, u16_t offset) { struct zmk_hid_consumer_report_body *report_body = &zmk_hid_get_consumer_report()->body; - return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, sizeof(struct zmk_hid_consumer_report_body)); + return bt_gatt_attr_read(conn, attr, buf, len, offset, report_body, + sizeof(struct zmk_hid_consumer_report_body)); } // static ssize_t write_proto_mode(struct bt_conn *conn, @@ -99,20 +101,15 @@ static ssize_t read_hids_consumer_input_report(struct bt_conn *conn, const struc // return 0; // } -static void input_ccc_changed(const struct bt_gatt_attr *attr, u16_t value) -{ +static void input_ccc_changed(const struct bt_gatt_attr *attr, u16_t value) { host_requests_notification = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0; } -static ssize_t write_ctrl_point(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - const void *buf, u16_t len, u16_t offset, - u8_t flags) -{ +static ssize_t write_ctrl_point(struct bt_conn *conn, const struct bt_gatt_attr *attr, + const void *buf, u16_t len, u16_t offset, u8_t flags) { u8_t *value = attr->user_data; - if (offset + len > sizeof(ctrl_point)) - { + if (offset + len > sizeof(ctrl_point)) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } @@ -122,35 +119,27 @@ static ssize_t write_ctrl_point(struct bt_conn *conn, } /* HID Service Declaration */ -BT_GATT_SERVICE_DEFINE(hog_svc, - BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS), - // BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_PROTOCOL_MODE, BT_GATT_CHRC_WRITE_WITHOUT_RESP, - // BT_GATT_PERM_WRITE, NULL, write_proto_mode, &proto_mode), - BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ, - BT_GATT_PERM_READ, read_hids_info, NULL, &info), - BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, - BT_GATT_PERM_READ, read_hids_report_map, NULL, NULL), +BT_GATT_SERVICE_DEFINE( + hog_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_HIDS), + // BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_PROTOCOL_MODE, BT_GATT_CHRC_WRITE_WITHOUT_RESP, + // BT_GATT_PERM_WRITE, NULL, write_proto_mode, &proto_mode), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_INFO, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_hids_info, + NULL, &info), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT_MAP, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, + read_hids_report_map, NULL, NULL), - BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, - BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, - BT_GATT_PERM_READ_ENCRYPT, - read_hids_input_report, NULL, NULL), - BT_GATT_CCC(input_ccc_changed, - BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), - BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ, - read_hids_report_ref, NULL, &input), - BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, - BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, - BT_GATT_PERM_READ_ENCRYPT, - read_hids_consumer_input_report, NULL, NULL), - BT_GATT_CCC(input_ccc_changed, - BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), - BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ, - read_hids_report_ref, NULL, &consumer_input), - BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, - BT_GATT_CHRC_WRITE_WITHOUT_RESP, - BT_GATT_PERM_WRITE, - NULL, write_ctrl_point, &ctrl_point)); + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ, read_hids_report_ref, NULL, + &input), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_REPORT, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, + BT_GATT_PERM_READ_ENCRYPT, read_hids_consumer_input_report, NULL, NULL), + BT_GATT_CCC(input_ccc_changed, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_HIDS_REPORT_REF, BT_GATT_PERM_READ, read_hids_report_ref, NULL, + &consumer_input), + BT_GATT_CHARACTERISTIC(BT_UUID_HIDS_CTRL_POINT, BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE, NULL, write_ctrl_point, &ctrl_point)); struct bt_conn *destination_connection() { struct bt_conn *conn; @@ -165,11 +154,9 @@ struct bt_conn *destination_connection() { } return conn; - } -int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report) -{ +int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report) { struct bt_conn *conn = destination_connection(); if (conn == NULL) { return -ENOTCONN; @@ -177,15 +164,16 @@ int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report) LOG_DBG("Sending to NULL? %s", conn == NULL ? "yes" : "no"); - return bt_gatt_notify(conn, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body)); + return bt_gatt_notify(conn, &hog_svc.attrs[5], report, + sizeof(struct zmk_hid_keypad_report_body)); }; -int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) -{ +int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { struct bt_conn *conn = destination_connection(); if (conn == NULL) { return -ENOTCONN; } - - return bt_gatt_notify(conn, &hog_svc.attrs[10], report, sizeof(struct zmk_hid_consumer_report_body)); + + return bt_gatt_notify(conn, &hog_svc.attrs[10], report, + sizeof(struct zmk_hid_consumer_report_body)); }; diff --git a/app/src/keymap.c b/app/src/keymap.c index b1c68f1e..a87ce04b 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -24,33 +24,38 @@ static u8_t zmk_keymap_layer_default = 0; #define DT_DRV_COMPAT zmk_keymap -#define LAYER_CHILD_LEN(node) 1+ +#define LAYER_CHILD_LEN(node) 1 + #define ZMK_KEYMAP_NODE DT_DRV_INST(0) -#define ZMK_KEYMAP_LAYERS_LEN (DT_INST_FOREACH_CHILD(0, LAYER_CHILD_LEN) 0) +#define ZMK_KEYMAP_LAYERS_LEN (DT_INST_FOREACH_CHILD(0, LAYER_CHILD_LEN) 0) #define LAYER_NODE(l) DT_PHANDLE_BY_IDX(ZMK_KEYMAP_NODE, layers, l) -#define _TRANSFORM_ENTRY(idx, layer) \ - { .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, bindings, idx)), \ - .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param1), (0), (DT_PHA_BY_IDX(layer, bindings, idx, param1))), \ - .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param2), (0), (DT_PHA_BY_IDX(layer, bindings, idx, param2))), \ - }, - -#define TRANSFORMED_LAYER(node) \ - { UTIL_LISTIFY(DT_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, node) }, +#define _TRANSFORM_ENTRY(idx, layer) \ + { \ + .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(layer, bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(layer, bindings, idx, param2))), \ + }, +#define TRANSFORMED_LAYER(node) {UTIL_LISTIFY(DT_PROP_LEN(node, bindings), _TRANSFORM_ENTRY, node)}, #if ZMK_KEYMAP_HAS_SENSORS -#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \ - { .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, sensor_bindings, idx)), \ - .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param1), (0), (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param1))), \ - .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param2), (0), (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param2))), \ - }, +#define _TRANSFORM_SENSOR_ENTRY(idx, layer) \ + { \ + .behavior_dev = DT_LABEL(DT_PHANDLE_BY_IDX(layer, sensor_bindings, idx)), \ + .param1 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param1), (0), \ + (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param1))), \ + .param2 = COND_CODE_0(DT_PHA_HAS_CELL_AT_IDX(layer, sensor_bindings, idx, param2), (0), \ + (DT_PHA_BY_IDX(layer, sensor_bindings, idx, param2))), \ + }, -#define SENSOR_LAYER(node) \ - COND_CODE_1(DT_NODE_HAS_PROP(node, sensor_bindings), \ - ({ UTIL_LISTIFY(DT_PROP_LEN(node, sensor_bindings), _TRANSFORM_SENSOR_ENTRY, node) }), \ - ({})), +#define SENSOR_LAYER(node) \ + COND_CODE_1( \ + DT_NODE_HAS_PROP(node, sensor_bindings), \ + ({UTIL_LISTIFY(DT_PROP_LEN(node, sensor_bindings), _TRANSFORM_SENSOR_ENTRY, node)}), \ + ({})), #endif /* ZMK_KEYMAP_HAS_SENSORS */ @@ -62,155 +67,142 @@ static u8_t zmk_keymap_layer_default = 0; static u32_t zmk_keymap_active_behavior_layer[ZMK_KEYMAP_LEN]; static struct zmk_behavior_binding zmk_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_LEN] = { - DT_INST_FOREACH_CHILD(0, TRANSFORMED_LAYER) -}; + DT_INST_FOREACH_CHILD(0, TRANSFORMED_LAYER)}; #if ZMK_KEYMAP_HAS_SENSORS -static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN][ZMK_KEYMAP_SENSORS_LEN] = { - DT_INST_FOREACH_CHILD(0, SENSOR_LAYER) -}; +static struct zmk_behavior_binding zmk_sensor_keymap[ZMK_KEYMAP_LAYERS_LEN] + [ZMK_KEYMAP_SENSORS_LEN] = { + DT_INST_FOREACH_CHILD(0, SENSOR_LAYER)}; #endif /* ZMK_KEYMAP_HAS_SENSORS */ -#define SET_LAYER_STATE(layer, state) \ - if (layer >= 32) \ - { \ - return -EINVAL; \ - } \ - WRITE_BIT(zmk_keymap_layer_state, layer, state); \ - return 0; +#define SET_LAYER_STATE(layer, state) \ + if (layer >= 32) { \ + return -EINVAL; \ + } \ + WRITE_BIT(zmk_keymap_layer_state, layer, state); \ + return 0; -bool zmk_keymap_layer_active(u8_t layer) -{ - return (zmk_keymap_layer_state & (BIT(layer))) == (BIT(layer)); +bool zmk_keymap_layer_active(u8_t layer) { + return (zmk_keymap_layer_state & (BIT(layer))) == (BIT(layer)); }; -int zmk_keymap_layer_activate(u8_t layer) -{ - SET_LAYER_STATE(layer, true); +int zmk_keymap_layer_activate(u8_t layer) { SET_LAYER_STATE(layer, true); }; + +int zmk_keymap_layer_deactivate(u8_t layer) { SET_LAYER_STATE(layer, false); }; + +int zmk_keymap_layer_toggle(u8_t layer) { + if (zmk_keymap_layer_active(layer)) { + return zmk_keymap_layer_deactivate(layer); + } + + return zmk_keymap_layer_activate(layer); }; -int zmk_keymap_layer_deactivate(u8_t layer) -{ - SET_LAYER_STATE(layer, false); -}; - -int zmk_keymap_layer_toggle(u8_t layer) -{ - if (zmk_keymap_layer_active(layer)) - { - return zmk_keymap_layer_deactivate(layer); - } - - return zmk_keymap_layer_activate(layer); -}; - -bool is_active_layer(u8_t layer, u32_t layer_state) -{ - return (layer_state & BIT(layer)) == BIT(layer) - || layer == zmk_keymap_layer_default; +bool is_active_layer(u8_t layer, u32_t layer_state) { + return (layer_state & BIT(layer)) == BIT(layer) || layer == zmk_keymap_layer_default; } -int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed) -{ - struct zmk_behavior_binding *binding = &zmk_keymap[layer][position]; - struct device *behavior; +int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed) { + struct zmk_behavior_binding *binding = &zmk_keymap[layer][position]; + struct device *behavior; - LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, log_strdup(binding->behavior_dev)); + LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, + log_strdup(binding->behavior_dev)); - behavior = device_get_binding(binding->behavior_dev); + behavior = device_get_binding(binding->behavior_dev); - if (!behavior) { - LOG_DBG("No behavior assigned to %d on layer %d", position, layer); - return 1; - } + if (!behavior) { + LOG_DBG("No behavior assigned to %d on layer %d", position, layer); + return 1; + } - if (pressed) { - return behavior_keymap_binding_pressed(behavior, position, binding->param1, binding->param2); - } else { - return behavior_keymap_binding_released(behavior, position, binding->param1, binding->param2); - } + if (pressed) { + return behavior_keymap_binding_pressed(behavior, position, binding->param1, + binding->param2); + } else { + return behavior_keymap_binding_released(behavior, position, binding->param1, + binding->param2); + } } - -int zmk_keymap_position_state_changed(u32_t position, bool pressed) -{ - for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= zmk_keymap_layer_default; layer--) - { - u32_t layer_state = pressed ? zmk_keymap_layer_state : zmk_keymap_active_behavior_layer[position]; - if (is_active_layer(layer, layer_state)) - { - int ret = zmk_keymap_apply_position_state(layer, position, pressed); - zmk_keymap_active_behavior_layer[position] = zmk_keymap_layer_state; +int zmk_keymap_position_state_changed(u32_t position, bool pressed) { + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= zmk_keymap_layer_default; layer--) { + u32_t layer_state = + pressed ? zmk_keymap_layer_state : zmk_keymap_active_behavior_layer[position]; + if (is_active_layer(layer, layer_state)) { + int ret = zmk_keymap_apply_position_state(layer, position, pressed); - if (ret > 0) { - LOG_DBG("behavior processing to continue to next layer"); - continue; - } else if (ret < 0) { - LOG_DBG("Behavior returned error: %d", ret); - return ret; - } else { - return ret; - } - } - } + zmk_keymap_active_behavior_layer[position] = zmk_keymap_layer_state; - return -ENOTSUP; + if (ret > 0) { + LOG_DBG("behavior processing to continue to next layer"); + continue; + } else if (ret < 0) { + LOG_DBG("Behavior returned error: %d", ret); + return ret; + } else { + return ret; + } + } + } + + return -ENOTSUP; } #if ZMK_KEYMAP_HAS_SENSORS -int zmk_keymap_sensor_triggered(u8_t sensor_number, struct device *sensor) -{ - for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= zmk_keymap_layer_default; layer--) - { - if (((zmk_keymap_layer_state & BIT(layer)) == BIT(layer) || layer == zmk_keymap_layer_default) && zmk_sensor_keymap[layer] != NULL) - { - struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_number]; - struct device *behavior; - int ret; +int zmk_keymap_sensor_triggered(u8_t sensor_number, struct device *sensor) { + for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= zmk_keymap_layer_default; layer--) { + if (((zmk_keymap_layer_state & BIT(layer)) == BIT(layer) || + layer == zmk_keymap_layer_default) && + zmk_sensor_keymap[layer] != NULL) { + struct zmk_behavior_binding *binding = &zmk_sensor_keymap[layer][sensor_number]; + struct device *behavior; + int ret; - LOG_DBG("layer: %d sensor_number: %d, binding name: %s", layer, sensor_number, log_strdup(binding->behavior_dev)); + LOG_DBG("layer: %d sensor_number: %d, binding name: %s", layer, sensor_number, + log_strdup(binding->behavior_dev)); - behavior = device_get_binding(binding->behavior_dev); + behavior = device_get_binding(binding->behavior_dev); - if (!behavior) { - LOG_DBG("No behavior assigned to %d on layer %d", sensor_number, layer); - continue; - } - - ret = behavior_sensor_keymap_binding_triggered(behavior, sensor, binding->param1, binding->param2); + if (!behavior) { + LOG_DBG("No behavior assigned to %d on layer %d", sensor_number, layer); + continue; + } - if (ret > 0) { - LOG_DBG("behavior processing to continue to next layer"); - continue; - } else if (ret < 0) { - LOG_DBG("Behavior returned error: %d", ret); - return ret; - } else { - return ret; - } - } - } + ret = behavior_sensor_keymap_binding_triggered(behavior, sensor, binding->param1, + binding->param2); - return -ENOTSUP; + if (ret > 0) { + LOG_DBG("behavior processing to continue to next layer"); + continue; + } else if (ret < 0) { + LOG_DBG("Behavior returned error: %d", ret); + return ret; + } else { + return ret; + } + } + } + + return -ENOTSUP; } #endif /* ZMK_KEYMAP_HAS_SENSORS */ -int keymap_listener(const struct zmk_event_header *eh) -{ - if (is_position_state_changed(eh)) { - const struct position_state_changed *ev = cast_position_state_changed(eh); - return zmk_keymap_position_state_changed(ev->position, ev->state); +int keymap_listener(const struct zmk_event_header *eh) { + if (is_position_state_changed(eh)) { + const struct position_state_changed *ev = cast_position_state_changed(eh); + return zmk_keymap_position_state_changed(ev->position, ev->state); #if ZMK_KEYMAP_HAS_SENSORS - } else if (is_sensor_event(eh)) { - const struct sensor_event *ev = cast_sensor_event(eh); - return zmk_keymap_sensor_triggered(ev->sensor_number, ev->sensor); + } else if (is_sensor_event(eh)) { + const struct sensor_event *ev = cast_sensor_event(eh); + return zmk_keymap_sensor_triggered(ev->sensor_number, ev->sensor); #endif /* ZMK_KEYMAP_HAS_SENSORS */ - } + } - return -ENOTSUP; + return -ENOTSUP; } ZMK_LISTENER(keymap, keymap_listener); @@ -219,4 +211,3 @@ ZMK_SUBSCRIPTION(keymap, position_state_changed); #if ZMK_KEYMAP_HAS_SENSORS ZMK_SUBSCRIPTION(keymap, sensor_event); #endif /* ZMK_KEYMAP_HAS_SENSORS */ - diff --git a/app/src/kscan.c b/app/src/kscan.c index 7a4d3a49..0046f5ca 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -18,61 +18,55 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define ZMK_KSCAN_EVENT_STATE_PRESSED 0 #define ZMK_KSCAN_EVENT_STATE_RELEASED 1 -struct zmk_kscan_event -{ - u32_t row; - u32_t column; - u32_t state; +struct zmk_kscan_event { + u32_t row; + u32_t column; + u32_t state; }; -struct zmk_kscan_msg_processor -{ - struct k_work work; +struct zmk_kscan_msg_processor { + struct k_work work; } msg_processor; K_MSGQ_DEFINE(zmk_kscan_msgq, sizeof(struct zmk_kscan_event), CONFIG_ZMK_KSCAN_EVENT_QUEUE_SIZE, 4); -static void zmk_kscan_callback(struct device *dev, u32_t row, u32_t column, bool pressed) -{ - struct zmk_kscan_event ev = { - .row = row, - .column = column, - .state = (pressed ? ZMK_KSCAN_EVENT_STATE_PRESSED : ZMK_KSCAN_EVENT_STATE_RELEASED)}; +static void zmk_kscan_callback(struct device *dev, u32_t row, u32_t column, bool pressed) { + struct zmk_kscan_event ev = { + .row = row, + .column = column, + .state = (pressed ? ZMK_KSCAN_EVENT_STATE_PRESSED : ZMK_KSCAN_EVENT_STATE_RELEASED)}; - k_msgq_put(&zmk_kscan_msgq, &ev, K_NO_WAIT); - k_work_submit(&msg_processor.work); + k_msgq_put(&zmk_kscan_msgq, &ev, K_NO_WAIT); + k_work_submit(&msg_processor.work); } -void zmk_kscan_process_msgq(struct k_work *item) -{ - struct zmk_kscan_event ev; +void zmk_kscan_process_msgq(struct k_work *item) { + struct zmk_kscan_event ev; - while (k_msgq_get(&zmk_kscan_msgq, &ev, K_NO_WAIT) == 0) - { - bool pressed = (ev.state == ZMK_KSCAN_EVENT_STATE_PRESSED); - u32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column); - struct position_state_changed *pos_ev; - LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s\n", ev.row, ev.column, position, (pressed ? "true" : "false")); - pos_ev = new_position_state_changed(); - pos_ev->state = pressed; - pos_ev->position = position; - ZMK_EVENT_RAISE(pos_ev); - } + while (k_msgq_get(&zmk_kscan_msgq, &ev, K_NO_WAIT) == 0) { + bool pressed = (ev.state == ZMK_KSCAN_EVENT_STATE_PRESSED); + u32_t position = zmk_matrix_transform_row_column_to_position(ev.row, ev.column); + struct position_state_changed *pos_ev; + LOG_DBG("Row: %d, col: %d, position: %d, pressed: %s\n", ev.row, ev.column, position, + (pressed ? "true" : "false")); + pos_ev = new_position_state_changed(); + pos_ev->state = pressed; + pos_ev->position = position; + ZMK_EVENT_RAISE(pos_ev); + } } -int zmk_kscan_init(char *name) -{ - struct device *dev = device_get_binding(name); - if (dev == NULL) - { - LOG_ERR("Failed to get the KSCAN device"); - return -EINVAL; - } +int zmk_kscan_init(char *name) { + struct device *dev = device_get_binding(name); + if (dev == NULL) { + LOG_ERR("Failed to get the KSCAN device"); + return -EINVAL; + } - k_work_init(&msg_processor.work, zmk_kscan_process_msgq); + k_work_init(&msg_processor.work, zmk_kscan_process_msgq); - kscan_config(dev, zmk_kscan_callback); - kscan_enable_callback(dev); + kscan_config(dev, zmk_kscan_callback); + kscan_enable_callback(dev); - return 0; + return 0; } diff --git a/app/src/kscan_composite.c b/app/src/kscan_composite.c index 15527ebe..02491407 100644 --- a/app/src/kscan_composite.c +++ b/app/src/kscan_composite.c @@ -15,37 +15,31 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #define MATRIX_ROWS DT_PROP(MATRIX_NODE_ID, rows) #define MATRIX_COLS DT_PROP(MATRIX_NODE_ID, columns) -struct kscan_composite_child_config -{ +struct kscan_composite_child_config { char *label; u8_t row_offset; u8_t column_offset; }; -#define CHILD_CONFIG(inst) \ - { \ - .label = DT_LABEL(DT_PHANDLE(inst, kscan)), \ - .row_offset = DT_PROP(inst, row_offset), \ - .column_offset = DT_PROP(inst, column_offset)}, +#define CHILD_CONFIG(inst) \ + {.label = DT_LABEL(DT_PHANDLE(inst, kscan)), \ + .row_offset = DT_PROP(inst, row_offset), \ + .column_offset = DT_PROP(inst, column_offset)}, const struct kscan_composite_child_config kscan_composite_children[] = { DT_FOREACH_CHILD(MATRIX_NODE_ID, CHILD_CONFIG)}; -struct kscan_composite_config -{ -}; +struct kscan_composite_config {}; -struct kscan_composite_data -{ +struct kscan_composite_data { kscan_callback_t callback; struct device *dev; }; -static int kscan_composite_enable_callback(struct device *dev) -{ - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); i++) - { +static int kscan_composite_enable_callback(struct device *dev) { + for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); + i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; kscan_enable_callback(device_get_binding(cfg->label)); @@ -53,10 +47,9 @@ static int kscan_composite_enable_callback(struct device *dev) return 0; } -static int kscan_composite_disable_callback(struct device *dev) -{ - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); i++) - { +static int kscan_composite_disable_callback(struct device *dev) { + for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); + i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; kscan_disable_callback(device_get_binding(cfg->label)); @@ -64,18 +57,17 @@ static int kscan_composite_disable_callback(struct device *dev) return 0; } -static void kscan_composite_child_callback(struct device *child_dev, u32_t row, u32_t column, bool pressed) -{ +static void kscan_composite_child_callback(struct device *child_dev, u32_t row, u32_t column, + bool pressed) { // TODO: Ideally we can get this passed into our callback! struct device *dev = device_get_binding(DT_INST_LABEL(0)); struct kscan_composite_data *data = dev->driver_data; - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); i++) - { + for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); + i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; - if (device_get_binding(cfg->label) != child_dev) - { + if (device_get_binding(cfg->label) != child_dev) { continue; } @@ -83,17 +75,15 @@ static void kscan_composite_child_callback(struct device *child_dev, u32_t row, } } -static int kscan_composite_configure(struct device *dev, kscan_callback_t callback) -{ +static int kscan_composite_configure(struct device *dev, kscan_callback_t callback) { struct kscan_composite_data *data = dev->driver_data; - if (!callback) - { + if (!callback) { return -EINVAL; } - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); i++) - { + for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); + i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; kscan_config(device_get_binding(cfg->label), &kscan_composite_child_callback); @@ -104,8 +94,7 @@ static int kscan_composite_configure(struct device *dev, kscan_callback_t callba return 0; } -static int kscan_composite_init(struct device *dev) -{ +static int kscan_composite_init(struct device *dev) { struct kscan_composite_data *data = dev->driver_data; data->dev = dev; @@ -123,8 +112,6 @@ static const struct kscan_composite_config kscan_composite_config = {}; static struct kscan_composite_data kscan_composite_data; -DEVICE_AND_API_INIT(kscan_composite, DT_INST_LABEL(0), kscan_composite_init, - &kscan_composite_data, - &kscan_composite_config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, +DEVICE_AND_API_INIT(kscan_composite, DT_INST_LABEL(0), kscan_composite_init, &kscan_composite_data, + &kscan_composite_config, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &mock_driver_api); diff --git a/app/src/kscan_mock.c b/app/src/kscan_mock.c index 741f6c17..e9c15a05 100644 --- a/app/src/kscan_mock.c +++ b/app/src/kscan_mock.c @@ -15,8 +15,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include -struct kscan_mock_data -{ +struct kscan_mock_data { kscan_callback_t callback; u8_t event_index; @@ -24,20 +23,17 @@ struct kscan_mock_data struct device *dev; }; -static int kscan_mock_disable_callback(struct device *dev) -{ +static int kscan_mock_disable_callback(struct device *dev) { struct kscan_mock_data *data = dev->driver_data; k_delayed_work_cancel(&data->work); return 0; } -static int kscan_mock_configure(struct device *dev, kscan_callback_t callback) -{ +static int kscan_mock_configure(struct device *dev, kscan_callback_t callback) { struct kscan_mock_data *data = dev->driver_data; - if (!callback) - { + if (!callback) { return -EINVAL; } @@ -47,64 +43,53 @@ static int kscan_mock_configure(struct device *dev, kscan_callback_t callback) return 0; } -#define MOCK_INST_INIT(n) \ - struct kscan_mock_config_##n \ - { \ - u32_t events[DT_INST_PROP_LEN(n, events)]; \ - bool exit_after; \ - }; \ - static void kscan_mock_schedule_next_event_##n(struct device *dev) \ - { \ - struct kscan_mock_data *data = dev->driver_data; \ - const struct kscan_mock_config_##n *cfg = dev->config_info; \ - if (data->event_index < DT_INST_PROP_LEN(n, events)) \ - { \ - u32_t ev = cfg->events[data->event_index]; \ - LOG_DBG("delaying next keypress: %d", ZMK_MOCK_MSEC(ev)); \ - k_delayed_work_submit(&data->work, K_MSEC(ZMK_MOCK_MSEC(ev))); \ - } else if (cfg->exit_after) { \ - LOG_DBG("Exiting"); \ - exit(0); \ - } \ - } \ - static void kscan_mock_work_handler_##n(struct k_work *work) \ - { \ - struct kscan_mock_data *data = \ - CONTAINER_OF(work, struct kscan_mock_data, work); \ - const struct kscan_mock_config_##n *cfg = data->dev->config_info; \ - u32_t ev = cfg->events[data->event_index]; \ - LOG_DBG("ev %u row %d column %d state %d\n", ev, \ - ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev)); \ - data->callback(data->dev, \ - ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev)); \ - kscan_mock_schedule_next_event_##n(data->dev); \ - data->event_index++; \ - } \ - static int kscan_mock_init_##n(struct device *dev) \ - { \ - struct kscan_mock_data *data = dev->driver_data; \ - data->dev = dev; \ - k_delayed_work_init(&data->work, kscan_mock_work_handler_##n); \ - return 0; \ - } \ - static int kscan_mock_enable_callback_##n(struct device *dev) \ - { \ - kscan_mock_schedule_next_event_##n(dev); \ - return 0; \ - } \ - static const struct kscan_driver_api mock_driver_api_##n = { \ - .config = kscan_mock_configure, \ - .enable_callback = kscan_mock_enable_callback_##n, \ - .disable_callback = kscan_mock_disable_callback, \ - }; \ - static struct kscan_mock_data kscan_mock_data_##n; \ - static const struct kscan_mock_config_##n kscan_mock_config_##n = { \ - .events = DT_INST_PROP(n, events), \ - .exit_after = DT_INST_PROP(n, exit_after) }; \ - DEVICE_AND_API_INIT(kscan_mock_##n, DT_INST_LABEL(n), kscan_mock_init_##n, \ - &kscan_mock_data_##n, \ - &kscan_mock_config_##n, \ - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ - &mock_driver_api_##n); +#define MOCK_INST_INIT(n) \ + struct kscan_mock_config_##n { \ + u32_t events[DT_INST_PROP_LEN(n, events)]; \ + bool exit_after; \ + }; \ + static void kscan_mock_schedule_next_event_##n(struct device *dev) { \ + struct kscan_mock_data *data = dev->driver_data; \ + const struct kscan_mock_config_##n *cfg = dev->config_info; \ + if (data->event_index < DT_INST_PROP_LEN(n, events)) { \ + u32_t ev = cfg->events[data->event_index]; \ + LOG_DBG("delaying next keypress: %d", ZMK_MOCK_MSEC(ev)); \ + k_delayed_work_submit(&data->work, K_MSEC(ZMK_MOCK_MSEC(ev))); \ + } else if (cfg->exit_after) { \ + LOG_DBG("Exiting"); \ + exit(0); \ + } \ + } \ + static void kscan_mock_work_handler_##n(struct k_work *work) { \ + struct kscan_mock_data *data = CONTAINER_OF(work, struct kscan_mock_data, work); \ + const struct kscan_mock_config_##n *cfg = data->dev->config_info; \ + u32_t ev = cfg->events[data->event_index]; \ + LOG_DBG("ev %u row %d column %d state %d\n", ev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), \ + ZMK_MOCK_IS_PRESS(ev)); \ + data->callback(data->dev, ZMK_MOCK_ROW(ev), ZMK_MOCK_COL(ev), ZMK_MOCK_IS_PRESS(ev)); \ + kscan_mock_schedule_next_event_##n(data->dev); \ + data->event_index++; \ + } \ + static int kscan_mock_init_##n(struct device *dev) { \ + struct kscan_mock_data *data = dev->driver_data; \ + data->dev = dev; \ + k_delayed_work_init(&data->work, kscan_mock_work_handler_##n); \ + return 0; \ + } \ + static int kscan_mock_enable_callback_##n(struct device *dev) { \ + kscan_mock_schedule_next_event_##n(dev); \ + return 0; \ + } \ + static const struct kscan_driver_api mock_driver_api_##n = { \ + .config = kscan_mock_configure, \ + .enable_callback = kscan_mock_enable_callback_##n, \ + .disable_callback = kscan_mock_disable_callback, \ + }; \ + static struct kscan_mock_data kscan_mock_data_##n; \ + static const struct kscan_mock_config_##n kscan_mock_config_##n = { \ + .events = DT_INST_PROP(n, events), .exit_after = DT_INST_PROP(n, exit_after)}; \ + DEVICE_AND_API_INIT(kscan_mock_##n, DT_INST_LABEL(n), kscan_mock_init_##n, \ + &kscan_mock_data_##n, &kscan_mock_config_##n, APPLICATION, \ + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &mock_driver_api_##n); DT_INST_FOREACH_STATUS_OKAY(MOCK_INST_INIT) diff --git a/app/src/main.c b/app/src/main.c index 5da272e5..dca923e9 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -18,20 +18,18 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); #define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) -void main(void) -{ - LOG_INF("Welcome to ZMK!\n"); +void main(void) { + LOG_INF("Welcome to ZMK!\n"); - if (zmk_kscan_init(ZMK_KSCAN_DEV) != 0) - { - return; - } + if (zmk_kscan_init(ZMK_KSCAN_DEV) != 0) { + return; + } #ifdef CONFIG_ZMK_DISPLAY - zmk_display_init(); + zmk_display_init(); - while (1) { - zmk_display_task_handler(); - } + while (1) { + zmk_display_task_handler(); + } #endif /* CONFIG_ZMK_DISPLAY */ } diff --git a/app/src/matrix_transform.c b/app/src/matrix_transform.c index 8a037b34..4e68a56f 100644 --- a/app/src/matrix_transform.c +++ b/app/src/matrix_transform.c @@ -11,16 +11,15 @@ #ifdef ZMK_KEYMAP_TRANSFORM_NODE -#define _TRANSFORM_ENTRY(i, _) \ - [(KT_ROW(DT_PROP_BY_IDX(ZMK_KEYMAP_TRANSFORM_NODE, map, i)) * ZMK_MATRIX_COLS) + KT_COL(DT_PROP_BY_IDX(ZMK_KEYMAP_TRANSFORM_NODE, map, i))] = i, +#define _TRANSFORM_ENTRY(i, _) \ + [(KT_ROW(DT_PROP_BY_IDX(ZMK_KEYMAP_TRANSFORM_NODE, map, i)) * ZMK_MATRIX_COLS) + \ + KT_COL(DT_PROP_BY_IDX(ZMK_KEYMAP_TRANSFORM_NODE, map, i))] = i, -static u32_t transform[] = - { UTIL_LISTIFY(ZMK_KEYMAP_LEN, _TRANSFORM_ENTRY, 0) }; +static u32_t transform[] = {UTIL_LISTIFY(ZMK_KEYMAP_LEN, _TRANSFORM_ENTRY, 0)}; #endif -u32_t zmk_matrix_transform_row_column_to_position(u32_t row, u32_t column) -{ +u32_t zmk_matrix_transform_row_column_to_position(u32_t row, u32_t column) { u32_t matrix_index; #if DT_NODE_HAS_PROP(ZMK_KEYMAP_TRANSFORM_NODE, col_offset) diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index 97c2ac0a..13912e30 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -18,8 +18,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -#define STRIP_LABEL DT_LABEL(DT_CHOSEN(zmk_underglow)) -#define STRIP_NUM_PIXELS DT_PROP(DT_CHOSEN(zmk_underglow), chain_length) +#define STRIP_LABEL DT_LABEL(DT_CHOSEN(zmk_underglow)) +#define STRIP_NUM_PIXELS DT_PROP(DT_CHOSEN(zmk_underglow), chain_length) enum rgb_underglow_effect { UNDERGLOW_EFFECT_SOLID, @@ -30,19 +30,19 @@ enum rgb_underglow_effect { }; struct led_hsb { - u16_t h; - u8_t s; - u8_t b; + u16_t h; + u8_t s; + u8_t b; }; struct rgb_underglow_state { u16_t hue; - u8_t saturation; - u8_t brightness; - u8_t animation_speed; - u8_t current_effect; + u8_t saturation; + u8_t brightness; + u8_t animation_speed; + u8_t current_effect; u16_t animation_step; - bool on; + bool on; }; struct rgb_underglow_state state; @@ -51,8 +51,7 @@ struct device *led_strip; struct led_rgb pixels[STRIP_NUM_PIXELS]; -static struct led_rgb hsb_to_rgb(struct led_hsb hsb) -{ +static struct led_rgb hsb_to_rgb(struct led_hsb hsb) { double r, g, b; u8_t i = hsb.h / 60; @@ -63,64 +62,81 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) double q = v * (1 - f * s); double t = v * (1 - (1 - f) * s); - switch (i % 6) - { - case 0: r = v; g = t; b = p; break; - case 1: r = q; g = v; b = p; break; - case 2: r = p; g = v; b = t; break; - case 3: r = p; g = q; b = v; break; - case 4: r = t; g = p; b = v; break; - case 5: r = v; g = p; b = q; break; + switch (i % 6) { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + case 5: + r = v; + g = p; + b = q; + break; } - struct led_rgb rgb = { r: r*255, g: g*255, b: b*255 }; + struct led_rgb rgb = {r : r * 255, g : g * 255, b : b * 255}; return rgb; } -static void zmk_rgb_underglow_effect_solid() -{ - for (int i=0; i 2400) { state.animation_step = 0; } } -static void zmk_rgb_underglow_effect_spectrum() -{ - for (int i=0; i= UNDERGLOW_EFFECT_NUMBER) { state.current_effect = 0; } - + state.animation_step = 0; return 0; } -int zmk_rgb_underglow_toggle() -{ - if (!led_strip) return -ENODEV; +int zmk_rgb_underglow_toggle() { + if (!led_strip) + return -ENODEV; state.on = !state.on; @@ -232,9 +242,8 @@ int zmk_rgb_underglow_toggle() k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50)); } else { - for (int i=0; i 350) { @@ -263,9 +272,9 @@ int zmk_rgb_underglow_change_hue(int direction) return 0; } -int zmk_rgb_underglow_change_sat(int direction) -{ - if (!led_strip) return -ENODEV; +int zmk_rgb_underglow_change_sat(int direction) { + if (!led_strip) + return -ENODEV; if (state.saturation == 0 && direction < 0) { return 0; @@ -280,9 +289,9 @@ int zmk_rgb_underglow_change_sat(int direction) return 0; } -int zmk_rgb_underglow_change_brt(int direction) -{ - if (!led_strip) return -ENODEV; +int zmk_rgb_underglow_change_brt(int direction) { + if (!led_strip) + return -ENODEV; if (state.brightness == 0 && direction < 0) { return 0; @@ -297,9 +306,9 @@ int zmk_rgb_underglow_change_brt(int direction) return 0; } -int zmk_rgb_underglow_change_spd(int direction) -{ - if (!led_strip) return -ENODEV; +int zmk_rgb_underglow_change_spd(int direction) { + if (!led_strip) + return -ENODEV; if (state.animation_speed == 1 && direction < 0) { return 0; @@ -314,6 +323,4 @@ int zmk_rgb_underglow_change_spd(int direction) return 0; } -SYS_INIT(zmk_rgb_underglow_init, - APPLICATION, - CONFIG_APPLICATION_INIT_PRIORITY); +SYS_INIT(zmk_rgb_underglow_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); diff --git a/app/src/sensors.c b/app/src/sensors.c index 7a7c0c5b..15f374b3 100644 --- a/app/src/sensors.c +++ b/app/src/sensors.c @@ -24,19 +24,19 @@ struct sensors_data_item { struct sensor_trigger trigger; }; -#define _SENSOR_ITEM(node) {.dev = NULL, .trigger = { .type = SENSOR_TRIG_DELTA, .chan = SENSOR_CHAN_ROTATION } }, -#define SENSOR_ITEM(idx, _) COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx),okay), (_SENSOR_ITEM(ZMK_KEYMAP_SENSORS_BY_IDX(idx))),()) +#define _SENSOR_ITEM(node) \ + {.dev = NULL, .trigger = {.type = SENSOR_TRIG_DELTA, .chan = SENSOR_CHAN_ROTATION}}, +#define SENSOR_ITEM(idx, _) \ + COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx), okay), \ + (_SENSOR_ITEM(ZMK_KEYMAP_SENSORS_BY_IDX(idx))), ()) -static struct sensors_data_item sensors[] = { - UTIL_LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, 0) -}; +static struct sensors_data_item sensors[] = {UTIL_LISTIFY(ZMK_KEYMAP_SENSORS_LEN, SENSOR_ITEM, 0)}; -static void zmk_sensors_trigger_handler(struct device *dev, struct sensor_trigger *trigger) -{ +static void zmk_sensors_trigger_handler(struct device *dev, struct sensor_trigger *trigger) { int err; - struct sensors_data_item * item = CONTAINER_OF(trigger, struct sensors_data_item, trigger); + struct sensors_data_item *item = CONTAINER_OF(trigger, struct sensors_data_item, trigger); struct sensor_event *event; - + LOG_DBG("sensor %d", item->sensor_number); err = sensor_sample_fetch(dev); @@ -52,8 +52,7 @@ static void zmk_sensors_trigger_handler(struct device *dev, struct sensor_trigge ZMK_EVENT_RAISE(event); } -static void zmk_sensors_init_item(const char *node, u8_t i, u8_t abs_i) -{ +static void zmk_sensors_init_item(const char *node, u8_t i, u8_t abs_i) { LOG_DBG("Init %s at index %d with sensor_number %d", node, i, abs_i); sensors[i].dev = device_get_binding(node); @@ -68,10 +67,11 @@ static void zmk_sensors_init_item(const char *node, u8_t i, u8_t abs_i) } #define _SENSOR_INIT(node) zmk_sensors_init_item(DT_LABEL(node), local_index++, absolute_index++); -#define SENSOR_INIT(idx, _i) COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx),okay), (_SENSOR_INIT(ZMK_KEYMAP_SENSORS_BY_IDX(idx))),(absolute_index++;)) +#define SENSOR_INIT(idx, _i) \ + COND_CODE_1(DT_NODE_HAS_STATUS(ZMK_KEYMAP_SENSORS_BY_IDX(idx), okay), \ + (_SENSOR_INIT(ZMK_KEYMAP_SENSORS_BY_IDX(idx))), (absolute_index++;)) -static int zmk_sensors_init(struct device *_arg) -{ +static int zmk_sensors_init(struct device *_arg) { int local_index = 0; int absolute_index = 0; @@ -79,8 +79,6 @@ static int zmk_sensors_init(struct device *_arg) return 0; } -SYS_INIT(zmk_sensors_init, - APPLICATION, - CONFIG_APPLICATION_INIT_PRIORITY); +SYS_INIT(zmk_sensors_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); #endif /* ZMK_KEYMAP_HAS_SENSORS */ \ No newline at end of file diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index 6d8b4357..cb1b68be 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -33,303 +33,290 @@ static struct bt_uuid_128 uuid = BT_UUID_INIT_128(ZMK_SPLIT_BT_SERVICE_UUID); static struct bt_gatt_discover_params discover_params; static struct bt_gatt_subscribe_params subscribe_params; -static u8_t split_central_notify_func(struct bt_conn *conn, - struct bt_gatt_subscribe_params *params, - const void *data, u16_t length) -{ - static u8_t position_state[POSITION_STATE_DATA_LEN]; +static u8_t split_central_notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, + const void *data, u16_t length) { + static u8_t position_state[POSITION_STATE_DATA_LEN]; - u8_t changed_positions[POSITION_STATE_DATA_LEN]; + u8_t changed_positions[POSITION_STATE_DATA_LEN]; - if (!data) { - LOG_DBG("[UNSUBSCRIBED]"); - params->value_handle = 0U; - return BT_GATT_ITER_STOP; - } + if (!data) { + LOG_DBG("[UNSUBSCRIBED]"); + params->value_handle = 0U; + return BT_GATT_ITER_STOP; + } - LOG_DBG("[NOTIFICATION] data %p length %u", data, length); + LOG_DBG("[NOTIFICATION] data %p length %u", data, length); - for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { - changed_positions[i] = ((u8_t *)data)[i] ^ position_state[i]; - position_state[i] = ((u8_t *)data)[i]; - } + for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { + changed_positions[i] = ((u8_t *)data)[i] ^ position_state[i]; + position_state[i] = ((u8_t *)data)[i]; + } - for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { - for (int j = 0; j < 8; j++) { - if (changed_positions[i] & BIT(j)) { - u32_t position = (i * 8) + j; - bool pressed = position_state[i] & BIT(j); - struct position_state_changed *pos_ev = new_position_state_changed(); - pos_ev->position = position; - pos_ev->state = pressed; + for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) { + for (int j = 0; j < 8; j++) { + if (changed_positions[i] & BIT(j)) { + u32_t position = (i * 8) + j; + bool pressed = position_state[i] & BIT(j); + struct position_state_changed *pos_ev = new_position_state_changed(); + pos_ev->position = position; + pos_ev->state = pressed; - LOG_DBG("Trigger key position state change for %d", position); - ZMK_EVENT_RAISE(pos_ev); - } - } - } + LOG_DBG("Trigger key position state change for %d", position); + ZMK_EVENT_RAISE(pos_ev); + } + } + } - - return BT_GATT_ITER_CONTINUE; + return BT_GATT_ITER_CONTINUE; } -static int split_central_subscribe(struct bt_conn *conn) -{ - int err = bt_gatt_subscribe(conn, &subscribe_params); - switch (err) { - case -EALREADY: - LOG_DBG("[ALREADY SUBSCRIBED]"); - break; - // break; - // bt_gatt_unsubscribe(conn, &subscribe_params); - // return split_central_subscribe(conn); - case 0: - LOG_DBG("[SUBSCRIBED]"); - break; - default: - LOG_ERR("Subscribe failed (err %d)", err); - break; - } +static int split_central_subscribe(struct bt_conn *conn) { + int err = bt_gatt_subscribe(conn, &subscribe_params); + switch (err) { + case -EALREADY: + LOG_DBG("[ALREADY SUBSCRIBED]"); + break; + // break; + // bt_gatt_unsubscribe(conn, &subscribe_params); + // return split_central_subscribe(conn); + case 0: + LOG_DBG("[SUBSCRIBED]"); + break; + default: + LOG_ERR("Subscribe failed (err %d)", err); + break; + } - return 0; + return 0; } -static u8_t split_central_discovery_func(struct bt_conn *conn, - const struct bt_gatt_attr *attr, - struct bt_gatt_discover_params *params) -{ - int err; +static u8_t split_central_discovery_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + int err; - if (!attr) { - LOG_DBG("Discover complete"); - (void)memset(params, 0, sizeof(*params)); - return BT_GATT_ITER_STOP; - } + if (!attr) { + LOG_DBG("Discover complete"); + (void)memset(params, 0, sizeof(*params)); + return BT_GATT_ITER_STOP; + } - LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); + LOG_DBG("[ATTRIBUTE] handle %u", attr->handle); - if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { - memcpy(&uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID), sizeof(uuid)); - discover_params.uuid = &uuid.uuid; - discover_params.start_handle = attr->handle + 1; - discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { + memcpy(&uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID), sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.start_handle = attr->handle + 1; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; - err = bt_gatt_discover(conn, &discover_params); - if (err) { - LOG_ERR("Discover failed (err %d)", err); - } - } else if (!bt_uuid_cmp(discover_params.uuid, - BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID))) { - memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); - discover_params.uuid = &uuid.uuid; - discover_params.start_handle = attr->handle + 2; - discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; - subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } + } else if (!bt_uuid_cmp(discover_params.uuid, + BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID))) { + memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid)); + discover_params.uuid = &uuid.uuid; + discover_params.start_handle = attr->handle + 2; + discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR; + subscribe_params.value_handle = bt_gatt_attr_value_handle(attr); - err = bt_gatt_discover(conn, &discover_params); - if (err) { - LOG_ERR("Discover failed (err %d)", err); - } - } else { - subscribe_params.notify = split_central_notify_func; - subscribe_params.value = BT_GATT_CCC_NOTIFY; - subscribe_params.ccc_handle = attr->handle; + err = bt_gatt_discover(conn, &discover_params); + if (err) { + LOG_ERR("Discover failed (err %d)", err); + } + } else { + subscribe_params.notify = split_central_notify_func; + subscribe_params.value = BT_GATT_CCC_NOTIFY; + subscribe_params.ccc_handle = attr->handle; - split_central_subscribe(conn); + split_central_subscribe(conn); - return BT_GATT_ITER_STOP; - } + return BT_GATT_ITER_STOP; + } - return BT_GATT_ITER_STOP; + return BT_GATT_ITER_STOP; } static void split_central_process_connection(struct bt_conn *conn) { - int err; + int err; - LOG_DBG("Current security for connection: %d", bt_conn_get_security(conn)); - - err = bt_conn_set_security(conn, BT_SECURITY_L2); - if (err) { - LOG_ERR("Failed to set security (reason %d)", err); - return; - } + LOG_DBG("Current security for connection: %d", bt_conn_get_security(conn)); - if (conn == default_conn && !subscribe_params.value) { - discover_params.uuid = &uuid.uuid; - discover_params.func = split_central_discovery_func; - discover_params.start_handle = 0x0001; - discover_params.end_handle = 0xffff; - discover_params.type = BT_GATT_DISCOVER_PRIMARY; + err = bt_conn_set_security(conn, BT_SECURITY_L2); + if (err) { + LOG_ERR("Failed to set security (reason %d)", err); + return; + } - err = bt_gatt_discover(default_conn, &discover_params); - if (err) { - LOG_ERR("Discover failed(err %d)", err); - return; - } - } + if (conn == default_conn && !subscribe_params.value) { + discover_params.uuid = &uuid.uuid; + discover_params.func = split_central_discovery_func; + discover_params.start_handle = 0x0001; + discover_params.end_handle = 0xffff; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; - struct bt_conn_info info; + err = bt_gatt_discover(default_conn, &discover_params); + if (err) { + LOG_ERR("Discover failed(err %d)", err); + return; + } + } - bt_conn_get_info(conn, &info); + struct bt_conn_info info; - LOG_DBG("New connection params: Interval: %d, Latency: %d, PHY: %d", info.le.interval, info.le.latency, info.le.phy->rx_phy); + bt_conn_get_info(conn, &info); + + LOG_DBG("New connection params: Interval: %d, Latency: %d, PHY: %d", info.le.interval, + info.le.latency, info.le.phy->rx_phy); } -static bool split_central_eir_found(struct bt_data *data, void *user_data) -{ - bt_addr_le_t *addr = user_data; - int i; +static bool split_central_eir_found(struct bt_data *data, void *user_data) { + bt_addr_le_t *addr = user_data; + int i; - LOG_DBG("[AD]: %u data_len %u", data->type, data->data_len); + LOG_DBG("[AD]: %u data_len %u", data->type, data->data_len); - switch (data->type) { - case BT_DATA_UUID128_SOME: - case BT_DATA_UUID128_ALL: - if (data->data_len % 16 != 0U) { - LOG_ERR("AD malformed"); - return true; - } + switch (data->type) { + case BT_DATA_UUID128_SOME: + case BT_DATA_UUID128_ALL: + if (data->data_len % 16 != 0U) { + LOG_ERR("AD malformed"); + return true; + } - for (i = 0; i < data->data_len; i += 16) { - struct bt_le_conn_param *param; - struct bt_uuid uuid; - int err; + for (i = 0; i < data->data_len; i += 16) { + struct bt_le_conn_param *param; + struct bt_uuid uuid; + int err; if (!bt_uuid_create(&uuid, &data->data[i], 16)) { LOG_ERR("Unable to load UUID"); continue; } - if (!bt_uuid_cmp(&uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { - char uuid_str[BT_UUID_STR_LEN]; - char service_uuid_str[BT_UUID_STR_LEN]; + if (!bt_uuid_cmp(&uuid, BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID))) { + char uuid_str[BT_UUID_STR_LEN]; + char service_uuid_str[BT_UUID_STR_LEN]; - bt_uuid_to_str(&uuid, uuid_str, sizeof(uuid_str)); - bt_uuid_to_str(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID), service_uuid_str, sizeof(service_uuid_str)); - LOG_DBG("UUID %s does not match split UUID: %s", log_strdup(uuid_str), log_strdup(service_uuid_str)); - continue; - } + bt_uuid_to_str(&uuid, uuid_str, sizeof(uuid_str)); + bt_uuid_to_str(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID), service_uuid_str, + sizeof(service_uuid_str)); + LOG_DBG("UUID %s does not match split UUID: %s", log_strdup(uuid_str), + log_strdup(service_uuid_str)); + continue; + } - LOG_DBG("Found the split service"); + LOG_DBG("Found the split service"); - zmk_ble_set_peripheral_addr(addr); + zmk_ble_set_peripheral_addr(addr); - err = bt_le_scan_stop(); - if (err) { - LOG_ERR("Stop LE scan failed (err %d)", err); - continue; - } + err = bt_le_scan_stop(); + if (err) { + LOG_ERR("Stop LE scan failed (err %d)", err); + continue; + } - default_conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); - if (default_conn) { - LOG_DBG("Found existing connection"); - split_central_process_connection(default_conn); - } else { - param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400); + default_conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); + if (default_conn) { + LOG_DBG("Found existing connection"); + split_central_process_connection(default_conn); + } else { + param = BT_LE_CONN_PARAM(0x0006, 0x0006, 30, 400); - err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, - param, &default_conn); - if (err) { - LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, BT_HCI_OP_LE_CREATE_CONN); - start_scan(); - } + err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn); + if (err) { + LOG_ERR("Create conn failed (err %d) (create conn? 0x%04x)", err, + BT_HCI_OP_LE_CREATE_CONN); + start_scan(); + } - err = bt_conn_le_phy_update(default_conn, BT_CONN_LE_PHY_PARAM_2M); - if (err) { - LOG_ERR("Update phy conn failed (err %d)", err); - start_scan(); - } - } + err = bt_conn_le_phy_update(default_conn, BT_CONN_LE_PHY_PARAM_2M); + if (err) { + LOG_ERR("Update phy conn failed (err %d)", err); + start_scan(); + } + } - return false; - } - } + return false; + } + } - return true; + return true; } static void split_central_device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, - struct net_buf_simple *ad) -{ - char dev[BT_ADDR_LE_STR_LEN]; + struct net_buf_simple *ad) { + char dev[BT_ADDR_LE_STR_LEN]; - bt_addr_le_to_str(addr, dev, sizeof(dev)); - LOG_DBG("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i", - log_strdup(dev), type, ad->len, rssi); + bt_addr_le_to_str(addr, dev, sizeof(dev)); + LOG_DBG("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i", log_strdup(dev), type, ad->len, + rssi); - /* We're only interested in connectable events */ - if (type == BT_GAP_ADV_TYPE_ADV_IND || - type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { - bt_data_parse(ad, split_central_eir_found, (void *)addr); - } + /* We're only interested in connectable events */ + if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + bt_data_parse(ad, split_central_eir_found, (void *)addr); + } } -static int start_scan(void) -{ - int err; +static int start_scan(void) { + int err; - err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, split_central_device_found); - if (err) { - LOG_ERR("Scanning failed to start (err %d)", err); - return err; - } + err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, split_central_device_found); + if (err) { + LOG_ERR("Scanning failed to start (err %d)", err); + return err; + } - LOG_DBG("Scanning successfully started"); + LOG_DBG("Scanning successfully started"); return 0; } -static void split_central_connected(struct bt_conn *conn, u8_t conn_err) -{ - char addr[BT_ADDR_LE_STR_LEN]; +static void split_central_connected(struct bt_conn *conn, u8_t conn_err) { + char addr[BT_ADDR_LE_STR_LEN]; - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + if (conn_err) { + LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err); - if (conn_err) { - LOG_ERR("Failed to connect to %s (%u)", log_strdup(addr), conn_err); + bt_conn_unref(default_conn); + default_conn = NULL; - bt_conn_unref(default_conn); - default_conn = NULL; + start_scan(); + return; + } - start_scan(); - return; - } + LOG_DBG("Connected: %s", log_strdup(addr)); - LOG_DBG("Connected: %s", log_strdup(addr)); - - split_central_process_connection(conn); + split_central_process_connection(conn); } -static void split_central_disconnected(struct bt_conn *conn, u8_t reason) -{ - char addr[BT_ADDR_LE_STR_LEN]; +static void split_central_disconnected(struct bt_conn *conn, u8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; - bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); - LOG_DBG("Disconnected: %s (reason %d)", log_strdup(addr), reason); + LOG_DBG("Disconnected: %s (reason %d)", log_strdup(addr), reason); - if (default_conn != conn) { - return; - } + if (default_conn != conn) { + return; + } - bt_conn_unref(default_conn); - default_conn = NULL; + bt_conn_unref(default_conn); + default_conn = NULL; - start_scan(); + start_scan(); } static struct bt_conn_cb conn_callbacks = { - .connected = split_central_connected, - .disconnected = split_central_disconnected, + .connected = split_central_connected, + .disconnected = split_central_disconnected, }; -int zmk_split_bt_central_init(struct device *_arg) -{ - bt_conn_cb_register(&conn_callbacks); +int zmk_split_bt_central_init(struct device *_arg) { + bt_conn_cb_register(&conn_callbacks); - return start_scan(); + return start_scan(); } -SYS_INIT(zmk_split_bt_central_init, - APPLICATION, - CONFIG_ZMK_BLE_INIT_PRIORITY); \ No newline at end of file +SYS_INIT(zmk_split_bt_central_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY); \ No newline at end of file diff --git a/app/src/split/bluetooth/service.c b/app/src/split/bluetooth/service.c index c2f65d28..86af685f 100644 --- a/app/src/split/bluetooth/service.c +++ b/app/src/split/bluetooth/service.c @@ -21,41 +21,36 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static u8_t num_of_positions = ZMK_KEYMAP_LEN; static u8_t position_state[16]; -static ssize_t split_svc_pos_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, void *buf, u16_t len, u16_t offset) -{ - return bt_gatt_attr_read(conn, attrs, buf, len, offset, &position_state, sizeof(position_state)); +static ssize_t split_svc_pos_state(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + void *buf, u16_t len, u16_t offset) { + return bt_gatt_attr_read(conn, attrs, buf, len, offset, &position_state, + sizeof(position_state)); } -static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_gatt_attr *attrs, void *buf, u16_t len, u16_t offset) -{ +static ssize_t split_svc_num_of_positions(struct bt_conn *conn, const struct bt_gatt_attr *attrs, + void *buf, u16_t len, u16_t offset) { return bt_gatt_attr_read(conn, attrs, buf, len, offset, attrs->user_data, sizeof(u8_t)); } -static void split_svc_pos_state_ccc(const struct bt_gatt_attr *attr, u16_t value) -{ +static void split_svc_pos_state_ccc(const struct bt_gatt_attr *attr, u16_t value) { LOG_DBG("value %d", value); } +BT_GATT_SERVICE_DEFINE( + split_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)), + BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID), + BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ_ENCRYPT, + split_svc_pos_state, NULL, &position_state), + BT_GATT_CCC(split_svc_pos_state_ccc, BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), + BT_GATT_DESCRIPTOR(BT_UUID_NUM_OF_DIGITALS, BT_GATT_PERM_READ, split_svc_num_of_positions, NULL, + &num_of_positions), ); -BT_GATT_SERVICE_DEFINE(split_svc, - BT_GATT_PRIMARY_SERVICE(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SERVICE_UUID)), - BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_CHAR_POSITION_STATE_UUID), BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, - BT_GATT_PERM_READ_ENCRYPT, - split_svc_pos_state, NULL, &position_state), - BT_GATT_CCC(split_svc_pos_state_ccc, - BT_GATT_PERM_READ_ENCRYPT | BT_GATT_PERM_WRITE_ENCRYPT), - BT_GATT_DESCRIPTOR(BT_UUID_NUM_OF_DIGITALS, BT_GATT_PERM_READ, - split_svc_num_of_positions, NULL, &num_of_positions), -); - -int zmk_split_bt_position_pressed(u8_t position) -{ +int zmk_split_bt_position_pressed(u8_t position) { WRITE_BIT(position_state[position / 8], position % 8, true); return bt_gatt_notify(NULL, &split_svc.attrs[1], &position_state, sizeof(position_state)); } -int zmk_split_bt_position_released(u8_t position) -{ +int zmk_split_bt_position_released(u8_t position) { WRITE_BIT(position_state[position / 8], position % 8, false); return bt_gatt_notify(NULL, &split_svc.attrs[1], &position_state, sizeof(position_state)); } \ No newline at end of file diff --git a/app/src/split_listener.c b/app/src/split_listener.c index 12638073..b2adfb2e 100644 --- a/app/src/split_listener.c +++ b/app/src/split_listener.c @@ -19,18 +19,17 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include -int split_listener(const struct zmk_event_header *eh) -{ - LOG_DBG(""); - if (is_position_state_changed(eh)) { - const struct position_state_changed *ev = cast_position_state_changed(eh); - if (ev->state) { - return zmk_split_bt_position_pressed(ev->position); - } else { - return zmk_split_bt_position_released(ev->position); +int split_listener(const struct zmk_event_header *eh) { + LOG_DBG(""); + if (is_position_state_changed(eh)) { + const struct position_state_changed *ev = cast_position_state_changed(eh); + if (ev->state) { + return zmk_split_bt_position_pressed(ev->position); + } else { + return zmk_split_bt_position_released(ev->position); + } } - } - return 0; + return 0; } ZMK_LISTENER(split_listener, split_listener); diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c index e2fe0f3d..530ffea8 100644 --- a/app/src/usb_hid.c +++ b/app/src/usb_hid.c @@ -22,71 +22,56 @@ static struct device *hid_dev; static K_SEM_DEFINE(hid_sem, 1, 1); -static void in_ready_cb(void) -{ - k_sem_give(&hid_sem); -} +static void in_ready_cb(void) { k_sem_give(&hid_sem); } -static const struct hid_ops ops = -{ - .int_in_ready = in_ready_cb, +static const struct hid_ops ops = { + .int_in_ready = in_ready_cb, }; -int zmk_usb_hid_send_report(const u8_t *report, size_t len) -{ - switch(usb_status) { - case USB_DC_SUSPEND: - return usb_wakeup_request(); - case USB_DC_ERROR: - case USB_DC_RESET: - case USB_DC_DISCONNECTED: - case USB_DC_UNKNOWN: - return -ENODEV; - default: - k_sem_take(&hid_sem, K_MSEC(30)); - int err = hid_int_ep_write(hid_dev, report, len, NULL); +int zmk_usb_hid_send_report(const u8_t *report, size_t len) { + switch (usb_status) { + case USB_DC_SUSPEND: + return usb_wakeup_request(); + case USB_DC_ERROR: + case USB_DC_RESET: + case USB_DC_DISCONNECTED: + case USB_DC_UNKNOWN: + return -ENODEV; + default: + k_sem_take(&hid_sem, K_MSEC(30)); + int err = hid_int_ep_write(hid_dev, report, len, NULL); - if (err) { - k_sem_give(&hid_sem); - } + if (err) { + k_sem_give(&hid_sem); + } - return err; - } + return err; + } } -void usb_hid_status_cb(enum usb_dc_status_code status, const u8_t *params) -{ - usb_status = status; -}; +void usb_hid_status_cb(enum usb_dc_status_code status, const u8_t *params) { usb_status = status; }; -static int zmk_usb_hid_init(struct device *_arg) -{ - int usb_enable_ret; +static int zmk_usb_hid_init(struct device *_arg) { + int usb_enable_ret; - hid_dev = device_get_binding("HID_0"); - if (hid_dev == NULL) - { - LOG_ERR("Unable to locate HID device"); - return -EINVAL; - } + hid_dev = device_get_binding("HID_0"); + if (hid_dev == NULL) { + LOG_ERR("Unable to locate HID device"); + return -EINVAL; + } - usb_hid_register_device(hid_dev, - zmk_hid_report_desc, sizeof(zmk_hid_report_desc), - &ops); + usb_hid_register_device(hid_dev, zmk_hid_report_desc, sizeof(zmk_hid_report_desc), &ops); - usb_hid_init(hid_dev); + usb_hid_init(hid_dev); - usb_enable_ret = usb_enable(usb_hid_status_cb); + usb_enable_ret = usb_enable(usb_hid_status_cb); - if (usb_enable_ret != 0) - { - LOG_ERR("Unable to enable USB"); - return -EINVAL; - } + if (usb_enable_ret != 0) { + LOG_ERR("Unable to enable USB"); + return -EINVAL; + } - return 0; + return 0; } -SYS_INIT(zmk_usb_hid_init, - APPLICATION, - CONFIG_ZMK_USB_INIT_PRIORITY); +SYS_INIT(zmk_usb_hid_init, APPLICATION, CONFIG_ZMK_USB_INIT_PRIORITY); From 7b12dc6caf7517aa95d66fadb529c260be752ff5 Mon Sep 17 00:00:00 2001 From: Nick Date: Sun, 13 Sep 2020 23:29:31 -0500 Subject: [PATCH 061/227] feature(board): add BT prof management to defaults --- app/boards/shields/corne/corne.keymap | 11 ++++++----- app/boards/shields/iris/iris.keymap | 13 +++++++------ app/boards/shields/lily58/lily58.keymap | 13 +++++++------ app/boards/shields/qaz/qaz.keymap | 3 ++- app/boards/shields/romac/romac.keymap | 17 +++++++++-------- app/boards/shields/sofle/sofle.keymap | 13 +++++++------ 6 files changed, 38 insertions(+), 32 deletions(-) diff --git a/app/boards/shields/corne/corne.keymap b/app/boards/shields/corne/corne.keymap index c0bbb4ab..5f0f15f0 100644 --- a/app/boards/shields/corne/corne.keymap +++ b/app/boards/shields/corne/corne.keymap @@ -1,5 +1,6 @@ #include #include +#include / { keymap { @@ -21,14 +22,14 @@ lower_layer { // ----------------------------------------------------------------------------------------- // | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | -// | CTRL | | | | | | | LFT | DWN | UP | RGT | | | +// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | // | SHFT | | | | | | | | | | | | | // | GUI | | SPC | | ENT | | ALT | bindings = < - &kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp BKSP - &kp LCTL &trans &trans &trans &trans &trans &kp LARW &kp DARW &kp UARW &kp RARW &trans &trans - &kp LSFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans - &kp LGUI &trans &kp SPC &kp RET &trans &kp RALT + &kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp BKSP + &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LARW &kp DARW &kp UARW &kp RARW &trans &trans + &kp LSFT &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp LGUI &trans &kp SPC &kp RET &trans &kp RALT >; }; diff --git a/app/boards/shields/iris/iris.keymap b/app/boards/shields/iris/iris.keymap index 46b0817f..3bd74ed7 100644 --- a/app/boards/shields/iris/iris.keymap +++ b/app/boards/shields/iris/iris.keymap @@ -3,6 +3,7 @@ #include #include +#include / { keymap { @@ -26,17 +27,17 @@ lower_layer { // ------------------------------------------------------------------------------------------------------------ -// | | | | | | | | | | | | | | +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | // | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | // | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | ~ | // | | | | | | | | | | | _ | + | { | } | "|" | // | | | | | | | | bindings = < -&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans -&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 -&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD -&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE - &trans &trans &trans &trans &trans &trans +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD +&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE + &trans &trans &trans &trans &trans &trans >; }; diff --git a/app/boards/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap index afd2694e..61c19f86 100644 --- a/app/boards/shields/lily58/lily58.keymap +++ b/app/boards/shields/lily58/lily58.keymap @@ -1,5 +1,6 @@ #include #include +#include / { keymap { @@ -25,17 +26,17 @@ lower_layer { // ------------------------------------------------------------------------------------------------------------ -// | | | | | | | | | | | | | | +// | BTCLR | BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | // | F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | // | ` | ! | @ | # | $ | % | | ^ | & | * | ( | ) | ~ | // | | | | | | | | | | | _ | + | { | } | "|" | // | | | | | | | | | | bindings = < -&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans -&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 -&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD -&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE - &trans &trans &trans &trans &trans &trans &trans &trans +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD +&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans >; sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD>; diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap index ffa2f6cc..07cd90e4 100644 --- a/app/boards/shields/qaz/qaz.keymap +++ b/app/boards/shields/qaz/qaz.keymap @@ -6,6 +6,7 @@ #include #include +#include #define DEFAULT 0 #define NUM_SYM 1 @@ -34,7 +35,7 @@ nav { bindings = < - &none &none &none &none &none &none &none &kp UARW &none &kp BKSP + &bt BT_CLR &bt BT_NXT &bt BT_PRV &none &none &none &none &kp UARW &none &kp BKSP &trans &trans &trans &trans &none &none &kp LARW &kp DARW &kp RARW &none &none &none &none &none &none &none &none &none &none &none &none &none &none &none &trans &trans &kp RET &trans &kp FSLH diff --git a/app/boards/shields/romac/romac.keymap b/app/boards/shields/romac/romac.keymap index f94a8290..97ea9c54 100644 --- a/app/boards/shields/romac/romac.keymap +++ b/app/boards/shields/romac/romac.keymap @@ -6,6 +6,7 @@ #include #include +#include / { keymap { @@ -28,16 +29,16 @@ nav_layer { // ----------------------- -// | _ | HOME | PGUP | -// | _ | END | PGDN | -// | _ | _ | _ | -// | _ | _ | RET | +// | BTNXT | HOME | PGUP | +// | BTPRV | END | PGDN | +// | BTCLR | _ | _ | +// | _ | _ | RET | // ----------------------- bindings = < - &trans &kp HOME &kp PGUP - &trans &kp END &kp PGDN - &trans &trans &trans - &trans &trans &kp RET + &bt BT_NXT &kp HOME &kp PGUP + &bt BT_PRV &kp END &kp PGDN + &bt BT_CLR &trans &trans + &trans &trans &kp RET >; }; }; diff --git a/app/boards/shields/sofle/sofle.keymap b/app/boards/shields/sofle/sofle.keymap index aadffa1f..1cbe742c 100644 --- a/app/boards/shields/sofle/sofle.keymap +++ b/app/boards/shields/sofle/sofle.keymap @@ -1,5 +1,6 @@ #include #include +#include / { keymap { @@ -44,17 +45,17 @@ raise_layer { // ------------------------------------------------------------------------------------------------------------ -// | | | | | | | | | | | | | | +// |BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | | | | | | | // | | INS | PSCR | GUI | | | | PGUP | | ^ | | | | // | | ALT | CTRL | SHIFT | | CAPS | | PGDN | <- | v | -> | DEL | BKSPC | // | | UNDO | CUT | COPY | PASTE | | | | | | | | | | | // | | | | | | | | | | | | bindings = < -&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans -&trans &kp INS &kp PRSC &kp GUI &trans &trans &kp PGUP &trans &kp UARW &trans &kp NUM_0 &trans -&trans &kp LALT &kp LCTL &kp LSFT &trans &kp CLCK &kp PGDN &kp LARW &kp DARW &kp RARW &kp DEL &kp BKSP -&trans &kp UNDO &kp CUT &kp COPY &kp PSTE &trans &trans &trans &trans &trans &trans &trans &trans &trans - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&trans &kp INS &kp PRSC &kp GUI &trans &trans &kp PGUP &trans &kp UARW &trans &kp NUM_0 &trans +&trans &kp LALT &kp LCTL &kp LSFT &trans &kp CLCK &kp PGDN &kp LARW &kp DARW &kp RARW &kp DEL &kp BKSP +&trans &kp UNDO &kp CUT &kp COPY &kp PSTE &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans >; sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD &inc_dec_kp PGUP PGDN>; From 1183f96cbc4e9a9d01b49278a43ea722486d5e67 Mon Sep 17 00:00:00 2001 From: tominabox1 Date: Mon, 14 Sep 2020 07:39:42 -0500 Subject: [PATCH 062/227] Update QAZ keymap for bluetooth config options and homerow hold-taps --- app/boards/shields/qaz/qaz.keymap | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap index ffa2f6cc..ac10772a 100644 --- a/app/boards/shields/qaz/qaz.keymap +++ b/app/boards/shields/qaz/qaz.keymap @@ -4,13 +4,27 @@ * SPDX-License-Identifier: MIT */ +#include #include #include #define DEFAULT 0 #define NUM_SYM 1 #define NAV 2 - + +/ { + behaviors { + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + label = "homerow mods"; + #binding-cells = <2>; + tapping_term_ms = <225>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; +}; + / { keymap { compatible = "zmk,keymap"; @@ -18,9 +32,9 @@ default_layer { bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P - &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp RET + &hm LGUI A &hm LALT S &hm LCTL D &hm LSFT F &kp G &kp H &hm RSFT J &hm RCTL K &hm RALT L &hm RGUI RET &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT - &kp LSFT &kp LGUI &kp LALT &mo NAV &kp SPC &mo NUM_SYM &kp QUOT &kp FSLH + &kp LSFT &kp LGUI &kp LALT < NAV RET < NUM_SYM SPC &kp COLN &kp QUOT &kp FSLH >; }; num_sym { @@ -37,7 +51,7 @@ &none &none &none &none &none &none &none &kp UARW &none &kp BKSP &trans &trans &trans &trans &none &none &kp LARW &kp DARW &kp RARW &none &none &none &none &none &none &none &none &none &none - &none &none &none &none &none &trans &trans &kp RET &trans &kp FSLH + &bt BT_CLR &bt BT_NXT &none &trans &trans &kp RET &trans &kp FSLH >; }; }; From fc167f5f5ede2049f5d7649353b456e36c9f0be3 Mon Sep 17 00:00:00 2001 From: tominabox1 Date: Mon, 14 Sep 2020 07:39:42 -0500 Subject: [PATCH 063/227] Update QAZ keymap for bluetooth config options and homerow hold-taps --- app/boards/shields/qaz/qaz.keymap | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap index 07cd90e4..1bcaba60 100644 --- a/app/boards/shields/qaz/qaz.keymap +++ b/app/boards/shields/qaz/qaz.keymap @@ -4,6 +4,7 @@ * SPDX-License-Identifier: MIT */ +#include #include #include #include @@ -11,7 +12,20 @@ #define DEFAULT 0 #define NUM_SYM 1 #define NAV 2 - + +/ { + behaviors { + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + label = "homerow mods"; + #binding-cells = <2>; + tapping_term_ms = <225>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; +}; + / { keymap { compatible = "zmk,keymap"; @@ -19,9 +33,9 @@ default_layer { bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P - &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp RET + &hm LGUI A &hm LALT S &hm LCTL D &hm LSFT F &kp G &kp H &hm RSFT J &hm RCTL K &hm RALT L &hm RGUI RET &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT - &kp LSFT &kp LGUI &kp LALT &mo NAV &kp SPC &mo NUM_SYM &kp QUOT &kp FSLH + &kp LSFT &kp LGUI &kp LALT < NAV RET < NUM_SYM SPC &kp COLN &kp QUOT &kp FSLH >; }; num_sym { @@ -38,7 +52,7 @@ &bt BT_CLR &bt BT_NXT &bt BT_PRV &none &none &none &none &kp UARW &none &kp BKSP &trans &trans &trans &trans &none &none &kp LARW &kp DARW &kp RARW &none &none &none &none &none &none &none &none &none &none - &none &none &none &none &none &trans &trans &kp RET &trans &kp FSLH + &bt BT_CLR &bt BT_NXT &none &trans &trans &kp RET &trans &kp FSLH >; }; }; From 6a02a2968aaae4ce803147fc4ab1f9e2ca6b4379 Mon Sep 17 00:00:00 2001 From: tominabox1 Date: Mon, 14 Sep 2020 08:43:28 -0500 Subject: [PATCH 064/227] add dstore to git ignore list --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e02cca0e..40e0536c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /tools /zephyr /build +*.DS_Store From 63e105db908dbae529c44a76c7f29622574f188c Mon Sep 17 00:00:00 2001 From: tominabox1 Date: Mon, 14 Sep 2020 08:45:31 -0500 Subject: [PATCH 065/227] Revising keymap to jive with upstream changes --- app/boards/shields/qaz/qaz.keymap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap index 1bcaba60..8781428b 100644 --- a/app/boards/shields/qaz/qaz.keymap +++ b/app/boards/shields/qaz/qaz.keymap @@ -52,7 +52,7 @@ &bt BT_CLR &bt BT_NXT &bt BT_PRV &none &none &none &none &kp UARW &none &kp BKSP &trans &trans &trans &trans &none &none &kp LARW &kp DARW &kp RARW &none &none &none &none &none &none &none &none &none &none - &bt BT_CLR &bt BT_NXT &none &trans &trans &kp RET &trans &kp FSLH + &none &none &none &trans &trans &kp RET &trans &kp FSLH >; }; }; From 62c47b1981f27bdcbdecb7aa3b704d665785ed2b Mon Sep 17 00:00:00 2001 From: tominabox1 Date: Mon, 14 Sep 2020 08:46:07 -0500 Subject: [PATCH 066/227] Remove duplicate include --- app/boards/shields/qaz/qaz.keymap | 1 - 1 file changed, 1 deletion(-) diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap index 8781428b..5ad9628e 100644 --- a/app/boards/shields/qaz/qaz.keymap +++ b/app/boards/shields/qaz/qaz.keymap @@ -4,7 +4,6 @@ * SPDX-License-Identifier: MIT */ -#include #include #include #include From 42c42ccbbd114641c596d795a196307cf36aea5d Mon Sep 17 00:00:00 2001 From: tominabox1 Date: Mon, 14 Sep 2020 09:25:31 -0500 Subject: [PATCH 067/227] Fixed some space/tab issues as well as updated copyright statements --- app/boards/shields/qaz/Kconfig.defconfig | 4 ++-- app/boards/shields/qaz/Kconfig.shield | 8 ++++---- app/boards/shields/qaz/qaz.keymap | 16 ++++++++-------- app/boards/shields/qaz/qaz.overlay | 4 ++-- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/boards/shields/qaz/Kconfig.defconfig b/app/boards/shields/qaz/Kconfig.defconfig index f82f4586..c84180bf 100644 --- a/app/boards/shields/qaz/Kconfig.defconfig +++ b/app/boards/shields/qaz/Kconfig.defconfig @@ -1,5 +1,5 @@ - # Copyright (c) 2020 TJ Campie - # SPDX-License-Identifier: MIT +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT if SHIELD_QAZ diff --git a/app/boards/shields/qaz/Kconfig.shield b/app/boards/shields/qaz/Kconfig.shield index 9da60772..32c443cd 100644 --- a/app/boards/shields/qaz/Kconfig.shield +++ b/app/boards/shields/qaz/Kconfig.shield @@ -1,5 +1,5 @@ -# Copyright (c) 2020 TJ Campie +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT - - config SHIELD_MY_BOARD - def_bool $(shields_list_contains,qaz) + +config SHIELD_MY_BOARD + def_bool $(shields_list_contains,qaz) diff --git a/app/boards/shields/qaz/qaz.keymap b/app/boards/shields/qaz/qaz.keymap index 5ad9628e..36229727 100644 --- a/app/boards/shields/qaz/qaz.keymap +++ b/app/boards/shields/qaz/qaz.keymap @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020 TJ Campie - * + * Copyright (c) 2020 The ZMK Contributors + * * SPDX-License-Identifier: MIT */ @@ -14,13 +14,13 @@ / { behaviors { - hm: homerow_mods { - compatible = "zmk,behavior-hold-tap"; - label = "homerow mods"; - #binding-cells = <2>; - tapping_term_ms = <225>; + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + label = "homerow mods"; + #binding-cells = <2>; + tapping_term_ms = <225>; flavor = "tap-preferred"; - bindings = <&kp>, <&kp>; + bindings = <&kp>, <&kp>; }; }; }; diff --git a/app/boards/shields/qaz/qaz.overlay b/app/boards/shields/qaz/qaz.overlay index 472005b9..4e733707 100644 --- a/app/boards/shields/qaz/qaz.overlay +++ b/app/boards/shields/qaz/qaz.overlay @@ -1,6 +1,6 @@ /* - * Copyright (c) 2020 TJ Campie - * + * Copyright (c) 2020 The ZMK Contributors + * * SPDX-License-Identifier: MIT */ From f6269df5fc7bbdf36ebb5aa5f0de9fc48f76469e Mon Sep 17 00:00:00 2001 From: Cody McGinnis Date: Mon, 14 Sep 2020 10:34:05 -0400 Subject: [PATCH 068/227] fix(tests): return error code when build fails --- app/run-test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/app/run-test.sh b/app/run-test.sh index 3b7cd589..dd8c8eed 100755 --- a/app/run-test.sh +++ b/app/run-test.sh @@ -22,6 +22,7 @@ echo "Running $testcase:" west build -d build/$testcase -b native_posix -- -DZMK_CONFIG=$testcase > /dev/null 2>&1 if [ $? -gt 0 ]; then echo "FAIL: $testcase did not build" >> ./build/tests/pass-fail.log + exit 1 else ./build/$testcase/zephyr/zmk.exe | sed -e "s/.*> //" | tee build/$testcase/keycode_events_full.log | sed -n -f $testcase/events.patterns > build/$testcase/keycode_events.log diff -au $testcase/keycode_events.snapshot build/$testcase/keycode_events.log From 0bf4467729f3bf560a04e51900489d81fe129376 Mon Sep 17 00:00:00 2001 From: tominabox1 Date: Mon, 14 Sep 2020 09:35:57 -0500 Subject: [PATCH 069/227] Update Kconfig.shield --- app/boards/shields/qaz/Kconfig.shield | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/boards/shields/qaz/Kconfig.shield b/app/boards/shields/qaz/Kconfig.shield index 32c443cd..7cc8f1e4 100644 --- a/app/boards/shields/qaz/Kconfig.shield +++ b/app/boards/shields/qaz/Kconfig.shield @@ -1,5 +1,5 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT -config SHIELD_MY_BOARD +config SHIELD_QAZ def_bool $(shields_list_contains,qaz) From 64c11f15b0cbc494045b8c2ba06e90e6a878d0ca Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Mon, 14 Sep 2020 20:19:54 -0700 Subject: [PATCH 070/227] Removed Copyright Header causing Parse Error --- app/boards/shields/iris/iris.keymap | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/boards/shields/iris/iris.keymap b/app/boards/shields/iris/iris.keymap index 46b0817f..4607adf0 100644 --- a/app/boards/shields/iris/iris.keymap +++ b/app/boards/shields/iris/iris.keymap @@ -1,6 +1,3 @@ -# Copyright (c) 2020 Pete Johanson, Kurtis Lew -# SPDX-License-Identifier: MIT - #include #include From 98098dbe21d96d75adbbbc2f7f375b85ce0c055e Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Mon, 14 Sep 2020 20:20:29 -0700 Subject: [PATCH 071/227] Updated build.yml to check default iris keymaps --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c8a711c1..30de94ee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,8 @@ jobs: - kyria_right - lily58_left - lily58_right + - iris_left + - iris_right - romac include: - board: proton_c From 1a492f0f9847d4c4f7e992c32b52920074d76ee4 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Mon, 14 Sep 2020 20:37:26 -0700 Subject: [PATCH 072/227] Updated dev guide --- docs/docs/dev-guide-new-shield.md | 36 +++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 6140b078..71af54ee 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -18,6 +18,9 @@ The high level steps are: - Add a default keymap, which users can override in their own configs as needed. - Add support for features such as encoders, OLED displays, or RGB underglow. + +- Update build.yml + It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.3.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing. ## New Shield Directory @@ -302,3 +305,36 @@ and then flash with: ``` west flash ``` + +## Updating `build.yml` + +Before publishing your shield to the public via a PR, navigate to `build.yml` found in `.github/workflows` and add your shield to the appropriate list. An example edit to `build.yml` is shown below. + +``` +jobs: + build: + runs-on: ubuntu-latest + name: Build Test + strategy: + matrix: + board: [proton_c, nice_nano, bluemicro840_v1, nrfmicro_13] + shield: + - corne_left + - corne_right + - kyria_left + - kyria_right + - lily58_left + - lily58_right + - iris_left + - iris_right + - romac + - + - + - + include: + - board: proton_c + shield: clueboard_california +``` +:::note +Notice that both the left and right halves of a split board need to be added to the list of shields for proper error checking. +:::note \ No newline at end of file From 5383bdd4dfc85b7782c489341eff96d0abf7dc72 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Mon, 14 Sep 2020 20:38:58 -0700 Subject: [PATCH 073/227] Revert "Merge pull request #1 from zmkfirmware/main" This reverts commit 36da21b8e334f70b6bd9986e9b31c8ec02b29f87, reversing changes made to 719db13c4150e0d09da2d3dbe90838fe604c2267. --- .../pro-micro/pro-micro-pins-labelled.jpg | Bin 115573 -> 0 bytes docs/docs/behavior/hold-tap.md | 2 +- docs/docs/dev-boards-shields-keymaps.md | 2 -- docs/docs/dev-guide-new-shield.md | 4 ---- 4 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg diff --git a/docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg b/docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg deleted file mode 100644 index f72d407719e9ff4d20ed45d93d12dead8caa9da5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 115573 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 DB^7&W diff --git a/docs/docs/behavior/hold-tap.md b/docs/docs/behavior/hold-tap.md index ab510223..fa68538b 100644 --- a/docs/docs/behavior/hold-tap.md +++ b/docs/docs/behavior/hold-tap.md @@ -59,4 +59,4 @@ If this config does not work for you, try the flavor "tap-preferred" and a short If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter.For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. #### Note -Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. +Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. \ No newline at end of file diff --git a/docs/docs/dev-boards-shields-keymaps.md b/docs/docs/dev-boards-shields-keymaps.md index 9ed5a328..cfe52526 100644 --- a/docs/docs/dev-boards-shields-keymaps.md +++ b/docs/docs/dev-boards-shields-keymaps.md @@ -35,8 +35,6 @@ in the `app/boards/${arch}/${board_name}` directory, e.g. `app/boards/arm/planck ## Pro Micro Compatible Keyboard -![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) - For keyboards that require a (usually Pro Micro compatible) add-on board to operate, the ZMK integration pieces are places in the _shield_ definition for that keyboard, allowing users to swap in different Pro Micro compatible boards (e.g. Proton-C, or nice!nano) and build a firmware the matches their actual diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 71af54ee..f270199d 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -67,10 +67,6 @@ endif ## Shield Overlay -![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) - -ZMK uses the green color coded pin names to generate devicetree node references. For example, to refer to the node `D0` in the devicetree files, use `&pro_micro_d 0` or to refer to `A1`, use `&pro_micro_a 1`. - The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, this might look something like: From f6932992d213a9e5ef061a13e7b8ef1137e7aa2f Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Mon, 14 Sep 2020 20:39:30 -0700 Subject: [PATCH 074/227] Revert "Revert "Merge pull request #1 from zmkfirmware/main"" This reverts commit 5383bdd4dfc85b7782c489341eff96d0abf7dc72. --- .../pro-micro/pro-micro-pins-labelled.jpg | Bin 0 -> 115573 bytes docs/docs/behavior/hold-tap.md | 2 +- docs/docs/dev-boards-shields-keymaps.md | 2 ++ docs/docs/dev-guide-new-shield.md | 4 ++++ 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg diff --git a/docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg b/docs/docs/assets/pro-micro/pro-micro-pins-labelled.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f72d407719e9ff4d20ed45d93d12dead8caa9da5 GIT binary patch literal 115573 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 DB^7&W literal 0 HcmV?d00001 diff --git a/docs/docs/behavior/hold-tap.md b/docs/docs/behavior/hold-tap.md index fa68538b..ab510223 100644 --- a/docs/docs/behavior/hold-tap.md +++ b/docs/docs/behavior/hold-tap.md @@ -59,4 +59,4 @@ If this config does not work for you, try the flavor "tap-preferred" and a short If you want to use a tap-hold with a keycode from a different code page, you have to define another behavior with another "bindings" parameter.For example, if you want to use SHIFT and volume up, define the bindings like `bindings = <&kp>, <&cp>;`. Only single-argument behaviors are supported at the moment. #### Note -Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. \ No newline at end of file +Astute readers may notice similarities between the possible behaviors in ZMK and other firmware, such as QMK. The hold-preferred flavor works similar to the `HOLD_ON_OTHER_KEY_PRESS` setting. The 'balanced' flavor is similar to the `PERMISSIVE_HOLD` setting, and the `tap-preferred` flavor is similar to `IGNORE_MOD_TAP_INTERRUPT`. diff --git a/docs/docs/dev-boards-shields-keymaps.md b/docs/docs/dev-boards-shields-keymaps.md index cfe52526..9ed5a328 100644 --- a/docs/docs/dev-boards-shields-keymaps.md +++ b/docs/docs/dev-boards-shields-keymaps.md @@ -35,6 +35,8 @@ in the `app/boards/${arch}/${board_name}` directory, e.g. `app/boards/arm/planck ## Pro Micro Compatible Keyboard +![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) + For keyboards that require a (usually Pro Micro compatible) add-on board to operate, the ZMK integration pieces are places in the _shield_ definition for that keyboard, allowing users to swap in different Pro Micro compatible boards (e.g. Proton-C, or nice!nano) and build a firmware the matches their actual diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index f270199d..71af54ee 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -67,6 +67,10 @@ endif ## Shield Overlay +![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) + +ZMK uses the green color coded pin names to generate devicetree node references. For example, to refer to the node `D0` in the devicetree files, use `&pro_micro_d 0` or to refer to `A1`, use `&pro_micro_a 1`. + The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, this might look something like: From 0f8561daa155c765b2c04fe012bc4fa3d38cdfd7 Mon Sep 17 00:00:00 2001 From: Kurtis Lew Date: Mon, 14 Sep 2020 20:46:42 -0700 Subject: [PATCH 075/227] Update dev-guide-new-shield.md --- docs/docs/dev-guide-new-shield.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 71af54ee..c5b9a3de 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -17,8 +17,6 @@ The high level steps are: - (Optional) Add the matrix transform for mapping KSCAN row/column values to sane key positions. This is needed for non-rectangular keyboards, or where the underlying row/column pin arrangement does not map one to one with logical locations on the keyboard. - Add a default keymap, which users can override in their own configs as needed. - Add support for features such as encoders, OLED displays, or RGB underglow. - - - Update build.yml It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.3.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing. @@ -337,4 +335,4 @@ jobs: ``` :::note Notice that both the left and right halves of a split board need to be added to the list of shields for proper error checking. -:::note \ No newline at end of file +:::note From d86e571757aef33dd0e9256715752a462b5a60fe Mon Sep 17 00:00:00 2001 From: Kurtis Lew Date: Mon, 14 Sep 2020 20:47:55 -0700 Subject: [PATCH 076/227] Update iris.keymap --- app/boards/shields/iris/iris.keymap | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/boards/shields/iris/iris.keymap b/app/boards/shields/iris/iris.keymap index 4607adf0..87654021 100644 --- a/app/boards/shields/iris/iris.keymap +++ b/app/boards/shields/iris/iris.keymap @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 Pete Johanson, Kurtis Lew + * + * SPDX-License-Identifier: MIT + */ + #include #include From ec86500524239500552e0105a86dd62872b99fd7 Mon Sep 17 00:00:00 2001 From: Kurtis Lew Date: Mon, 14 Sep 2020 20:53:26 -0700 Subject: [PATCH 077/227] Update dev-guide-new-shield.md --- docs/docs/dev-guide-new-shield.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index c5b9a3de..01aad30c 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -326,9 +326,9 @@ jobs: - iris_left - iris_right - romac - - - - - - + - + - + - include: - board: proton_c shield: clueboard_california From 81bc157f539235ad032fde78b6f6cec7a16d2c39 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 15 Sep 2020 14:31:59 -0500 Subject: [PATCH 078/227] Fix underglow not working by default --- app/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Kconfig b/app/Kconfig index cefae21a..cda5c582 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -168,6 +168,10 @@ menuconfig ZMK_RGB_UNDERGLOW if ZMK_RGB_UNDERGLOW +# This default value cuts down on tons of excess .conf files, if you're using GPIO, manually disable this +config SPI + default y + config ZMK_RGB_UNDERGLOW_HUE_STEP int "RGB underglow hue step in degrees of 360" default 10 From 608ae0df6dfe4d75bc98c36f6756dc4d69399109 Mon Sep 17 00:00:00 2001 From: Nick Date: Tue, 15 Sep 2020 14:47:19 -0500 Subject: [PATCH 079/227] fix lint with clang-format --- app/src/rgb_underglow.c | 57 ++++++++++++++++------------------------- app/src/settings.c | 9 ++----- 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c index d453755b..b371c943 100644 --- a/app/src/rgb_underglow.c +++ b/app/src/rgb_underglow.c @@ -52,9 +52,7 @@ struct led_rgb pixels[STRIP_NUM_PIXELS]; struct rgb_underglow_state state; #if IS_ENABLED(CONFIG_SETTINGS) -static int rgb_settings_set(const char *name, size_t len, - settings_read_cb read_cb, void *cb_arg) -{ +static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) { const char *next; int rc; @@ -74,14 +72,10 @@ static int rgb_settings_set(const char *name, size_t len, return -ENOENT; } -struct settings_handler rgb_conf = { - .name = "rgb/underglow", - .h_set = rgb_settings_set -}; +struct settings_handler rgb_conf = {.name = "rgb/underglow", .h_set = rgb_settings_set}; #endif -static struct led_rgb hsb_to_rgb(struct led_hsb hsb) -{ +static struct led_rgb hsb_to_rgb(struct led_hsb hsb) { double r, g, b; u8_t i = hsb.h / 60; @@ -130,20 +124,16 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) return rgb; } -static void zmk_rgb_underglow_off() -{ - for (int i=0; i #include -static int zmk_settings_init(struct device *_arg) -{ - return settings_load(); -} +static int zmk_settings_init(struct device *_arg) { return settings_load(); } -SYS_INIT(zmk_settings_init, - APPLICATION, - CONFIG_APPLICATION_INIT_PRIORITY); +SYS_INIT(zmk_settings_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); From 2855ba75f53554887f6e788736c45b7c818d09ac Mon Sep 17 00:00:00 2001 From: David Barr Date: Sat, 19 Sep 2020 10:55:07 +0100 Subject: [PATCH 080/227] Actually really working Ok, both sides work as expected, need to write a keymap. --- app/boards/shields/Kconfig.defconfig | 14 +++++ app/boards/shields/Kconfig.shield | 5 ++ app/boards/shields/cradios.dtsi | 67 ++++++++++++++++++++++++ app/boards/shields/cradios.keymap | 18 +++++++ app/boards/shields/cradios_left.conf | 2 + app/boards/shields/cradios_left.overlay | 15 ++++++ app/boards/shields/cradios_right.conf | 2 + app/boards/shields/cradios_right.overlay | 17 ++++++ 8 files changed, 140 insertions(+) create mode 100644 app/boards/shields/Kconfig.defconfig create mode 100644 app/boards/shields/Kconfig.shield create mode 100644 app/boards/shields/cradios.dtsi create mode 100644 app/boards/shields/cradios.keymap create mode 100644 app/boards/shields/cradios_left.conf create mode 100644 app/boards/shields/cradios_left.overlay create mode 100644 app/boards/shields/cradios_right.conf create mode 100644 app/boards/shields/cradios_right.overlay diff --git a/app/boards/shields/Kconfig.defconfig b/app/boards/shields/Kconfig.defconfig new file mode 100644 index 00000000..5b9ca9a1 --- /dev/null +++ b/app/boards/shields/Kconfig.defconfig @@ -0,0 +1,14 @@ + + + +config ZMK_KEYBOARD_NAME + default "cradios" + +# Unable to use interrupts as the same pin number is used +# across A & B controllers, and STM32F303CCT6 can't enable +# interrutps for multiple controllers for the same "line" +# for the external interrupts. +config ZMK_KSCAN_GPIO_POLLING + default y + + diff --git a/app/boards/shields/Kconfig.shield b/app/boards/shields/Kconfig.shield new file mode 100644 index 00000000..844d4332 --- /dev/null +++ b/app/boards/shields/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 Pete Johanson +# SPDX-License-Identifier: MIT + +config SHIELD_CRADIOS + def_bool $(shields_list_contains,cradios) diff --git a/app/boards/shields/cradios.dtsi b/app/boards/shields/cradios.dtsi new file mode 100644 index 00000000..68d1fc57 --- /dev/null +++ b/app/boards/shields/cradios.dtsi @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + #include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <34>; + rows = <1>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) +RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) +RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) +RC(0,15) RC(0,16) RC(0,33) RC(0,32) +>; + + + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + label = "KSCAN"; + }; + + + + + bt_unpair_combo: bt_unpair_combo { + compatible = "zmk,bt-unpair-combo"; + }; + + + + }; + + + &kscan0 { + input-gpios + = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; + + diff --git a/app/boards/shields/cradios.keymap b/app/boards/shields/cradios.keymap new file mode 100644 index 00000000..c46468dd --- /dev/null +++ b/app/boards/shields/cradios.keymap @@ -0,0 +1,18 @@ +#include +#include + + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH + &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 + >; + }; + }; +}; diff --git a/app/boards/shields/cradios_left.conf b/app/boards/shields/cradios_left.conf new file mode 100644 index 00000000..1e028a78 --- /dev/null +++ b/app/boards/shields/cradios_left.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y diff --git a/app/boards/shields/cradios_left.overlay b/app/boards/shields/cradios_left.overlay new file mode 100644 index 00000000..b0bdc6fe --- /dev/null +++ b/app/boards/shields/cradios_left.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ +#include "cradios.dtsi" + + + + + + +&bt_unpair_combo { + key-positions = <0 16>; +}; diff --git a/app/boards/shields/cradios_right.conf b/app/boards/shields/cradios_right.conf new file mode 100644 index 00000000..990cf7c0 --- /dev/null +++ b/app/boards/shields/cradios_right.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL=y diff --git a/app/boards/shields/cradios_right.overlay b/app/boards/shields/cradios_right.overlay new file mode 100644 index 00000000..ef920ac3 --- /dev/null +++ b/app/boards/shields/cradios_right.overlay @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ +#include "cradios.dtsi" + +&default_transform { + col-offset = <17>; +}; + + + + +&bt_unpair_combo { + key-positions = <21 32>; +}; From ed5d3646fe7596fb40d0b7505f8062cdac6537be Mon Sep 17 00:00:00 2001 From: David Barr Date: Sat, 19 Sep 2020 10:56:40 +0100 Subject: [PATCH 081/227] Add files via upload --- app/boards/shields/cradios/cradios.dtsi | 51 ++++++++++++++++--- .../shields/cradios/cradios_left.overlay | 29 +++-------- .../shields/cradios/cradios_right.overlay | 29 +++-------- 3 files changed, 55 insertions(+), 54 deletions(-) diff --git a/app/boards/shields/cradios/cradios.dtsi b/app/boards/shields/cradios/cradios.dtsi index 95b4f272..68d1fc57 100644 --- a/app/boards/shields/cradios/cradios.dtsi +++ b/app/boards/shields/cradios/cradios.dtsi @@ -10,23 +10,58 @@ zmk,kscan = &kscan0; zmk,matrix_transform = &default_transform; }; - default_transform: keymap_transform_0 { compatible = "zmk,matrix-transform"; columns = <34>; rows = <1>; map = < -RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,17) RC(0,18) RC(0,19) RC(0,20) RC(0,21) -RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,22) RC(0,23) RC(0,24) RC(0,25) RC(0,26) -RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,27) RC(0,28) RC(0,29) RC(0,30) RC(0,31) -RC(0,15) RC(0,16) RC(0,32) RC(0,33) +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) +RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) +RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) +RC(0,15) RC(0,16) RC(0,33) RC(0,32) >; + + }; - kscan0: kscan { - compatible = "zmk,kscan-gpio-direct"; - label = "KSCAN"; + kscan0: kscan { + compatible = "zmk,kscan-gpio-direct"; + label = "KSCAN"; }; + + + + bt_unpair_combo: bt_unpair_combo { + compatible = "zmk,bt-unpair-combo"; + }; + + + }; + + + &kscan0 { + input-gpios + = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + ; +}; + + diff --git a/app/boards/shields/cradios/cradios_left.overlay b/app/boards/shields/cradios/cradios_left.overlay index ab5a874d..b0bdc6fe 100644 --- a/app/boards/shields/cradios/cradios_left.overlay +++ b/app/boards/shields/cradios/cradios_left.overlay @@ -6,27 +6,10 @@ #include "cradios.dtsi" -&kscan0 { - input-gpios - = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - ; + + + + +&bt_unpair_combo { + key-positions = <0 16>; }; - - - diff --git a/app/boards/shields/cradios/cradios_right.overlay b/app/boards/shields/cradios/cradios_right.overlay index 59a81ba5..ef920ac3 100644 --- a/app/boards/shields/cradios/cradios_right.overlay +++ b/app/boards/shields/cradios/cradios_right.overlay @@ -8,27 +8,10 @@ &default_transform { col-offset = <17>; }; -&kscan0 { - input-gpios - = <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - ; + + + + +&bt_unpair_combo { + key-positions = <21 32>; }; - - - From 550c35db23f15c6835a43fe1d2e4a3b5a04ac2b8 Mon Sep 17 00:00:00 2001 From: CrossR Date: Sun, 20 Sep 2020 12:52:25 +0100 Subject: [PATCH 082/227] Fix PR comments, add error checking for push. --- docs/static/setup.ps1 | 23 ++++++++++++++++++----- docs/static/setup.sh | 34 +++++++++++++++++++++++----------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index acda1944..a2d66eec 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -16,7 +16,7 @@ function Get-Choice-From-Options { if ($selection -eq $Options.length + 1) { Write-Host "Goodbye!" - exit + exit 1 } elseif ($selection -le $Options.length) { $choice = $($selection - 1) @@ -40,7 +40,7 @@ function Test-Git-Config { if ($lastExitCode -ne 0) { Write-Host $ErrMsg - exit + exit 1 } } @@ -49,7 +49,7 @@ try { } catch [System.Management.Automation.CommandNotFoundException] { Write-Host "Git is not installed, and is required for this script!" - exit + exit 1 } Test-Git-Config -Option "user.name" -ErrMsg "Git username not set!`nRun: git config --global user.name 'My Name'" @@ -134,7 +134,7 @@ $do_it = Read-Host "Continue? [Yn]" if ($do_it -ne "" -and $do_it -ne "Y" -and $do_it -ne "y") { Write-Host "Aborting..." - exit + exit 1 } git clone --single-branch "$repo_path" "$repo_name" @@ -167,10 +167,23 @@ git commit -m "Initial User Config." if ($github_repo -ne "") { git remote add origin "$github_repo" + git push --set-upstream origin $(git symbolic-ref --short HEAD) + # If push failed, assume that the origin was incorrect and give instructions on fixing. + if ($lastExitCode -ne 0) { + Write-Host "Remote repository $github_repo not found..." + Write-Host "Check GitHub URL, and try adding again." + Write-Host "Run the following: " + Write-Host " git remote rm origin" + Write-Host " git remote add origin FIXED_URL" + Write-Host " git push --set-upstream origin $(git symbolic-ref --short HEAD)" + Write-Host "Once pushed, your firmware should be availalbe from GitHub Actions at: $actions" + exit 1 + } + if ($github_repo -imatch "https") { $actions = "$($github_repo.substring(0, $github_repo.length - 4))/actions" - Write-Host "Your firmware should be availalbe from the GitHub Actions shortly: $actions" + Write-Host "Your firmware should be availalbe from GitHub Actions shortly: $actions" } } diff --git a/docs/static/setup.sh b/docs/static/setup.sh index b3c14f77..df985a67 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -2,21 +2,21 @@ set -e -CheckExists() { +check_exists() { command_to_run=$1 error_message=$2 if ! eval "$command_to_run" &> /dev/null; then printf "%s\n" "$error_message" - exit + exit 1 fi } -CheckExists "command -v git" "git is not installed, and is required for this script!" -CheckExists "command -v curl" "curl is not installed, and is required for this script!" +check_exists "command -v git" "git is not installed, and is required for this script!" +check_exists "command -v curl" "curl is not installed, and is required for this script!" -CheckExists "git config user.name" "Git username not set!\nRun: git config --global user.name 'My Name'" -CheckExists "git config user.email" "Git email not set!\nRun: git config --global user.email 'example@myemail.com'" +check_exists "git config user.name" "Git username not set!\nRun: git config --global user.name 'My Name'" +check_exists "git config user.email" "Git email not set!\nRun: git config --global user.email 'example@myemail.com'" repo_path="https://github.com/zmkfirmware/zmk-config-split-template.git" title="ZMK Config Setup:" @@ -36,8 +36,8 @@ select opt in "${options[@]}" "Quit"; do 2 ) board="proton_c"; break;; 3 ) board="bluemicro840_v1"; break;; - $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit;; - *) echo "Invalid option. Try another one.";continue;; + $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;; + *) echo "Invalid option. Try another one."; continue;; esac done @@ -65,7 +65,7 @@ select opt in "${options[@]}" "Quit"; do # Add link to docs on adding your own custom shield in your ZMK config! # $(( ${#options[@]}+1 )) ) echo "Other!"; break;; - $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit;; + $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;; *) echo "Invalid option. Try another one.";continue;; esac @@ -111,7 +111,7 @@ read -r -p "Continue? [Yn]: " do_it if [ -n "$do_it" ] && [ "$do_it" != "y" ] && [ "$do_it" != "Y" ]; then echo "Aborting..." - exit + exit 1 fi git clone --single-branch $repo_path ${repo_name} @@ -149,8 +149,20 @@ if [ -n "$github_repo" ]; then git remote add origin "$github_repo" git push --set-upstream origin "$(git symbolic-ref --short HEAD)" + # If push failed, assume that the origin was incorrect and give instructions on fixing. + if [ $? -ne 0 ] { + echo "Remote repository $github_repo not found..." + echo "Check GitHub URL, and try adding again." + echo "Run the following: " + echo " git remote rm origin" + echo " git remote add origin FIXED_URL" + echo " git push --set-upstream origin $(git symbolic-ref --short HEAD)" + echo "Once pushed, your firmware should be availalbe from GitHub Actions at: ${github_repo%.git}/actions" + exit 1 + } + # TODO: Support determing the actions URL when non-https:// repo URL is used. if [ "${github_repo}" != "${github_repo#https://}" ]; then - echo "Your firmware should be available from the GitHub Actions shortly: ${github_repo%.git}/actions" + echo "Your firmware should be available from GitHub Actions shortly: ${github_repo%.git}/actions" fi fi From aa1f9bad6e76b878441806d3b2b6e555ff7e2c43 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sat, 19 Sep 2020 23:18:48 -0400 Subject: [PATCH 083/227] chore: Add initial CONTRIBUTING.md docs.* Closes #23 --- CONTRIBUTING.md | 120 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..3ea8c783 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,120 @@ +# Contributing To ZMK + +Thanks for taking an interest in contributing to ZMK! After reading through the documentation, if +you have any questions, please come join us on the +[ZMK Discord Server][discord-invite]. + +## Code of Conduct + +All community members are expected to abide by the [Code of Conduct][code-of-conduct]. +For any and all conduct inquiries or concerns, please contact conduct@zmkfirmware.dev. + +[code-of-conduct]: https://github.com/zmkfirmware/zmk/blob/main/CODE_OF_CONDUCT.md + +## How Can I Contribute + +There are many different ways that you can contribute to ZMK, several of which require no coding +abilities. These include: + +- Chat Support +- Issue Reporting/Commenting +- Testing +- Documentation +- Code Contributions + +## Chat Support + +Providing user support on the [ZMK Discord Server][discord-invite] is a great way to help the +project. In particular, answering questions in the [#help](https://discord.com/channels/719497620560543766/719909884769992755) channel is incredibly appreciated. + +## Issue Reporting/Commenting + +Often, you might encounter unexpected behavior when building, flashing, or running the ZMK +firmware. Submitting or commenting on issues on GitHub is a great way to contribute to the +ZMK project. + +### Before Submitting a Report + +- Review the [Frequently Asked Questions](https://zmkfirmware.dev/docs/faq). +- Check the [Troubleshooting Guide](https://zmkfirmware.dev/docs/troubleshooting) for answers. +- Search the [open issues](https://github.com/zmkfirmware/zmk/issues) for an existing report that + matches your problem. + +### Opening A Report + +To open a report: + +- Head to https://github.com/zmkfirmware/zmk/issues/new +- Provide an accurate summary of the issue in the title. +- Provide as much detail as you can about the issue including: + - What [board/shield](https://zmkfirmware.dev/docs/faq#what-is-a-board) you are using. + - A link to the user repository, if you used it to build your firmware. + - Exact steps to reproduce the problem. + - Any relevant screenshots or [logs](https://zmkfirmware.dev/docs/dev-guide-usb-logging) + +## Testing + +The `help wanted` label will be added to any [pull requests](https://github.com/zmkfirmware/zmk/pulls?q=is%3Aopen+is%3Apr+label%3A%22help+wanted%22) +or [issues](https://github.com/zmkfirmware/zmk/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22) +where user testing can assist the ZMK contributors to verify fixes, confirm +bugs, etc. + +When providing testing feedback, please provide: + +- Exact steps used to test +- Any hardware details relevant to testing +- Pass/fail summary for testing. +- Full details of any failures, including: + - Logs + - Screenshots + +## Documentation + +Quality documentation is a huge part of what makes a successful project. Contributions to add +documentation to areas not currently covered are greatly appreciated. + +### Contributing + +- The documentation site can be found in the main ZMK repo, in the + [docs/](https://github.com/zmkfirmware/zmk/tree/main/docs) subdirectory. +- The documentation is maintained using [Docusaurus V2](https://v2.docusaurus.io/docs/). +- To get started, from the `docs/` directory, run `npm ci` and then `npm start`. +- Enhancements should be submitted as pull requests to the `main` branch of ZMK. + +## Code Contributions + +### Development Setup + +To get your development environment setup going, start at the +[basic setup](https://zmkfirmware.dev/docs/dev-setup) docs, and make sure you can build and flash +your own locally built firmware. + +### Formatting + +ZMK uses `clang-format` to ensure consist formatting for our source code. Before submitting your +changes, make sure you've manually run `clang-format`, or have your IDE configured to auto-format +on save. + +### Commit Messages + +The ZMK project is working towards, but not yet enforcing, the use of +[conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) for commit messages. + +Further documentation and details will be provided here soon. + +### Pull Requests + +When opening a pull request with your changes, please: + +- Submit the PR to the `main` branch of the + [`zmkfirmware/zmk`](https://github.com/zmkfirmware/zmk) repository. +- Use a descriptive title that summarizes the change. +- In the description, include: + - References to any open issues fixed by the PR. + - Feature added by the PR + - Bugs fixed by the PR. + - Testing you've performed locally. + - Requested testing by reviewers or testers. + - Screenshots or logs that support understanding the change. + +[discord-invite]: https://zmkfirmware.dev/community/discord/invite From 90bfe6026da99f352af750403880fb55defa1b42 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 21 Sep 2020 09:49:56 -0400 Subject: [PATCH 084/227] fix(boards): Flash Planck with `dfu-util`. --- app/boards/arm/planck/board.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/boards/arm/planck/board.cmake b/app/boards/arm/planck/board.cmake index 4843c415..772796da 100644 --- a/app/boards/arm/planck/board.cmake +++ b/app/boards/arm/planck/board.cmake @@ -1,6 +1,7 @@ # SPDX-License-Identifier: MIT +board_runner_args(dfu-util "--pid=0483:df11" "--alt=0" "--dfuse") board_runner_args(jlink "--device=STM32F303VC" "--speed=4000") -include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake) +include(${ZEPHYR_BASE}/boards/common/dfu-util.board.cmake) include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake) From a7ef79e3f8f98785523cf0ebf990c1ca3db2fe60 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 21 Sep 2020 01:25:37 -0400 Subject: [PATCH 085/227] feat(blog): SOTF #2 initial work.- Closes #182 --- docs/blog/2020-09-21-zmk-sotf-2.md | 106 +++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 docs/blog/2020-09-21-zmk-sotf-2.md diff --git a/docs/blog/2020-09-21-zmk-sotf-2.md b/docs/blog/2020-09-21-zmk-sotf-2.md new file mode 100644 index 00000000..82278add --- /dev/null +++ b/docs/blog/2020-09-21-zmk-sotf-2.md @@ -0,0 +1,106 @@ +--- +title: ZMK State Of The Firmware \#2 +author: Pete Johanson +author_title: Project Creator +author_url: https://gitlab.com/petejohanson +author_image_url: https://www.gravatar.com/avatar/2001ceff7e9dc753cf96fcb2e6f41110 +tags: [SOTF, keyboards, firmware, oss, ble] +--- + +Welcome to the second ZMK "State Of The Firmware" (SOTF)! + +This update will cover all the major activity since [SOTF #1](/blog/2020/08/12/zmk-sotf-1), preparations for the upcoming +Hacktoberfest activity, and a current open call for community feedback on a ZMK mascot. + +## Recent Activity + +So much going on in ZMK! + +- Added a new generic [Hold Tap behavior](https://zmkfirmware.dev/docs/behavior/hold-tap) + in [#146](https://github.com/zmkfirmware/zmk/pull/146) which now powers mod-tap, layer-tap, etc. - [okke-formsma] +- [BLE profile/connection management](https://zmkfirmware.dev/docs/behavior/bluetooth) + in [#133](https://github.com/zmkfirmware/zmk/pull/133) - [petejohanson] +- Integration tests were added to automate testing of behaviors in [#131](https://github.com/zmkfirmware/zmk/pull/131) by [BrainWart] & [petejohanson] +- [Toggle layer behavior](https://zmkfirmware.dev/docs/behavior/layers#toggle-layer), e.g. `&tog LOWER`, in + [#98](https://github.com/zmkfirmware/zmk/pull/98) - [BrainWart] +- Key fix for dropped press/release over HID [#93](https://github.com/zmkfirmware/zmk/pull/93)/[#96](https://github.com/zmkfirmware/zmk/pull/96) - [careyk007](https://github.com/careyk007) & [petejohanson] +- Code formatting standardized using `clang-format` in [#183](https://github.com/zmkfirmware/zmk/pull/183) - [petejohanson] +- [Bootloader reset behavior](https://zmkfirmware.dev/docs/behavior/reset#bootloader-reset), e.g. `&bootloader`, in [#116](https://github.com/zmkfirmware/zmk/pull/116) - [petejohanson] +- Various bug fixes and documentation + +## New Shields + +- QAZ in [#130](https://github.com/zmkfirmware/zmk/pull/130) - [tominabox1](https://github.com/tominabox1) +- Iris in [#151](https://github.com/zmkfirmware/zmk/pull/151) - [kurtis-lew](https://github.com/kurtis-lew) +- RoMac 2.1 in [#122](https://github.com/zmkfirmware/zmk/pull/122) - [bmcgavin](https://github.com/bmcgavin) +- Sofle in [#118](https://github.com/zmkfirmware/zmk/pull/118) - [CrossR](https://github.com/CrossR) +- splitreus62 in [#92](https://github.com/zmkfirmware/zmk/pull/92) - [Na-Cly](https://github.com/Na-Cly) + +## New Boards + +- DZ60RGB rev1 in [#166](https://github.com/zmkfirmware/zmk/pull/166) - [Nicell] +- nrfMicro in [#101](https://github.com/zmkfirmware/zmk/pull/101) - [okke-formsma] +- BlueMicro840 [#91](https://github.com/zmkfirmware/zmk/pull/91) - [Na-Cly](https://github.com/Na-Cly) + +## Hacktoberfest Preparation + +[Hacktoberfest](https://hacktoberfest.digitalocean.com/) is a yearly celebration of open source, +which encourages participation in OSS, especially from new contributors. + +The ZMK contributors have been busy preparing for folks to join in on the fun by contributing to +ZMK! + +- There is now a basic [Contributing Guide](https://github.com/zmkfirmware/zmk/blob/main/CONTRIBUTING.md) to help newcomers get oriented, and get up to speed. +- The [`Hacktoberfest`](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3AHacktoberfest) + issue label will help participants discover good issues to work on. + (The existing [`good first issue`](https://github.com/zmkfirmware/zmk/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label also helps with this) + +We're looking forward to the launch of Hacktoberfest! + +## Mascot Selection Feedback + +The ZMK project would like to settle on a mascot! We're soliciting community feedback as part of +the process before a final mascot is selected. + +The current mascots up for consideration are: + +- Griffin +- Peregrine Falcon +- Zapata Wren +- Zorro (south american fox) + +If you're interested in helping with the decision, head over to [Issue #195](https://github.com/zmkfirmware/zmk/issues/195) and add a reaction! + +## Coming Soon! + +There still lots of activity in ZMK, and plenty of exciting upcoming changes. + +- Improved modifier infrastructure, including "shifted keycodes" - [okke-formsma] +- Battery percentage reporting over BLE - [Nicell] +- Complete defines for HID keycodes/usage IDs - [innovaker](https://github.com/innovaker) +- Additional core BLE connection/bond management work - [petejohanson] +- Improved power management - [petejohanson], [Nicell] +- One shot mod/layer behaviors - [okke-formsma] + +## Statistics + +Some statistics of interest for ZMK: + +- GitHub + - 115 Closed PRs + - 64 Stars + - 48 Forks +- Discord Chat + - 186 total registered +- Website (last 30 days) + - 7.4K page views + - 474 new users + +## Thanks! + +Thanks again to the numerous contributors and users who have made working on ZMK such a pleasure! + +[okke-formsma]: https://github.com/okke-formsma +[nicell]: https://github.com/Nicell +[petejohanson]: https://github.com/petejohanson +[brainwart]: https://github.com/BrainWart From c044fe853275a6322834bfdeaf61b9f62becf085 Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Mon, 21 Sep 2020 22:29:54 -0700 Subject: [PATCH 086/227] Add RoMac plus v4 support on nice nano v1 --- .../shields/romac_plus/Kconfig.defconfig | 9 +++ app/boards/shields/romac_plus/Kconfig.shield | 5 ++ .../romac_plus/boards/nice_nano.overlay | 28 +++++++++ app/boards/shields/romac_plus/romac_plus.conf | 3 + app/boards/shields/romac_plus/romac_plus.dtsi | 61 +++++++++++++++++++ .../shields/romac_plus/romac_plus.keymap | 48 +++++++++++++++ .../shields/romac_plus/romac_plus.overlay | 37 +++++++++++ 7 files changed, 191 insertions(+) create mode 100644 app/boards/shields/romac_plus/Kconfig.defconfig create mode 100644 app/boards/shields/romac_plus/Kconfig.shield create mode 100644 app/boards/shields/romac_plus/boards/nice_nano.overlay create mode 100644 app/boards/shields/romac_plus/romac_plus.conf create mode 100644 app/boards/shields/romac_plus/romac_plus.dtsi create mode 100644 app/boards/shields/romac_plus/romac_plus.keymap create mode 100644 app/boards/shields/romac_plus/romac_plus.overlay diff --git a/app/boards/shields/romac_plus/Kconfig.defconfig b/app/boards/shields/romac_plus/Kconfig.defconfig new file mode 100644 index 00000000..45b15b8d --- /dev/null +++ b/app/boards/shields/romac_plus/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 Pete Johanson, Richard Jones +# SPDX-License-Identifier: MIT + +if SHIELD_ROMAC_PLUS + +config ZMK_KEYBOARD_NAME + default "RoMac_plus-v4" + +endif \ No newline at end of file diff --git a/app/boards/shields/romac_plus/Kconfig.shield b/app/boards/shields/romac_plus/Kconfig.shield new file mode 100644 index 00000000..c89ef023 --- /dev/null +++ b/app/boards/shields/romac_plus/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 Pete Johanson, Richard Jones +# SPDX-License-Identifier: MIT + +config SHIELD_ROMAC_PLUS + def_bool $(shields_list_contains,romac_plus) diff --git a/app/boards/shields/romac_plus/boards/nice_nano.overlay b/app/boards/shields/romac_plus/boards/nice_nano.overlay new file mode 100644 index 00000000..a8dafa2d --- /dev/null +++ b/app/boards/shields/romac_plus/boards/nice_nano.overlay @@ -0,0 +1,28 @@ +&spi1 { + compatible = "nordic,nrf-spi"; + status = "okay"; + mosi-pin = <6>; + // Unused pins, needed for SPI definition, but not used by the ws2812 driver itself. + sck-pin = <5>; + miso-pin = <7>; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + label = "WS2812"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <10>; /* arbitrary; change at will */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.conf b/app/boards/shields/romac_plus/romac_plus.conf new file mode 100644 index 00000000..8ec9fa98 --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.conf @@ -0,0 +1,3 @@ +# Uncomment to enable encoder +CONFIG_EC11=y +CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.dtsi b/app/boards/shields/romac_plus/romac_plus.dtsi new file mode 100644 index 00000000..3895f860 --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.dtsi @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <3>; + rows = <4>; + + map = < +RC(0,0) RC(0,1) RC(0,2) +RC(1,0) RC(1,1) RC(1,2) +RC(2,0) RC(2,1) RC(2,2) +RC(3,0) RC(3,1) RC(3,2) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro_d 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + left_encoder: encoder_left { + compatible = "alps,ec11"; + label = "LEFT_ENCODER"; + a-gpios = <&pro_micro_d 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + b-gpios = <&pro_micro_d 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_UP)>; + resolution = <4>; + status = "disabled"; + }; + + sensors { + compatible = "zmk,keymap-sensors"; + sensors = <&left_encoder>; + }; + + bt_unpair_combo: bt_unpair_combo { + compatible = "zmk,bt-unpair-combo"; + }; + + // TODO: per-key RGB node(s)? +}; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.keymap b/app/boards/shields/romac_plus/romac_plus.keymap new file mode 100644 index 00000000..77485dce --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.keymap @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Pete Johanson, Richard Jones + * + * SPDX-License-Identifier: MIT + */ + +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------- +// | 7 | 8 | 9 | +// | 4 | 5 | 6 | +// | 1 | 2 | 3 | +// | MO(1) | 0 | . | +// ---------------------- + bindings = < + &kp NUM_7 &kp NUM_8 &kp NUM_9 + &kp NUM_4 &kp NUM_5 &kp NUM_6 + &kp NUM_1 &kp NUM_2 &kp NUM_3 + &cp M_PLAY &kp NUM_0 &kp DOT + >; + + sensor-bindings = <&inc_dec_cp M_NEXT M_PREV>; + }; + + // nav_layer { +// ----------------------- +// | _ | HOME | PGUP | +// | _ | END | PGDN | +// | _ | _ | _ | +// | _ | _ | RET | +// ----------------------- + // bindings = < + // &trans &kp HOME &kp PGUP + // &trans &kp END &kp PGDN + // &trans &trans &trans .0 + // &trans &trans &kp RET + // >; + + // sensor-bindings = <&inc_dec_kp A B>; + // }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.overlay b/app/boards/shields/romac_plus/romac_plus.overlay new file mode 100644 index 00000000..23ef3e68 --- /dev/null +++ b/app/boards/shields/romac_plus/romac_plus.overlay @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Pete Johanson, Richard Jones + * + * SPDX-License-Identifier: MIT + */ + +#include "romac_plus.dtsi" + +/ { + chosen { + zmk,kscan = &kscan0; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + + col-gpios + = <&pro_micro_a 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 2 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 3 GPIO_ACTIVE_HIGH> + ; + + }; + + bt_unpair_combo: bt_unpair_combo { + compatible = "zmk,bt-unpair-combo"; + key-positions = <0 11>; + }; + +}; + +&left_encoder { + status = "okay"; +}; \ No newline at end of file From 551756b0ec7131e6129d31c0a28083d072d160a2 Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Mon, 21 Sep 2020 22:52:50 -0700 Subject: [PATCH 087/227] Add romac_plus to build.yml --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4a43f5d5..9af3d22b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,6 +19,7 @@ jobs: - iris_left - iris_right - romac + - romac_plus - settings_reset include: - board: proton_c From f1fd71c231ab75d2e2563d7b40cb1460dca0eed7 Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Wed, 23 Sep 2020 12:39:06 -0700 Subject: [PATCH 088/227] Disabled ec11 since it's an optional configuration --- app/boards/shields/romac_plus/romac_plus.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/boards/shields/romac_plus/romac_plus.conf b/app/boards/shields/romac_plus/romac_plus.conf index 8ec9fa98..cff5b30c 100644 --- a/app/boards/shields/romac_plus/romac_plus.conf +++ b/app/boards/shields/romac_plus/romac_plus.conf @@ -1,3 +1,3 @@ # Uncomment to enable encoder -CONFIG_EC11=y -CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file +#CONFIG_EC11=y +#CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file From 31af9646e6d1316cd960d8cff98c524c2f25934a Mon Sep 17 00:00:00 2001 From: Jason Chestnut Date: Wed, 23 Sep 2020 16:05:29 -0400 Subject: [PATCH 089/227] Adding kconfig flag for enabling matrix polling (vs interrupts) on the matrix gpio driver. --- app/drivers/zephyr/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/drivers/zephyr/Kconfig b/app/drivers/zephyr/Kconfig index 0237846a..a5b6d20c 100644 --- a/app/drivers/zephyr/Kconfig +++ b/app/drivers/zephyr/Kconfig @@ -9,6 +9,10 @@ config ZMK_KSCAN_GPIO_POLLING bool "Poll for key event triggers instead of using interrupts" default n +config ZMK_KSCAN_GPIO_MATRIX_POLLING + bool "Poll for key event triggers instead of using interrupts on matrix boards." + default n + endif config ZMK_KSCAN_INIT_PRIORITY From 4c092044ce22f0c60c3bf0ef860ecc543328d5bf Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Wed, 23 Sep 2020 16:21:42 -0700 Subject: [PATCH 090/227] Adopt single authors headers --- app/boards/shields/romac_plus/Kconfig.defconfig | 2 +- app/boards/shields/romac_plus/Kconfig.shield | 2 +- app/boards/shields/romac_plus/romac_plus.conf | 3 +++ app/boards/shields/romac_plus/romac_plus.dtsi | 2 +- app/boards/shields/romac_plus/romac_plus.keymap | 2 +- app/boards/shields/romac_plus/romac_plus.overlay | 2 +- 6 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/boards/shields/romac_plus/Kconfig.defconfig b/app/boards/shields/romac_plus/Kconfig.defconfig index 45b15b8d..1d04082c 100644 --- a/app/boards/shields/romac_plus/Kconfig.defconfig +++ b/app/boards/shields/romac_plus/Kconfig.defconfig @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Pete Johanson, Richard Jones +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT if SHIELD_ROMAC_PLUS diff --git a/app/boards/shields/romac_plus/Kconfig.shield b/app/boards/shields/romac_plus/Kconfig.shield index c89ef023..a7c7c614 100644 --- a/app/boards/shields/romac_plus/Kconfig.shield +++ b/app/boards/shields/romac_plus/Kconfig.shield @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Pete Johanson, Richard Jones +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT config SHIELD_ROMAC_PLUS diff --git a/app/boards/shields/romac_plus/romac_plus.conf b/app/boards/shields/romac_plus/romac_plus.conf index cff5b30c..d784dc48 100644 --- a/app/boards/shields/romac_plus/romac_plus.conf +++ b/app/boards/shields/romac_plus/romac_plus.conf @@ -1,3 +1,6 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + # Uncomment to enable encoder #CONFIG_EC11=y #CONFIG_EC11_TRIGGER_GLOBAL_THREAD=y \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.dtsi b/app/boards/shields/romac_plus/romac_plus.dtsi index 3895f860..be056185 100644 --- a/app/boards/shields/romac_plus/romac_plus.dtsi +++ b/app/boards/shields/romac_plus/romac_plus.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/shields/romac_plus/romac_plus.keymap b/app/boards/shields/romac_plus/romac_plus.keymap index 77485dce..947b20a9 100644 --- a/app/boards/shields/romac_plus/romac_plus.keymap +++ b/app/boards/shields/romac_plus/romac_plus.keymap @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson, Richard Jones + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/shields/romac_plus/romac_plus.overlay b/app/boards/shields/romac_plus/romac_plus.overlay index 23ef3e68..7b570015 100644 --- a/app/boards/shields/romac_plus/romac_plus.overlay +++ b/app/boards/shields/romac_plus/romac_plus.overlay @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson, Richard Jones + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ From 0ce36865b2026c8739c01cebd3031180aa0f3b1f Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Wed, 23 Sep 2020 16:23:54 -0700 Subject: [PATCH 091/227] Update keyboard name to be more user friendly --- app/boards/shields/romac_plus/Kconfig.defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/boards/shields/romac_plus/Kconfig.defconfig b/app/boards/shields/romac_plus/Kconfig.defconfig index 1d04082c..c4efdb97 100644 --- a/app/boards/shields/romac_plus/Kconfig.defconfig +++ b/app/boards/shields/romac_plus/Kconfig.defconfig @@ -4,6 +4,6 @@ if SHIELD_ROMAC_PLUS config ZMK_KEYBOARD_NAME - default "RoMac_plus-v4" + default "RoMac+ v4" endif \ No newline at end of file From 9fffebd5dac13d0a57f6f6aaff0654a2bd0986c1 Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Wed, 23 Sep 2020 16:31:02 -0700 Subject: [PATCH 092/227] Adopt new BT unpairing standards --- app/boards/shields/romac_plus/romac_plus.dtsi | 3 --- app/boards/shields/romac_plus/romac_plus.keymap | 5 +++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/boards/shields/romac_plus/romac_plus.dtsi b/app/boards/shields/romac_plus/romac_plus.dtsi index be056185..d04b2142 100644 --- a/app/boards/shields/romac_plus/romac_plus.dtsi +++ b/app/boards/shields/romac_plus/romac_plus.dtsi @@ -53,9 +53,6 @@ RC(3,0) RC(3,1) RC(3,2) sensors = <&left_encoder>; }; - bt_unpair_combo: bt_unpair_combo { - compatible = "zmk,bt-unpair-combo"; - }; // TODO: per-key RGB node(s)? }; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.keymap b/app/boards/shields/romac_plus/romac_plus.keymap index 947b20a9..3fa9441b 100644 --- a/app/boards/shields/romac_plus/romac_plus.keymap +++ b/app/boards/shields/romac_plus/romac_plus.keymap @@ -5,6 +5,7 @@ */ #include +#include #include / { @@ -30,13 +31,13 @@ // nav_layer { // ----------------------- -// | _ | HOME | PGUP | +// | BT_CLR | HOME | PGUP | // | _ | END | PGDN | // | _ | _ | _ | // | _ | _ | RET | // ----------------------- // bindings = < - // &trans &kp HOME &kp PGUP + // &bt BT_CLR &kp HOME &kp PGUP // &trans &kp END &kp PGDN // &trans &trans &trans .0 // &trans &trans &kp RET From 641524b1b9564fd2b433b9bc430736fb3205a3c5 Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Wed, 23 Sep 2020 16:37:46 -0700 Subject: [PATCH 093/227] Update Keymap legends for consistency --- app/boards/shields/romac_plus/romac_plus.dtsi | 2 - .../shields/romac_plus/romac_plus.keymap | 44 +++++++++---------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/app/boards/shields/romac_plus/romac_plus.dtsi b/app/boards/shields/romac_plus/romac_plus.dtsi index d04b2142..9b148ca0 100644 --- a/app/boards/shields/romac_plus/romac_plus.dtsi +++ b/app/boards/shields/romac_plus/romac_plus.dtsi @@ -36,7 +36,6 @@ RC(3,0) RC(3,1) RC(3,2) , <&pro_micro_d 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> , <&pro_micro_d 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> ; - }; left_encoder: encoder_left { @@ -52,7 +51,6 @@ RC(3,0) RC(3,1) RC(3,2) compatible = "zmk,keymap-sensors"; sensors = <&left_encoder>; }; - // TODO: per-key RGB node(s)? }; \ No newline at end of file diff --git a/app/boards/shields/romac_plus/romac_plus.keymap b/app/boards/shields/romac_plus/romac_plus.keymap index 3fa9441b..d8d1f787 100644 --- a/app/boards/shields/romac_plus/romac_plus.keymap +++ b/app/boards/shields/romac_plus/romac_plus.keymap @@ -13,37 +13,37 @@ compatible = "zmk,keymap"; default_layer { -// ------------------- -// | 7 | 8 | 9 | -// | 4 | 5 | 6 | -// | 1 | 2 | 3 | -// | MO(1) | 0 | . | -// ---------------------- +// -------------------------- +// | 7 | 8 | 9 | +// | 4 | 5 | 6 | +// | 1 | 2 | 3 | +// | M_PLAY | 0 | MO(1) | +// -------------------------- bindings = < &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_1 &kp NUM_2 &kp NUM_3 - &cp M_PLAY &kp NUM_0 &kp DOT + &cp M_PLAY &kp NUM_0 &mo 1 >; sensor-bindings = <&inc_dec_cp M_NEXT M_PREV>; }; - // nav_layer { -// ----------------------- -// | BT_CLR | HOME | PGUP | -// | _ | END | PGDN | -// | _ | _ | _ | -// | _ | _ | RET | -// ----------------------- - // bindings = < - // &bt BT_CLR &kp HOME &kp PGUP - // &trans &kp END &kp PGDN - // &trans &trans &trans .0 - // &trans &trans &kp RET - // >; + nav_layer { +// -------------------------- +// | BT_CLR | HOME | PGUP | +// | _ | END | PGDN | +// | _ | _ | _ | +// | _ | _ | _ | +// -------------------------- + bindings = < + &bt BT_CLR &kp HOME &kp PGUP + &trans &kp END &kp PGDN + &trans &trans &trans + &trans &trans &trans + >; - // sensor-bindings = <&inc_dec_kp A B>; - // }; + sensor-bindings = <&inc_dec_kp A B>; + }; }; }; \ No newline at end of file From 8e92ae30893e620ca1c615637a3bcf3f05088225 Mon Sep 17 00:00:00 2001 From: Kristoffer Onias Date: Wed, 23 Sep 2020 17:49:13 -0700 Subject: [PATCH 094/227] Remove bt_unpair_combo from romac_plus.overlay --- app/boards/shields/romac_plus/romac_plus.overlay | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/boards/shields/romac_plus/romac_plus.overlay b/app/boards/shields/romac_plus/romac_plus.overlay index 7b570015..86430349 100644 --- a/app/boards/shields/romac_plus/romac_plus.overlay +++ b/app/boards/shields/romac_plus/romac_plus.overlay @@ -22,12 +22,6 @@ , <&pro_micro_a 2 GPIO_ACTIVE_HIGH> , <&pro_micro_a 3 GPIO_ACTIVE_HIGH> ; - - }; - - bt_unpair_combo: bt_unpair_combo { - compatible = "zmk,bt-unpair-combo"; - key-positions = <0 11>; }; }; From 53425aa3c4719908eb8e6ed23057188f4e502237 Mon Sep 17 00:00:00 2001 From: Jason Chestnut Date: Thu, 24 Sep 2020 07:55:32 -0400 Subject: [PATCH 095/227] Rename kscan direct wired driver polling kscan flag in preparationfor addition of new matrix driver flag that enables polling. --- app/drivers/zephyr/Kconfig | 4 ++-- app/drivers/zephyr/kscan_gpio_direct.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/drivers/zephyr/Kconfig b/app/drivers/zephyr/Kconfig index a5b6d20c..0bf6c0a6 100644 --- a/app/drivers/zephyr/Kconfig +++ b/app/drivers/zephyr/Kconfig @@ -5,11 +5,11 @@ config ZMK_KSCAN_GPIO_DRIVER if ZMK_KSCAN_GPIO_DRIVER -config ZMK_KSCAN_GPIO_POLLING +config ZMK_KSCAN_MATRIX_POLLING bool "Poll for key event triggers instead of using interrupts" default n -config ZMK_KSCAN_GPIO_MATRIX_POLLING +config ZMK_KSCAN_DIRECT_POLLING bool "Poll for key event triggers instead of using interrupts on matrix boards." default n diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c index 1e5ab59e..7ba3399b 100644 --- a/app/drivers/zephyr/kscan_gpio_direct.c +++ b/app/drivers/zephyr/kscan_gpio_direct.c @@ -33,9 +33,9 @@ struct kscan_gpio_config { }; struct kscan_gpio_data { -#if defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) +#if defined(ZMK_KSCAN_DIRECT_POLLING) struct k_timer poll_timer; -#endif /* defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ +#endif /* defined(ZMK_KSCAN_DIRECT_POLLING) */ kscan_callback_t callback; union work_reference work; struct device *dev; @@ -53,7 +53,7 @@ static const struct kscan_gpio_item_config *kscan_gpio_input_configs(struct devi return cfg->inputs; } -#if !defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) +#if !defined(ZMK_KSCAN_DIRECT_POLLING) struct kscan_gpio_irq_callback { union work_reference *work; @@ -101,7 +101,7 @@ static void kscan_gpio_irq_callback_handler(struct device *dev, struct gpio_call } } -#else /* !defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ +#else /* !defined(ZMK_KSCAN_DIRECT_POLLING) */ static void kscan_gpio_timer_handler(struct k_timer *timer) { struct kscan_gpio_data *data = CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer); @@ -120,7 +120,7 @@ static int kscan_gpio_direct_disable(struct device *dev) { return 0; } -#endif /* defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ +#endif /* defined(ZMK_KSCAN_DIRECT_POLLING) */ static int kscan_gpio_direct_configure(struct device *dev, kscan_callback_t callback) { struct kscan_gpio_data *data = dev->driver_data; @@ -173,7 +173,7 @@ static const struct kscan_driver_api gpio_driver_api = { #define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios) #define GPIO_INST_INIT(n) \ - COND_CODE_0(CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + COND_CODE_0(ZMK_KSCAN_DIRECT_POLLING, \ (static struct kscan_gpio_irq_callback irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \ static struct kscan_gpio_data kscan_gpio_data_##n = { \ .inputs = {[INST_INPUT_LEN(n) - 1] = NULL}}; \ @@ -195,7 +195,7 @@ static const struct kscan_driver_api gpio_driver_api = { return err; \ } \ COND_CODE_0( \ - CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + ZMK_KSCAN_DIRECT_POLLING, \ (irq_callbacks_##n[i].work = &data->work; \ irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ @@ -208,7 +208,7 @@ static const struct kscan_driver_api gpio_driver_api = { ()) \ } \ data->dev = dev; \ - COND_CODE_1(CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + COND_CODE_1(ZMK_KSCAN_DIRECT_POLLING, \ (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ if (cfg->debounce_period > 0) { \ k_delayed_work_init(&data->work.delayed, kscan_gpio_work_handler); \ @@ -227,4 +227,4 @@ static const struct kscan_driver_api gpio_driver_api = { DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT) -#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ \ No newline at end of file +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ From cd194dbac4747126f017ce6e9ddf070ca6cc1fef Mon Sep 17 00:00:00 2001 From: CrossR Date: Thu, 24 Sep 2020 17:42:34 +0100 Subject: [PATCH 096/227] Add licenses. --- docs/static/setup.ps1 | 8 ++++++-- docs/static/setup.sh | 19 ++++++++++++------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index a2d66eec..3946e66c 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -1,3 +1,7 @@ +# Copyright (c) 2020 The ZMK Contributors +# +# SPDX-License-Identifier: MIT + $ErrorActionPreference = "Stop" function Get-Choice-From-Options { @@ -10,7 +14,7 @@ function Get-Choice-From-Options { for ($i = 0; $i -lt $Options.length; $i++) { Write-Host "$($i + 1)) $($Options[$i])" } - + Write-Host "$($Options.length + 1)) Quit" $selection = Read-Host $Prompt @@ -103,7 +107,7 @@ if ($github_user -ne "") { } $github_repo = Read-Host "GitHub Repo [https://github.com/$github_user/$repo_name.git]" - + if ($github_repo -eq "") { $github_repo = "https://github.com/$github_user/$repo_name.git" } diff --git a/docs/static/setup.sh b/docs/static/setup.sh index df985a67..5bf36451 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -1,11 +1,15 @@ #!/bin/bash +# Copyright (c) 2020 The ZMK Contributors +# +# SPDX-License-Identifier: MIT + set -e check_exists() { command_to_run=$1 error_message=$2 - + if ! eval "$command_to_run" &> /dev/null; then printf "%s\n" "$error_message" exit 1 @@ -28,7 +32,7 @@ echo "$title" echo "" echo "MCU Board Selection:" PS3="$prompt " -select opt in "${options[@]}" "Quit"; do +select opt in "${options[@]}" "Quit"; do case "$REPLY" in @@ -50,8 +54,8 @@ options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac") PS3="$prompt " # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. -# select opt in "${options[@]}" "Other" "Quit"; do -select opt in "${options[@]}" "Quit"; do +# select opt in "${options[@]}" "Other" "Quit"; do +select opt in "${options[@]}" "Quit"; do case "$REPLY" in @@ -64,7 +68,7 @@ select opt in "${options[@]}" "Quit"; do 7 ) shield_title="RoMac" shield="romac"; split="n"; break;; # Add link to docs on adding your own custom shield in your ZMK config! - # $(( ${#options[@]}+1 )) ) echo "Other!"; break;; + # $(( ${#options[@]}+1 )) ) echo "Other!"; break;; $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;; *) echo "Invalid option. Try another one.";continue;; @@ -148,9 +152,10 @@ git commit -m "Initial User Config." if [ -n "$github_repo" ]; then git remote add origin "$github_repo" git push --set-upstream origin "$(git symbolic-ref --short HEAD)" + push_return_code=$? # If push failed, assume that the origin was incorrect and give instructions on fixing. - if [ $? -ne 0 ] { + if [ ${push_return_code} -ne 0 ]; then echo "Remote repository $github_repo not found..." echo "Check GitHub URL, and try adding again." echo "Run the following: " @@ -159,7 +164,7 @@ if [ -n "$github_repo" ]; then echo " git push --set-upstream origin $(git symbolic-ref --short HEAD)" echo "Once pushed, your firmware should be availalbe from GitHub Actions at: ${github_repo%.git}/actions" exit 1 - } + fi # TODO: Support determing the actions URL when non-https:// repo URL is used. if [ "${github_repo}" != "${github_repo#https://}" ]; then From 5c4705d465d4b5f742299cf77f549186c9cc7933 Mon Sep 17 00:00:00 2001 From: Jason Chestnut Date: Thu, 24 Sep 2020 14:30:47 -0400 Subject: [PATCH 097/227] Add new matrix scan flag and implementation in the gpio matrix driver. --- app/boards/arm/planck/Kconfig.defconfig | 3 + .../clueboard_california/Kconfig.defconfig | 2 +- app/drivers/zephyr/Kconfig | 6 +- app/drivers/zephyr/kscan_gpio_matrix.c | 133 ++++++++++++------ 4 files changed, 95 insertions(+), 49 deletions(-) diff --git a/app/boards/arm/planck/Kconfig.defconfig b/app/boards/arm/planck/Kconfig.defconfig index 6f5bf525..913c1c13 100644 --- a/app/boards/arm/planck/Kconfig.defconfig +++ b/app/boards/arm/planck/Kconfig.defconfig @@ -11,4 +11,7 @@ config ZMK_KEYBOARD_NAME config ZMK_USB default y +config ZMK_KSCAN_MATRIX_POLLING + default y + endif # BOARD_PLANCK_REV6 diff --git a/app/boards/shields/clueboard_california/Kconfig.defconfig b/app/boards/shields/clueboard_california/Kconfig.defconfig index 2408f9ff..e101ea76 100644 --- a/app/boards/shields/clueboard_california/Kconfig.defconfig +++ b/app/boards/shields/clueboard_california/Kconfig.defconfig @@ -8,7 +8,7 @@ config ZMK_KEYBOARD_NAME # across A & B controllers, and STM32F303CCT6 can't enable # interrutps for multiple controllers for the same "line" # for the external interrupts. -config ZMK_KSCAN_GPIO_POLLING +config ZMK_KSCAN_DIRECT_POLLING default y endif diff --git a/app/drivers/zephyr/Kconfig b/app/drivers/zephyr/Kconfig index 0bf6c0a6..c5ff3a66 100644 --- a/app/drivers/zephyr/Kconfig +++ b/app/drivers/zephyr/Kconfig @@ -6,11 +6,11 @@ config ZMK_KSCAN_GPIO_DRIVER if ZMK_KSCAN_GPIO_DRIVER config ZMK_KSCAN_MATRIX_POLLING - bool "Poll for key event triggers instead of using interrupts" - default n + bool "Poll for key event triggers instead of using interrupts on matrix boards." + default y config ZMK_KSCAN_DIRECT_POLLING - bool "Poll for key event triggers instead of using interrupts on matrix boards." + bool "Poll for key event triggers instead of using interrupts on direct wired boards." default n endif diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index 634f694c..46616ff5 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -31,6 +31,8 @@ struct kscan_gpio_item_config { #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) +#if !defined(ZMK_KSCAN_MATRIX_POLLING) +/* Set up for interrupt-based input. */ static int kscan_gpio_config_interrupts(struct device **devices, const struct kscan_gpio_item_config *configs, size_t len, gpio_flags_t flags) { @@ -48,6 +50,61 @@ static int kscan_gpio_config_interrupts(struct device **devices, return 0; } + +#define KSCAN_GPIO_MATRIX_ENABLE(n) \ +static int kscan_gpio_matrix_enable(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ + GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ +} \ + +#define KSCAN_GPIO_MATRIX_DISABLE(n) \ +static int kscan_gpio_matrix_disable(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ + GPIO_INT_DISABLE); \ +} \ + +#define KSCAN_GPIO_CALLBACK_HANDLER(n) \ +static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \ + gpio_port_pins_t pin) { \ + struct kscan_gpio_irq_callback_##n *data = \ + CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ + COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ + k_delayed_work_cancel(data->work); \ + k_delayed_work_submit(data->work, \ + K_MSEC(DT_INST_PROP(n, debounce_period))); \ + })) \ +} \ + +#else /* !defined(ZMK_KSCAN_MATRIX_POLLING) */ +/* Set up for matrix scanning. */ + +static void kscan_gpio_timer_handler(struct k_timer *timer) { + struct kscan_gpio_data *data = CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer); + + k_work_submit(&data->work.direct); +} + +#define KSCAN_GPIO_MATRIX_ENABLE(n) \ +static int kscan_gpio_matrix_enable(struct device *dev) { \ + struct kscan_gpio_data *data = dev->driver_data; \ + k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \ + return 0; \ +} \ + +#define KSCAN_GPIO_MATRIX_DISABLE(n) \ +static int kscan_gpio_matrix_disable(struct device *dev) { \ + struct kscan_gpio_data *data = dev->driver_data; \ + k_timer_stop(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \ + return 0; \ +} \ + +#define KSCAN_GPIO_MATRIX_ENABLE(n) \ + + +#endif /* !defined(ZMK_KSCAN_MATRIX_POLLING) */ + #define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios) #define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios) #define INST_OUTPUT_LEN(n) \ @@ -58,17 +115,22 @@ static int kscan_gpio_config_interrupts(struct device **devices, (INST_MATRIX_ROWS(n))) #define GPIO_INST_INIT(n) \ - struct kscan_gpio_irq_callback_##n { \ - struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \ - struct gpio_callback callback; \ - }; \ - static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)]; \ + COND_CODE_0( \ + ZMK_KSCAN_MATRIX_POLLING, \ + (struct kscan_gpio_irq_callback_##n { \ + struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \ + struct gpio_callback callback; \ + }; \ + static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)]; \ + KSCAN_GPIO_ENTABLE_INTERRUPTS(n)), \ + ()) \ struct kscan_gpio_config_##n { \ struct kscan_gpio_item_config rows[INST_MATRIX_ROWS(n)]; \ struct kscan_gpio_item_config cols[INST_MATRIX_COLS(n)]; \ }; \ struct kscan_gpio_data_##n { \ - kscan_callback_t callback; \ + COND_CODE_1(ZMK_KSCAN_MATRIX_POLLING, \ + (struct k_timer poll_timer;),(kscan_callback_t callback;)) \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \ @@ -96,16 +158,6 @@ static int kscan_gpio_config_interrupts(struct device **devices, return ( \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ } \ - static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ - kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ - } \ - static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ - kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DISABLE); \ - } \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ @@ -128,7 +180,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, /* Disable our interrupts temporarily while we scan, to avoid */ \ /* re-entry while we iterate columns and set them active one by one */ \ /* to get pressed state for each matrix cell. */ \ - kscan_gpio_disable_interrupts_##n(dev); \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_disable_interrupts_##n(dev);), ()) \ kscan_gpio_set_output_state_##n(dev, 0); \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ @@ -146,7 +198,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, /* Set all our outputs as active again, then re-enable interrupts, */ \ /* so we can trigger interrupts again for future press/release */ \ kscan_gpio_set_output_state_##n(dev, 1); \ - kscan_gpio_enable_interrupts_##n(dev); \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_enable_interrupts_##n(dev);), ()) \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ bool pressed = read_state[r][c]; \ @@ -172,16 +224,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ kscan_gpio_read_##n(data->dev); \ } \ - static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \ - gpio_port_pins_t pin) { \ - struct kscan_gpio_irq_callback_##n *data = \ - CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ - COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ - k_delayed_work_cancel(data->work); \ - k_delayed_work_submit(data->work, \ - K_MSEC(DT_INST_PROP(n, debounce_period))); \ - })) \ - } \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (KSCAN_GPIO_CALLBACK_HANDLER(n)), ()) \ static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \ .rows = {[INST_MATRIX_ROWS(n) - 1] = NULL}, .cols = {[INST_MATRIX_COLS(n) - 1] = NULL}}; \ static int kscan_gpio_configure_##n(struct device *dev, kscan_callback_t callback) { \ @@ -192,13 +235,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, data->callback = callback; \ return 0; \ }; \ - static int kscan_gpio_enable_##n(struct device *dev) { \ - int err = kscan_gpio_enable_interrupts_##n(dev); \ - if (err) { \ - return err; \ - } \ - return kscan_gpio_read_##n(dev); \ - }; \ + KSCAN_GPIO_MATRIX_ENABLE(n) \ + KSCAN_GPIO_MATRIX_DISABLE(n) \ static int kscan_gpio_init_##n(struct device *dev) { \ struct kscan_gpio_data_##n *data = dev->driver_data; \ int err; \ @@ -215,16 +253,21 @@ static int kscan_gpio_config_interrupts(struct device **devices, LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ return err; \ } \ - irq_callbacks_##n[i].work = &data->work; \ - gpio_init_callback(&irq_callbacks_##n[i].callback, \ - kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \ - err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ - if (err) { \ - LOG_ERR("Error adding the callback to the column device"); \ - return err; \ - } \ + COND_CODE_0( \ + ZMK_KSCAN_MATRIX_POLLING, \ + (irq_callbacks_##n[i].work = &data->work; \ + gpio_init_callback(&irq_callbacks_##n[i].callback, \ + kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \ + err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ + if (err) { \ + LOG_ERR("Error adding the callback to the column device"); \ + return err; \ + }), \ + ()) \ } \ struct device **output_devices = kscan_gpio_output_devices_##n(dev); \ + COND_CODE_1(ZMK_KSCAN_MATRIX_POLLING, \ + (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \ output_devices[o] = device_get_binding(out_cfg->label); \ @@ -247,8 +290,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ static const struct kscan_driver_api gpio_driver_api_##n = { \ .config = kscan_gpio_configure_##n, \ - .enable_callback = kscan_gpio_enable_##n, \ - .disable_callback = kscan_gpio_disable_interrupts_##n, \ + .enable_callback = kscan_gpio_matrix_enable, \ + .disable_callback = kscan_gpio_matrix_disable, \ }; \ static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ .rows = {UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n)}, \ From d5ec32612d9a1d1bf07674fe4b01a926c727ba99 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 24 Sep 2020 14:34:38 -0400 Subject: [PATCH 098/227] feat(docs): Add missing shields to hardware page. --- docs/docs/hardware.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/docs/hardware.md b/docs/docs/hardware.md index 299d1f5c..236aa972 100644 --- a/docs/docs/hardware.md +++ b/docs/docs/hardware.md @@ -26,6 +26,11 @@ That being said, there are currently only a few specific [boards](/docs/faq#what - [Kyria](https://splitkb.com/products/kyria-pcb-kit) (`kyria_left` and `kyria_right`) - [Corne](https://github.com/foostan/crkbd) (`corne_left` and `corne_right`) - [Lily58](https://github.com/kata0510/Lily58) (`lily58_left` and `lily58_right`) +- [Sofle](https://github.com/josefadamcik/SofleKeyboard) (`sofle_left` and `sofle_right`) +- [Splitreus62](https://github.com/Na-Cly/splitreus62) (`splitreus62_left` and `splitreus62_right`) +- [RoMac+ v4](https://www.littlekeyboards.com/products/romac) (`romac_plus`) +- [RoMac v2](https://mechboards.co.uk/shop/kits/romac-macro-pad/) (`romac') +- [QAZ](https://www.cbkbd.com/product/qaz-keyboard-kit) (`qaz`) ## Other Hardware From 966830562182bca5645ec5c7f44c1e7390408bdd Mon Sep 17 00:00:00 2001 From: Jason Chestnut Date: Thu, 24 Sep 2020 17:35:51 -0400 Subject: [PATCH 099/227] Restore original matrix driver to correct implementation errors. --- app/drivers/zephyr/kscan_gpio_matrix.c | 133 +++++++++---------------- 1 file changed, 45 insertions(+), 88 deletions(-) diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index 46616ff5..634f694c 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -31,8 +31,6 @@ struct kscan_gpio_item_config { #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) -#if !defined(ZMK_KSCAN_MATRIX_POLLING) -/* Set up for interrupt-based input. */ static int kscan_gpio_config_interrupts(struct device **devices, const struct kscan_gpio_item_config *configs, size_t len, gpio_flags_t flags) { @@ -50,61 +48,6 @@ static int kscan_gpio_config_interrupts(struct device **devices, return 0; } - -#define KSCAN_GPIO_MATRIX_ENABLE(n) \ -static int kscan_gpio_matrix_enable(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ - kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ -} \ - -#define KSCAN_GPIO_MATRIX_DISABLE(n) \ -static int kscan_gpio_matrix_disable(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ - kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DISABLE); \ -} \ - -#define KSCAN_GPIO_CALLBACK_HANDLER(n) \ -static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \ - gpio_port_pins_t pin) { \ - struct kscan_gpio_irq_callback_##n *data = \ - CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ - COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ - k_delayed_work_cancel(data->work); \ - k_delayed_work_submit(data->work, \ - K_MSEC(DT_INST_PROP(n, debounce_period))); \ - })) \ -} \ - -#else /* !defined(ZMK_KSCAN_MATRIX_POLLING) */ -/* Set up for matrix scanning. */ - -static void kscan_gpio_timer_handler(struct k_timer *timer) { - struct kscan_gpio_data *data = CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer); - - k_work_submit(&data->work.direct); -} - -#define KSCAN_GPIO_MATRIX_ENABLE(n) \ -static int kscan_gpio_matrix_enable(struct device *dev) { \ - struct kscan_gpio_data *data = dev->driver_data; \ - k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \ - return 0; \ -} \ - -#define KSCAN_GPIO_MATRIX_DISABLE(n) \ -static int kscan_gpio_matrix_disable(struct device *dev) { \ - struct kscan_gpio_data *data = dev->driver_data; \ - k_timer_stop(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \ - return 0; \ -} \ - -#define KSCAN_GPIO_MATRIX_ENABLE(n) \ - - -#endif /* !defined(ZMK_KSCAN_MATRIX_POLLING) */ - #define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios) #define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios) #define INST_OUTPUT_LEN(n) \ @@ -115,22 +58,17 @@ static int kscan_gpio_matrix_disable(struct device *dev) { (INST_MATRIX_ROWS(n))) #define GPIO_INST_INIT(n) \ - COND_CODE_0( \ - ZMK_KSCAN_MATRIX_POLLING, \ - (struct kscan_gpio_irq_callback_##n { \ - struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \ - struct gpio_callback callback; \ - }; \ - static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)]; \ - KSCAN_GPIO_ENTABLE_INTERRUPTS(n)), \ - ()) \ + struct kscan_gpio_irq_callback_##n { \ + struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \ + struct gpio_callback callback; \ + }; \ + static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)]; \ struct kscan_gpio_config_##n { \ struct kscan_gpio_item_config rows[INST_MATRIX_ROWS(n)]; \ struct kscan_gpio_item_config cols[INST_MATRIX_COLS(n)]; \ }; \ struct kscan_gpio_data_##n { \ - COND_CODE_1(ZMK_KSCAN_MATRIX_POLLING, \ - (struct k_timer poll_timer;),(kscan_callback_t callback;)) \ + kscan_callback_t callback; \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \ @@ -158,6 +96,16 @@ static int kscan_gpio_matrix_disable(struct device *dev) { return ( \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ } \ + static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ + GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ + } \ + static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ + GPIO_INT_DISABLE); \ + } \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ @@ -180,7 +128,7 @@ static int kscan_gpio_matrix_disable(struct device *dev) { /* Disable our interrupts temporarily while we scan, to avoid */ \ /* re-entry while we iterate columns and set them active one by one */ \ /* to get pressed state for each matrix cell. */ \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_disable_interrupts_##n(dev);), ()) \ + kscan_gpio_disable_interrupts_##n(dev); \ kscan_gpio_set_output_state_##n(dev, 0); \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ @@ -198,7 +146,7 @@ static int kscan_gpio_matrix_disable(struct device *dev) { /* Set all our outputs as active again, then re-enable interrupts, */ \ /* so we can trigger interrupts again for future press/release */ \ kscan_gpio_set_output_state_##n(dev, 1); \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_enable_interrupts_##n(dev);), ()) \ + kscan_gpio_enable_interrupts_##n(dev); \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ bool pressed = read_state[r][c]; \ @@ -224,7 +172,16 @@ static int kscan_gpio_matrix_disable(struct device *dev) { struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ kscan_gpio_read_##n(data->dev); \ } \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (KSCAN_GPIO_CALLBACK_HANDLER(n)), ()) \ + static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \ + gpio_port_pins_t pin) { \ + struct kscan_gpio_irq_callback_##n *data = \ + CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ + COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ + k_delayed_work_cancel(data->work); \ + k_delayed_work_submit(data->work, \ + K_MSEC(DT_INST_PROP(n, debounce_period))); \ + })) \ + } \ static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \ .rows = {[INST_MATRIX_ROWS(n) - 1] = NULL}, .cols = {[INST_MATRIX_COLS(n) - 1] = NULL}}; \ static int kscan_gpio_configure_##n(struct device *dev, kscan_callback_t callback) { \ @@ -235,8 +192,13 @@ static int kscan_gpio_matrix_disable(struct device *dev) { data->callback = callback; \ return 0; \ }; \ - KSCAN_GPIO_MATRIX_ENABLE(n) \ - KSCAN_GPIO_MATRIX_DISABLE(n) \ + static int kscan_gpio_enable_##n(struct device *dev) { \ + int err = kscan_gpio_enable_interrupts_##n(dev); \ + if (err) { \ + return err; \ + } \ + return kscan_gpio_read_##n(dev); \ + }; \ static int kscan_gpio_init_##n(struct device *dev) { \ struct kscan_gpio_data_##n *data = dev->driver_data; \ int err; \ @@ -253,21 +215,16 @@ static int kscan_gpio_matrix_disable(struct device *dev) { LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ return err; \ } \ - COND_CODE_0( \ - ZMK_KSCAN_MATRIX_POLLING, \ - (irq_callbacks_##n[i].work = &data->work; \ - gpio_init_callback(&irq_callbacks_##n[i].callback, \ - kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \ - err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ - if (err) { \ - LOG_ERR("Error adding the callback to the column device"); \ - return err; \ - }), \ - ()) \ + irq_callbacks_##n[i].work = &data->work; \ + gpio_init_callback(&irq_callbacks_##n[i].callback, \ + kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \ + err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ + if (err) { \ + LOG_ERR("Error adding the callback to the column device"); \ + return err; \ + } \ } \ struct device **output_devices = kscan_gpio_output_devices_##n(dev); \ - COND_CODE_1(ZMK_KSCAN_MATRIX_POLLING, \ - (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \ output_devices[o] = device_get_binding(out_cfg->label); \ @@ -290,8 +247,8 @@ static int kscan_gpio_matrix_disable(struct device *dev) { } \ static const struct kscan_driver_api gpio_driver_api_##n = { \ .config = kscan_gpio_configure_##n, \ - .enable_callback = kscan_gpio_matrix_enable, \ - .disable_callback = kscan_gpio_matrix_disable, \ + .enable_callback = kscan_gpio_enable_##n, \ + .disable_callback = kscan_gpio_disable_interrupts_##n, \ }; \ static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ .rows = {UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n)}, \ From b1dce208f8accab56c7864e01cff70a88bc39b3f Mon Sep 17 00:00:00 2001 From: Jason Chestnut Date: Fri, 25 Sep 2020 11:29:21 -0400 Subject: [PATCH 100/227] Add matrix polling logic to matrix GPIO driver. --- app/drivers/zephyr/Kconfig | 2 +- app/drivers/zephyr/kscan_gpio_matrix.c | 65 +++++++++++++++++++------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/app/drivers/zephyr/Kconfig b/app/drivers/zephyr/Kconfig index c5ff3a66..0534cab2 100644 --- a/app/drivers/zephyr/Kconfig +++ b/app/drivers/zephyr/Kconfig @@ -7,7 +7,7 @@ if ZMK_KSCAN_GPIO_DRIVER config ZMK_KSCAN_MATRIX_POLLING bool "Poll for key event triggers instead of using interrupts on matrix boards." - default y + default n config ZMK_KSCAN_DIRECT_POLLING bool "Poll for key event triggers instead of using interrupts on direct wired boards." diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index 634f694c..8c6cabd8 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -31,7 +31,8 @@ struct kscan_gpio_item_config { #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) -static int kscan_gpio_config_interrupts(struct device **devices, +COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, +(static int kscan_gpio_config_interrupts(struct device **devices, const struct kscan_gpio_item_config *configs, size_t len, gpio_flags_t flags) { for (int i = 0; i < len; i++) { @@ -47,7 +48,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, } return 0; -} +}), ()) + #define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios) #define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios) #define INST_OUTPUT_LEN(n) \ @@ -69,6 +71,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, }; \ struct kscan_gpio_data_##n { \ kscan_callback_t callback; \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \ @@ -96,16 +99,17 @@ static int kscan_gpio_config_interrupts(struct device **devices, return ( \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ } \ - static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ - } \ - static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + } \ + static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ GPIO_INT_DISABLE); \ - } \ + }), ()) \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ @@ -128,7 +132,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, /* Disable our interrupts temporarily while we scan, to avoid */ \ /* re-entry while we iterate columns and set them active one by one */ \ /* to get pressed state for each matrix cell. */ \ - kscan_gpio_disable_interrupts_##n(dev); \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (kscan_gpio_disable_interrupts_##n(dev);),()) \ kscan_gpio_set_output_state_##n(dev, 0); \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ @@ -143,10 +148,11 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ gpio_pin_set(out_dev, out_cfg->pin, 0); \ } \ - /* Set all our outputs as active again, then re-enable interrupts, */ \ - /* so we can trigger interrupts again for future press/release */ \ + /* Set all our outputs as active again. */ \ kscan_gpio_set_output_state_##n(dev, 1); \ - kscan_gpio_enable_interrupts_##n(dev); \ + /*Re-enable interrupts so that they can be triggered again for future press/release*/ \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (kscan_gpio_enable_interrupts_##n(dev);), ()) \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ bool pressed = read_state[r][c]; \ @@ -190,15 +196,34 @@ static int kscan_gpio_config_interrupts(struct device **devices, return -EINVAL; \ } \ data->callback = callback; \ + LOG_DBG("Configured GPIO %d", n); \ return 0; \ }; \ static int kscan_gpio_enable_##n(struct device *dev) { \ - int err = kscan_gpio_enable_interrupts_##n(dev); \ - if (err) { \ - return err; \ - } \ - return kscan_gpio_read_##n(dev); \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (int err = kscan_gpio_enable_interrupts_##n(dev); \ + if (err) { \ + return err; \ + } \ + return kscan_gpio_read_##n(dev);), \ + (struct kscan_gpio_data_##n *data = dev->driver_data; \ + k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \ + return 0;)) \ }; \ + static int kscan_gpio_disable_##n(struct device *dev) { \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (return kscan_gpio_disable_interrupts_##n(dev);), \ + (struct kscan_gpio_data_##n *data = dev->driver_data; \ + k_timer_stop(&data->poll_timer); \ + return 0;)) \ + }; \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \ + (static void kscan_gpio_timer_handler(struct k_timer *timer) { \ + struct kscan_gpio_data_##n *data = \ + CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \ + k_work_submit(&data->work.work); \ + LOG_DBG("Submitted work in timer handler."); \ + })) \ static int kscan_gpio_init_##n(struct device *dev) { \ struct kscan_gpio_data_##n *data = dev->driver_data; \ int err; \ @@ -214,6 +239,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, if (err) { \ LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ return err; \ + } else { \ + LOG_DBG("Configured pin %d on %s for input", in_cfg->pin, in_cfg->label); \ } \ irq_callbacks_##n[i].work = &data->work; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ @@ -241,6 +268,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ } \ data->dev = dev; \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \ + (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);)) \ (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \ &data->work, kscan_gpio_work_handler_##n); \ return 0; \ @@ -248,7 +277,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, static const struct kscan_driver_api gpio_driver_api_##n = { \ .config = kscan_gpio_configure_##n, \ .enable_callback = kscan_gpio_enable_##n, \ - .disable_callback = kscan_gpio_disable_interrupts_##n, \ + .disable_callback = kscan_gpio_disable_##n, \ }; \ static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ .rows = {UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n)}, \ From cca8337f0562afbfb11de5af92ba5dc3c9334991 Mon Sep 17 00:00:00 2001 From: Jason Chestnut Date: Wed, 23 Sep 2020 16:05:29 -0400 Subject: [PATCH 101/227] Add support to GPIO matrix driver for matrix polling, rather than interrupt-based IO. - Add ZMK_KSCAN_MATRIX_POLLING config flag to Kconfig - Update matrix driver code to use the above flag to conditionally add the handling code for polling operations. --- app/boards/arm/planck/Kconfig.defconfig | 3 + .../clueboard_california/Kconfig.defconfig | 2 +- app/drivers/zephyr/Kconfig | 8 ++- app/drivers/zephyr/kscan_gpio_direct.c | 18 +++--- app/drivers/zephyr/kscan_gpio_matrix.c | 63 +++++++++++++------ 5 files changed, 64 insertions(+), 30 deletions(-) diff --git a/app/boards/arm/planck/Kconfig.defconfig b/app/boards/arm/planck/Kconfig.defconfig index 6f5bf525..913c1c13 100644 --- a/app/boards/arm/planck/Kconfig.defconfig +++ b/app/boards/arm/planck/Kconfig.defconfig @@ -11,4 +11,7 @@ config ZMK_KEYBOARD_NAME config ZMK_USB default y +config ZMK_KSCAN_MATRIX_POLLING + default y + endif # BOARD_PLANCK_REV6 diff --git a/app/boards/shields/clueboard_california/Kconfig.defconfig b/app/boards/shields/clueboard_california/Kconfig.defconfig index 2408f9ff..e101ea76 100644 --- a/app/boards/shields/clueboard_california/Kconfig.defconfig +++ b/app/boards/shields/clueboard_california/Kconfig.defconfig @@ -8,7 +8,7 @@ config ZMK_KEYBOARD_NAME # across A & B controllers, and STM32F303CCT6 can't enable # interrutps for multiple controllers for the same "line" # for the external interrupts. -config ZMK_KSCAN_GPIO_POLLING +config ZMK_KSCAN_DIRECT_POLLING default y endif diff --git a/app/drivers/zephyr/Kconfig b/app/drivers/zephyr/Kconfig index 0237846a..0534cab2 100644 --- a/app/drivers/zephyr/Kconfig +++ b/app/drivers/zephyr/Kconfig @@ -5,10 +5,14 @@ config ZMK_KSCAN_GPIO_DRIVER if ZMK_KSCAN_GPIO_DRIVER -config ZMK_KSCAN_GPIO_POLLING - bool "Poll for key event triggers instead of using interrupts" +config ZMK_KSCAN_MATRIX_POLLING + bool "Poll for key event triggers instead of using interrupts on matrix boards." default n +config ZMK_KSCAN_DIRECT_POLLING + bool "Poll for key event triggers instead of using interrupts on direct wired boards." + default n + endif config ZMK_KSCAN_INIT_PRIORITY diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c index 1e5ab59e..7ba3399b 100644 --- a/app/drivers/zephyr/kscan_gpio_direct.c +++ b/app/drivers/zephyr/kscan_gpio_direct.c @@ -33,9 +33,9 @@ struct kscan_gpio_config { }; struct kscan_gpio_data { -#if defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) +#if defined(ZMK_KSCAN_DIRECT_POLLING) struct k_timer poll_timer; -#endif /* defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ +#endif /* defined(ZMK_KSCAN_DIRECT_POLLING) */ kscan_callback_t callback; union work_reference work; struct device *dev; @@ -53,7 +53,7 @@ static const struct kscan_gpio_item_config *kscan_gpio_input_configs(struct devi return cfg->inputs; } -#if !defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) +#if !defined(ZMK_KSCAN_DIRECT_POLLING) struct kscan_gpio_irq_callback { union work_reference *work; @@ -101,7 +101,7 @@ static void kscan_gpio_irq_callback_handler(struct device *dev, struct gpio_call } } -#else /* !defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ +#else /* !defined(ZMK_KSCAN_DIRECT_POLLING) */ static void kscan_gpio_timer_handler(struct k_timer *timer) { struct kscan_gpio_data *data = CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer); @@ -120,7 +120,7 @@ static int kscan_gpio_direct_disable(struct device *dev) { return 0; } -#endif /* defined(CONFIG_ZMK_KSCAN_GPIO_POLLING) */ +#endif /* defined(ZMK_KSCAN_DIRECT_POLLING) */ static int kscan_gpio_direct_configure(struct device *dev, kscan_callback_t callback) { struct kscan_gpio_data *data = dev->driver_data; @@ -173,7 +173,7 @@ static const struct kscan_driver_api gpio_driver_api = { #define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios) #define GPIO_INST_INIT(n) \ - COND_CODE_0(CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + COND_CODE_0(ZMK_KSCAN_DIRECT_POLLING, \ (static struct kscan_gpio_irq_callback irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \ static struct kscan_gpio_data kscan_gpio_data_##n = { \ .inputs = {[INST_INPUT_LEN(n) - 1] = NULL}}; \ @@ -195,7 +195,7 @@ static const struct kscan_driver_api gpio_driver_api = { return err; \ } \ COND_CODE_0( \ - CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + ZMK_KSCAN_DIRECT_POLLING, \ (irq_callbacks_##n[i].work = &data->work; \ irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ @@ -208,7 +208,7 @@ static const struct kscan_driver_api gpio_driver_api = { ()) \ } \ data->dev = dev; \ - COND_CODE_1(CONFIG_ZMK_KSCAN_GPIO_POLLING, \ + COND_CODE_1(ZMK_KSCAN_DIRECT_POLLING, \ (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ if (cfg->debounce_period > 0) { \ k_delayed_work_init(&data->work.delayed, kscan_gpio_work_handler); \ @@ -227,4 +227,4 @@ static const struct kscan_driver_api gpio_driver_api = { DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT) -#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ \ No newline at end of file +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index 634f694c..72709ba0 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -31,7 +31,8 @@ struct kscan_gpio_item_config { #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) -static int kscan_gpio_config_interrupts(struct device **devices, +COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, +(static int kscan_gpio_config_interrupts(struct device **devices, const struct kscan_gpio_item_config *configs, size_t len, gpio_flags_t flags) { for (int i = 0; i < len; i++) { @@ -47,7 +48,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, } return 0; -} +}), ()) + #define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios) #define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios) #define INST_OUTPUT_LEN(n) \ @@ -69,6 +71,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, }; \ struct kscan_gpio_data_##n { \ kscan_callback_t callback; \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \ @@ -96,16 +99,17 @@ static int kscan_gpio_config_interrupts(struct device **devices, return ( \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ } \ - static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ - } \ - static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + } \ + static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ GPIO_INT_DISABLE); \ - } \ + }), ()) \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ @@ -128,7 +132,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, /* Disable our interrupts temporarily while we scan, to avoid */ \ /* re-entry while we iterate columns and set them active one by one */ \ /* to get pressed state for each matrix cell. */ \ - kscan_gpio_disable_interrupts_##n(dev); \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (kscan_gpio_disable_interrupts_##n(dev);),()) \ kscan_gpio_set_output_state_##n(dev, 0); \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ @@ -143,10 +148,11 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ gpio_pin_set(out_dev, out_cfg->pin, 0); \ } \ - /* Set all our outputs as active again, then re-enable interrupts, */ \ - /* so we can trigger interrupts again for future press/release */ \ + /* Set all our outputs as active again. */ \ kscan_gpio_set_output_state_##n(dev, 1); \ - kscan_gpio_enable_interrupts_##n(dev); \ + /*Re-enable interrupts so that they can be triggered again for future press/release*/ \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (kscan_gpio_enable_interrupts_##n(dev);), ()) \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ bool pressed = read_state[r][c]; \ @@ -193,12 +199,29 @@ static int kscan_gpio_config_interrupts(struct device **devices, return 0; \ }; \ static int kscan_gpio_enable_##n(struct device *dev) { \ - int err = kscan_gpio_enable_interrupts_##n(dev); \ - if (err) { \ - return err; \ - } \ - return kscan_gpio_read_##n(dev); \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (int err = kscan_gpio_enable_interrupts_##n(dev); \ + if (err) { \ + return err; \ + } \ + return kscan_gpio_read_##n(dev);), \ + (struct kscan_gpio_data_##n *data = dev->driver_data; \ + k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \ + return 0;)) \ }; \ + static int kscan_gpio_disable_##n(struct device *dev) { \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + (return kscan_gpio_disable_interrupts_##n(dev);), \ + (struct kscan_gpio_data_##n *data = dev->driver_data; \ + k_timer_stop(&data->poll_timer); \ + return 0;)) \ + }; \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \ + (static void kscan_gpio_timer_handler(struct k_timer *timer) { \ + struct kscan_gpio_data_##n *data = \ + CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \ + k_work_submit(&data->work.work); \ + })) \ static int kscan_gpio_init_##n(struct device *dev) { \ struct kscan_gpio_data_##n *data = dev->driver_data; \ int err; \ @@ -214,6 +237,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, if (err) { \ LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \ return err; \ + } else { \ + LOG_DBG("Configured pin %d on %s for input", in_cfg->pin, in_cfg->label); \ } \ irq_callbacks_##n[i].work = &data->work; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ @@ -241,6 +266,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ } \ data->dev = dev; \ + COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \ + (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);)) \ (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \ &data->work, kscan_gpio_work_handler_##n); \ return 0; \ @@ -248,7 +275,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, static const struct kscan_driver_api gpio_driver_api_##n = { \ .config = kscan_gpio_configure_##n, \ .enable_callback = kscan_gpio_enable_##n, \ - .disable_callback = kscan_gpio_disable_interrupts_##n, \ + .disable_callback = kscan_gpio_disable_##n, \ }; \ static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \ .rows = {UTIL_LISTIFY(INST_MATRIX_ROWS(n), _KSCAN_GPIO_ROW_CFG_INIT, n)}, \ From 7f7c7037b04c78d8a3b74557197e0a2996eb980e Mon Sep 17 00:00:00 2001 From: Noah Thornton Date: Sat, 26 Sep 2020 11:59:12 -0700 Subject: [PATCH 102/227] Add quefrency shield --- .github/workflows/build.yml | 2 + .../shields/quefrency/Kconfig.defconfig | 17 +++++++ app/boards/shields/quefrency/Kconfig.shield | 8 +++ app/boards/shields/quefrency/quefrency.conf | 0 app/boards/shields/quefrency/quefrency.dtsi | 29 +++++++++++ app/boards/shields/quefrency/quefrency.keymap | 51 +++++++++++++++++++ .../shields/quefrency/quefrency_left.conf | 2 + .../shields/quefrency/quefrency_left.overlay | 34 +++++++++++++ .../shields/quefrency/quefrency_right.conf | 2 + .../shields/quefrency/quefrency_right.overlay | 42 +++++++++++++++ 10 files changed, 187 insertions(+) create mode 100644 app/boards/shields/quefrency/Kconfig.defconfig create mode 100644 app/boards/shields/quefrency/Kconfig.shield create mode 100644 app/boards/shields/quefrency/quefrency.conf create mode 100644 app/boards/shields/quefrency/quefrency.dtsi create mode 100644 app/boards/shields/quefrency/quefrency.keymap create mode 100644 app/boards/shields/quefrency/quefrency_left.conf create mode 100644 app/boards/shields/quefrency/quefrency_left.overlay create mode 100644 app/boards/shields/quefrency/quefrency_right.conf create mode 100644 app/boards/shields/quefrency/quefrency_right.overlay diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9af3d22b..454ab796 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,6 +21,8 @@ jobs: - romac - romac_plus - settings_reset + - quefrency_left + - quefrency_right include: - board: proton_c shield: clueboard_california diff --git a/app/boards/shields/quefrency/Kconfig.defconfig b/app/boards/shields/quefrency/Kconfig.defconfig new file mode 100644 index 00000000..c383340d --- /dev/null +++ b/app/boards/shields/quefrency/Kconfig.defconfig @@ -0,0 +1,17 @@ +#Copyright (c) 2020 Noah Thornton +#SPDX-License-Identifier: MIT + + +if SHIELD_QUEFRENCY_LEFT + +config ZMK_KEYBOARD_NAME + default "Quefrency Left" + +endif + +if SHIELD_QUEFRENCY_RIGHT + +config ZMK_KEYBOARD_NAME + default "Quefrency Right" + +endif diff --git a/app/boards/shields/quefrency/Kconfig.shield b/app/boards/shields/quefrency/Kconfig.shield new file mode 100644 index 00000000..d56a1b22 --- /dev/null +++ b/app/boards/shields/quefrency/Kconfig.shield @@ -0,0 +1,8 @@ +# Copyright (c) 2020 Noah Thornton +# SPDX-License-Identifier: MIT + +config SHIELD_QUEFRENCY_LEFT + def_bool $(shields_list_contains,quefrency_left) + +config SHIELD_QUEFRENCY_RIGHT + def_bool $(shields_list_contains,quefrency_right) diff --git a/app/boards/shields/quefrency/quefrency.conf b/app/boards/shields/quefrency/quefrency.conf new file mode 100644 index 00000000..e69de29b diff --git a/app/boards/shields/quefrency/quefrency.dtsi b/app/boards/shields/quefrency/quefrency.dtsi new file mode 100644 index 00000000..76f9b2e4 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency.dtsi @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Noah Thornton + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <15>; + rows = <6>; + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) /**/ RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,14) RC(5,13) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) /**/RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(5,14) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) /**/ RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,14) RC(2,13) +RC(3,0) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) /**/ RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,12) RC(3,13) RC(3,14) RC(3,11) +RC(4,0) RC(4,1) RC(4,2) RC(4,4) RC(4,6) /**/ RC(4,7) RC(4,10) RC(4,11) RC(4,12) RC(4,13) RC(4,14) RC(4,9) + >; + }; +}; + diff --git a/app/boards/shields/quefrency/quefrency.keymap b/app/boards/shields/quefrency/quefrency.keymap new file mode 100644 index 00000000..1eb7caa8 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency.keymap @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Noah Thornton + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + +// ---------------------------------------------- ----------------------------------------------------- +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | | 7 | 8 | 9 | 0 | - | = | BKSPC | ` | +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | [ | ] | \ | DEL | +// | LCTRL | A | S | D | F | G | | H | J | K | L | ; | ' | ENTER | PGUP | +// | SHIFT | Z | X | C | V | B | | N | M | , | . | / | RSHFT | UP | PGDN | +// | LCTRL | LGUI | LALT | SPACE | FN | | SPACE | RALT | FN | RCTRL | LFT | DWN | RGHT | +// ------------------------------------------- ------------------------------------------------------ + + default_layer { + bindings = < + &kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 /**/ &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp MINUS &kp EQL &kp BKSP &kp GRAV + &kp TAB &kp Q &kp W &kp E &kp R &kp T /**/ &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH &kp HOME + &kp LCTL &kp A &kp S &kp D &kp F &kp G /**/ &kp H &kp J &kp K &kp L &kp SCLN &kp QUOT &kp RET &kp PGUP + &kp LSFT &kp Z &kp X &kp C &kp V &kp B /**/ &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RSFT &kp UARW &kp PGDN + &kp LCTL &kp LGUI &kp LALT &kp SPC &mo 1 /**/ &kp SPC &kp RALT &mo 1 &kp RCTL &kp LARW &kp DARW &kp RARW + >; + }; + +// ---------------------------------------------- ----------------------------------------------------- +// |BT_CLR| F1 | F2 | F3 | F4 | F5 | F6 | | F7 | F8 | F9 | F10 | F11 | F12 | |BT_CLR| +// | | BT-0 | BT-1| BT-2 | | | | | | | | | | | | | +// | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | | | | +// | | | | | | | | | | | | | | +// ------------------------------------------- ------------------------------------------------------ + + fn_layer { + bindings = < + &bt BT_CLR &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 /**/ &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &trans &bt BT_CLR + &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans &trans + &trans &trans &trans &trans &trans /**/ &trans &trans &trans &trans &trans &trans &trans + >; + }; + }; +}; diff --git a/app/boards/shields/quefrency/quefrency_left.conf b/app/boards/shields/quefrency/quefrency_left.conf new file mode 100644 index 00000000..1e028a78 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency_left.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y diff --git a/app/boards/shields/quefrency/quefrency_left.overlay b/app/boards/shields/quefrency/quefrency_left.overlay new file mode 100644 index 00000000..a62ac8f7 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency_left.overlay @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Noah Thornton + * + * SPDX-License-Identifier: MIT + */ + +#include "quefrency.dtsi" + +/ { + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + + + col-gpios + = <&pro_micro_a 2 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 10 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro_a 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; diff --git a/app/boards/shields/quefrency/quefrency_right.conf b/app/boards/shields/quefrency/quefrency_right.conf new file mode 100644 index 00000000..990cf7c0 --- /dev/null +++ b/app/boards/shields/quefrency/quefrency_right.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL=y diff --git a/app/boards/shields/quefrency/quefrency_right.overlay b/app/boards/shields/quefrency/quefrency_right.overlay new file mode 100644 index 00000000..f4037ced --- /dev/null +++ b/app/boards/shields/quefrency/quefrency_right.overlay @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Noah Thornton + * + * SPDX-License-Identifier: MIT + */ + +#include "quefrency.dtsi" + +&default_transform { + col-offset = <7>; +}; + +/ { + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + + + + col-gpios + = <&pro_micro_a 2 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 10 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 5 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro_a 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + }; +}; From 24b638dfa37211fc5f0c09844d38760bae5eda5f Mon Sep 17 00:00:00 2001 From: Noah Thornton Date: Sat, 26 Sep 2020 21:09:19 -0500 Subject: [PATCH 103/227] Apply suggestions from code review Revise copyright header Co-authored-by: Pete Johanson --- app/boards/shields/quefrency/Kconfig.defconfig | 2 +- app/boards/shields/quefrency/Kconfig.shield | 2 +- app/boards/shields/quefrency/quefrency.dtsi | 3 +-- app/boards/shields/quefrency/quefrency.keymap | 2 +- app/boards/shields/quefrency/quefrency_left.overlay | 2 +- app/boards/shields/quefrency/quefrency_right.overlay | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/boards/shields/quefrency/Kconfig.defconfig b/app/boards/shields/quefrency/Kconfig.defconfig index c383340d..2b00cb62 100644 --- a/app/boards/shields/quefrency/Kconfig.defconfig +++ b/app/boards/shields/quefrency/Kconfig.defconfig @@ -1,4 +1,4 @@ -#Copyright (c) 2020 Noah Thornton +#Copyright (c) 2020 The ZMK Contributors #SPDX-License-Identifier: MIT diff --git a/app/boards/shields/quefrency/Kconfig.shield b/app/boards/shields/quefrency/Kconfig.shield index d56a1b22..d205e58f 100644 --- a/app/boards/shields/quefrency/Kconfig.shield +++ b/app/boards/shields/quefrency/Kconfig.shield @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Noah Thornton +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT config SHIELD_QUEFRENCY_LEFT diff --git a/app/boards/shields/quefrency/quefrency.dtsi b/app/boards/shields/quefrency/quefrency.dtsi index 76f9b2e4..74ddc33d 100644 --- a/app/boards/shields/quefrency/quefrency.dtsi +++ b/app/boards/shields/quefrency/quefrency.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Noah Thornton + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -26,4 +26,3 @@ RC(4,0) RC(4,1) RC(4,2) RC(4,4) RC(4,6) /**/ RC(4,7) >; }; }; - diff --git a/app/boards/shields/quefrency/quefrency.keymap b/app/boards/shields/quefrency/quefrency.keymap index 1eb7caa8..21c5ed40 100644 --- a/app/boards/shields/quefrency/quefrency.keymap +++ b/app/boards/shields/quefrency/quefrency.keymap @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Noah Thornton + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/shields/quefrency/quefrency_left.overlay b/app/boards/shields/quefrency/quefrency_left.overlay index a62ac8f7..a1d205e3 100644 --- a/app/boards/shields/quefrency/quefrency_left.overlay +++ b/app/boards/shields/quefrency/quefrency_left.overlay @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Noah Thornton + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/shields/quefrency/quefrency_right.overlay b/app/boards/shields/quefrency/quefrency_right.overlay index f4037ced..3876144e 100644 --- a/app/boards/shields/quefrency/quefrency_right.overlay +++ b/app/boards/shields/quefrency/quefrency_right.overlay @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Noah Thornton + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ From 9afd44b9d4a6790d315f2824ca6d21953804b1af Mon Sep 17 00:00:00 2001 From: Noah Thornton Date: Sat, 26 Sep 2020 22:10:14 -0500 Subject: [PATCH 104/227] Provide context on Quefrency physical PCB layouts The Quefrency board has two options for each left and right half, resulting in 4 unique combinations. This has been noted in the overlay and dtsi files. --- app/boards/shields/quefrency/quefrency.dtsi | 4 ++++ app/boards/shields/quefrency/quefrency_left.overlay | 3 +++ app/boards/shields/quefrency/quefrency_right.overlay | 3 +++ 3 files changed, 10 insertions(+) diff --git a/app/boards/shields/quefrency/quefrency.dtsi b/app/boards/shields/quefrency/quefrency.dtsi index 74ddc33d..5f1e9086 100644 --- a/app/boards/shields/quefrency/quefrency.dtsi +++ b/app/boards/shields/quefrency/quefrency.dtsi @@ -13,6 +13,10 @@ zmk,matrix_transform = &default_transform; }; + /* + * This transform correspondsto the 60% left without macro keypad and 65% right, even this + * combination of PCBs can have keys in different locations based on configuration. + */ default_transform: keymap_transform_0 { compatible = "zmk,matrix-transform"; columns = <15>; diff --git a/app/boards/shields/quefrency/quefrency_left.overlay b/app/boards/shields/quefrency/quefrency_left.overlay index a1d205e3..a385cc58 100644 --- a/app/boards/shields/quefrency/quefrency_left.overlay +++ b/app/boards/shields/quefrency/quefrency_left.overlay @@ -7,6 +7,9 @@ #include "quefrency.dtsi" / { + /* This kscan is for the 60% left half without macro keys the + * macro pad layout may require different column and row pins + */ kscan0: kscan { compatible = "zmk,kscan-gpio-matrix"; label = "KSCAN"; diff --git a/app/boards/shields/quefrency/quefrency_right.overlay b/app/boards/shields/quefrency/quefrency_right.overlay index 3876144e..53e0f77c 100644 --- a/app/boards/shields/quefrency/quefrency_right.overlay +++ b/app/boards/shields/quefrency/quefrency_right.overlay @@ -12,6 +12,9 @@ / { + /* This kscan is for the 65% right half the 60% right half + * may require different column and row pins + */ kscan0: kscan { compatible = "zmk,kscan-gpio-matrix"; label = "KSCAN"; From 9392c4f9ffbe815a44d007cf85a2a17955f46edb Mon Sep 17 00:00:00 2001 From: jason Date: Sun, 27 Sep 2020 21:27:30 -0400 Subject: [PATCH 105/227] Fix preprocessor flag issues for pull request. --- app/drivers/zephyr/kscan_gpio_direct.c | 16 ++++++++-------- app/drivers/zephyr/kscan_gpio_matrix.c | 23 ++++++++++++----------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c index 7ba3399b..c3414fbf 100644 --- a/app/drivers/zephyr/kscan_gpio_direct.c +++ b/app/drivers/zephyr/kscan_gpio_direct.c @@ -33,9 +33,9 @@ struct kscan_gpio_config { }; struct kscan_gpio_data { -#if defined(ZMK_KSCAN_DIRECT_POLLING) +#if defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) struct k_timer poll_timer; -#endif /* defined(ZMK_KSCAN_DIRECT_POLLING) */ +#endif /* defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) */ kscan_callback_t callback; union work_reference work; struct device *dev; @@ -53,7 +53,7 @@ static const struct kscan_gpio_item_config *kscan_gpio_input_configs(struct devi return cfg->inputs; } -#if !defined(ZMK_KSCAN_DIRECT_POLLING) +#if !defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) struct kscan_gpio_irq_callback { union work_reference *work; @@ -101,7 +101,7 @@ static void kscan_gpio_irq_callback_handler(struct device *dev, struct gpio_call } } -#else /* !defined(ZMK_KSCAN_DIRECT_POLLING) */ +#else /* !defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) */ static void kscan_gpio_timer_handler(struct k_timer *timer) { struct kscan_gpio_data *data = CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer); @@ -120,7 +120,7 @@ static int kscan_gpio_direct_disable(struct device *dev) { return 0; } -#endif /* defined(ZMK_KSCAN_DIRECT_POLLING) */ +#endif /* defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) */ static int kscan_gpio_direct_configure(struct device *dev, kscan_callback_t callback) { struct kscan_gpio_data *data = dev->driver_data; @@ -173,7 +173,7 @@ static const struct kscan_driver_api gpio_driver_api = { #define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios) #define GPIO_INST_INIT(n) \ - COND_CODE_0(ZMK_KSCAN_DIRECT_POLLING, \ + COND_CODE_0(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ (static struct kscan_gpio_irq_callback irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \ static struct kscan_gpio_data kscan_gpio_data_##n = { \ .inputs = {[INST_INPUT_LEN(n) - 1] = NULL}}; \ @@ -195,7 +195,7 @@ static const struct kscan_driver_api gpio_driver_api = { return err; \ } \ COND_CODE_0( \ - ZMK_KSCAN_DIRECT_POLLING, \ + CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ (irq_callbacks_##n[i].work = &data->work; \ irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ @@ -208,7 +208,7 @@ static const struct kscan_driver_api gpio_driver_api = { ()) \ } \ data->dev = dev; \ - COND_CODE_1(ZMK_KSCAN_DIRECT_POLLING, \ + COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ if (cfg->debounce_period > 0) { \ k_delayed_work_init(&data->work.delayed, kscan_gpio_work_handler); \ diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index e581d33e..b940c6da 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -31,8 +31,8 @@ struct kscan_gpio_item_config { #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) -COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, -(static int kscan_gpio_config_interrupts(struct device **devices, +#ifdef CONFIG_ZMK_KSCAN_MATRIX_POLLING +static int kscan_gpio_config_interrupts(struct device **devices, const struct kscan_gpio_item_config *configs, size_t len, gpio_flags_t flags) { for (int i = 0; i < len; i++) { @@ -48,7 +48,8 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, } return 0; -}), ()) +} +#endif #define INST_MATRIX_ROWS(n) DT_INST_PROP_LEN(n, row_gpios) #define INST_MATRIX_COLS(n) DT_INST_PROP_LEN(n, col_gpios) @@ -71,7 +72,7 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, }; \ struct kscan_gpio_data_##n { \ kscan_callback_t callback; \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \ @@ -99,7 +100,7 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, return ( \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ } \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ @@ -132,7 +133,7 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, /* Disable our interrupts temporarily while we scan, to avoid */ \ /* re-entry while we iterate columns and set them active one by one */ \ /* to get pressed state for each matrix cell. */ \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (kscan_gpio_disable_interrupts_##n(dev);),()) \ kscan_gpio_set_output_state_##n(dev, 0); \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ @@ -151,7 +152,7 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, /* Set all our outputs as active again. */ \ kscan_gpio_set_output_state_##n(dev, 1); \ /*Re-enable interrupts so that they can be triggered again for future press/release*/ \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (kscan_gpio_enable_interrupts_##n(dev);), ()) \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ @@ -200,7 +201,7 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, return 0; \ }; \ static int kscan_gpio_enable_##n(struct device *dev) { \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (int err = kscan_gpio_enable_interrupts_##n(dev); \ if (err) { \ return err; \ @@ -211,13 +212,13 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, return 0;)) \ }; \ static int kscan_gpio_disable_##n(struct device *dev) { \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (return kscan_gpio_disable_interrupts_##n(dev);), \ (struct kscan_gpio_data_##n *data = dev->driver_data; \ k_timer_stop(&data->poll_timer); \ return 0;)) \ }; \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ (static void kscan_gpio_timer_handler(struct k_timer *timer) { \ struct kscan_gpio_data_##n *data = \ CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \ @@ -267,7 +268,7 @@ COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, } \ } \ data->dev = dev; \ - COND_CODE_0(ZMK_KSCAN_MATRIX_POLLING, (), \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);)) \ (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \ &data->work, kscan_gpio_work_handler_##n); \ From c2a861c0e6a731fd92368768a9b07d5feac7d374 Mon Sep 17 00:00:00 2001 From: Jason Chestnut Date: Mon, 28 Sep 2020 08:24:51 -0400 Subject: [PATCH 106/227] Modify preprocessor directives to use basic #if !defined() rather than Zephyr macros where appropriate. --- app/drivers/zephyr/kscan_gpio_matrix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index b940c6da..5fa618bc 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -31,7 +31,7 @@ struct kscan_gpio_item_config { #define _KSCAN_GPIO_ROW_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, row_gpios, idx) #define _KSCAN_GPIO_COL_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, col_gpios, idx) -#ifdef CONFIG_ZMK_KSCAN_MATRIX_POLLING +#if !defined(CONFIG_ZMK_KSCAN_MATRIX_POLLING) static int kscan_gpio_config_interrupts(struct device **devices, const struct kscan_gpio_item_config *configs, size_t len, gpio_flags_t flags) { From 182a6dca1fc9b1d5e7b0d3828501d6be43ff70dd Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 29 Sep 2020 12:21:06 -0400 Subject: [PATCH 107/227] fix(bluetooth): Proper max paired/conns. * Proper max values for both split central, and non-split keyboards. --- app/Kconfig | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/app/Kconfig b/app/Kconfig index 61805656..ccd40da5 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -132,14 +132,28 @@ endif endif -if ZMK_BLE && (!ZMK_SPLIT_BLE || ZMK_SPLIT_BLE_ROLE_CENTRAL) +if ZMK_BLE + +if ZMK_SPLIT_BLE && ZMK_SPLIT_BLE_ROLE_CENTRAL config BT_MAX_CONN default 6 config BT_MAX_PAIRED + default 6 + +endif + +if !ZMK_SPLIT_BLE + +config BT_MAX_CONN default 5 +config BT_MAX_PAIRED + default 5 + +endif + endif endmenu From a3d0c03726a0bc607d4daab7a90dda57d4ba6a6f Mon Sep 17 00:00:00 2001 From: David Barr Date: Wed, 30 Sep 2020 16:20:41 +0100 Subject: [PATCH 108/227] rename cradios to cradio --- .DS_Store | Bin 0 -> 8196 bytes app/.DS_Store | Bin 0 -> 8196 bytes app/boards/.DS_Store | Bin 0 -> 8196 bytes app/boards/shields/.DS_Store | Bin 0 -> 8196 bytes .../{cradios => cradio}/Kconfig.defconfig | 5 +- .../{cradios => cradio}/Kconfig.shield | 4 +- .../{cradios.dtsi => cradio/cradio.dtsi} | 4 -- .../{cradios.keymap => cradio/cradio.keymap} | 0 .../cradio_left.conf} | 0 .../cradio_left.overlay} | 8 +-- .../cradio_right.conf} | 0 .../cradio_right.overlay} | 5 +- .../{cradios => cradio}/default.keymap | 0 app/boards/shields/cradios/cradios.dtsi | 67 ------------------ app/boards/shields/cradios/cradios.keymap | 18 ----- .../shields/cradios/cradios_right.overlay | 17 ----- app/boards/shields/cradios_left.conf | 2 - app/boards/shields/cradios_left.overlay | 15 ---- app/boards/shields/cradios_right.conf | 2 - 19 files changed, 6 insertions(+), 141 deletions(-) create mode 100644 .DS_Store create mode 100644 app/.DS_Store create mode 100644 app/boards/.DS_Store create mode 100644 app/boards/shields/.DS_Store rename app/boards/shields/{cradios => cradio}/Kconfig.defconfig (92%) rename app/boards/shields/{cradios => cradio}/Kconfig.shield (50%) rename app/boards/shields/{cradios.dtsi => cradio/cradio.dtsi} (99%) rename app/boards/shields/{cradios.keymap => cradio/cradio.keymap} (100%) rename app/boards/shields/{cradios/cradios_left.conf => cradio/cradio_left.conf} (100%) rename app/boards/shields/{cradios/cradios_left.overlay => cradio/cradio_left.overlay} (81%) rename app/boards/shields/{cradios/cradios_right.conf => cradio/cradio_right.conf} (100%) rename app/boards/shields/{cradios_right.overlay => cradio/cradio_right.overlay} (86%) rename app/boards/shields/{cradios => cradio}/default.keymap (100%) delete mode 100644 app/boards/shields/cradios/cradios.dtsi delete mode 100644 app/boards/shields/cradios/cradios.keymap delete mode 100644 app/boards/shields/cradios/cradios_right.overlay delete mode 100644 app/boards/shields/cradios_left.conf delete mode 100644 app/boards/shields/cradios_left.overlay delete mode 100644 app/boards/shields/cradios_right.conf diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..6b508f3d3ac3d8e154cb8b9356cbeda358ea05b0 GIT binary patch literal 8196 zcmeHMTWl3Y82Y%Mi6DcsKM4J8t2@<}4agPTcNPKrjKq%t>nhl&t^ z5P=YZ5P=YZ5P|;#0(55cBCT-l3v1Yh2!sgSmI(0oLyRhyi9pT@>AyOt@vi_R`4zw~ z)MvayG8V{0AZLXn3l$WhBt<9&R}2*4q>lxDi9pT@DZ&AR%LfKCV{k)3e|CC)%y$P& z2pP5^0wDr7BEWw>d7wcCGO5Yy@9&oBdhz(z7|F|DwR(*t%aXiKKG`$oO!j!1mvdXR z>~TIirg>wjpx^5_)#G&gP7x@nL0O`5tlHcUv_ zo_X3dva(zhY3#MNabxbzl2WFYshj4bgzsXk#LA_?T*^F?GrhB74mGw#me^Y-bXrcA zqw^=~zC~4I+a>8Z*SBU3YK2-+D|S(U*6Y%$gJo9TBg@R~eUP?OgerUQm1L&(Sz5}l z0#*HfQXLtX5NHO&5fs614T!FXYJ@^Q&!N>3! zd;#CVkMJ}63ctbc@CW>b63VDx0jjta%W)gVaX&U-BQ{|R9>Js7h27YTCvgOmsNpDP z@C;_r!}ItkK8BCullVNojIZFU_!_>6@8G+572n4X@N@hU=fwIV^JMJ`)*A@?o;tyg zk;oc+OpA=%jI7c2`<0IWhOFNfaE2DG-%z}9bNS9aHFXD?7dCO(zFkitpEZIOK3(SN z;BVei4$^L`Wy+>#AF;}qTI8_c^gP4a8qObyb3?r=x+Tgual~+2bVrm$h}&XV5#6n@ zJYufwJ69?3C|gA&71q5{C6hIa&(6x$^V>tm*6s7 zg%9CV;@ns81N;QPz@Nl784Iz5*j9#7+>Cc)1@6L1+=KhDo|xB&2e2IvVFw;2_Vr>v z4&V?DV;T)Sjbmu~+{@u4PT|9N0Usd-K7r5TbHu_Ih=rH%^<|vvT*kR8i=3P2$=a4< zkCJAdp-Y{^(Jh5Qp2((@-~ZcJ{{DYUuGBt-AZqLe%FpsJw=rl z?l&u>A3}|P9Vh8u$4M^yVMzTLx$>AqAZLXn4V8cWLqMq-p8r1b0{-y)Uj*ZJ>irGE Cjn>8h literal 0 HcmV?d00001 diff --git a/app/.DS_Store b/app/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7b9df9785ffe429ff6989ceea0ab40fc7af0588f GIT binary patch literal 8196 zcmeHMTTC2P82kW${VP;L1B7USCx=2$tOhe2hhMt%sQ!rX(v`$2ZA61 zK?H&b1Q7@#5Jcer5CJ-~SrOJa_qjG`g9ro>xFsXN-VYI~3}Zena`avu)OaZXAxidaiU&o;{%NihhcL+@16hW=bQODCmt&ei6?c zFvc-xg9ro>SRDcO_!K|_Y)~PclfQqINSTJ?Mx$S1C@+6q!FoXy1#zQzvVY2+?RQl- zP{v6{(xlhTvq1i>*^b;BX#u+3)PYN+S>X9)scp1!@`0nlbB(>4%fHnVGhnxLll6&1A+@UA@&b`;BwDGvexVF6)gscG_+C4CAt#arFCivNLA% z4zhMe47wdNlTo}}xFx)!a&NT0>2Sx=#@mWyN!na8JYzUU!qi7qC#hSSVNDLs8k##b zM)9&-Q`0B?u>&ygjW`%f*sXwTB$k0f%PoPqXGOQIws5`)O0TtF-@aL6o&Y zQ%&fmFKRqUqGQ7|Jet0+F1Uv~(!9{otuE3k{4txOD z;6wNXK7()Id-xH4hF{=U_znI*0Y#Ls5Ea~k6}S_lco3Vg8C$Rok6{n?Vjm9RNu0nq zsyK-$JcDU;@jO0^kKm*DI6jLn;!F54zJjmgTlh9!#dq;N{1iXOB|g7Uma@J6e0{)g zsk7q2B+B|9) zN17}tye(YGMA~zuT-q8QByQ<**O|Lod!xXiVUQd3wiAl7nii*#6$fjwN zpSDcfnk0Fatt(xEtD7t8`-Y)c4xVE zgz71(tT4Mpj-CrOUOG Hi#2}&7R=yI literal 0 HcmV?d00001 diff --git a/app/boards/.DS_Store b/app/boards/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f1a7fabe09abafc68e9bade17e3a66f1e4d09db5 GIT binary patch literal 8196 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 - }; kscan0: kscan { @@ -37,11 +36,8 @@ RC(0,15) RC(0,16) RC(0,33) RC(0,32) compatible = "zmk,bt-unpair-combo"; }; - - }; - &kscan0 { input-gpios = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> diff --git a/app/boards/shields/cradios.keymap b/app/boards/shields/cradio/cradio.keymap similarity index 100% rename from app/boards/shields/cradios.keymap rename to app/boards/shields/cradio/cradio.keymap diff --git a/app/boards/shields/cradios/cradios_left.conf b/app/boards/shields/cradio/cradio_left.conf similarity index 100% rename from app/boards/shields/cradios/cradios_left.conf rename to app/boards/shields/cradio/cradio_left.conf diff --git a/app/boards/shields/cradios/cradios_left.overlay b/app/boards/shields/cradio/cradio_left.overlay similarity index 81% rename from app/boards/shields/cradios/cradios_left.overlay rename to app/boards/shields/cradio/cradio_left.overlay index b0bdc6fe..c6600724 100644 --- a/app/boards/shields/cradios/cradios_left.overlay +++ b/app/boards/shields/cradio/cradio_left.overlay @@ -3,13 +3,9 @@ * * SPDX-License-Identifier: MIT */ -#include "cradios.dtsi" - - - - - +#include "cradio.dtsi" &bt_unpair_combo { + key-positions = <0 16>; }; diff --git a/app/boards/shields/cradios/cradios_right.conf b/app/boards/shields/cradio/cradio_right.conf similarity index 100% rename from app/boards/shields/cradios/cradios_right.conf rename to app/boards/shields/cradio/cradio_right.conf diff --git a/app/boards/shields/cradios_right.overlay b/app/boards/shields/cradio/cradio_right.overlay similarity index 86% rename from app/boards/shields/cradios_right.overlay rename to app/boards/shields/cradio/cradio_right.overlay index ef920ac3..3469199b 100644 --- a/app/boards/shields/cradios_right.overlay +++ b/app/boards/shields/cradio/cradio_right.overlay @@ -3,15 +3,12 @@ * * SPDX-License-Identifier: MIT */ -#include "cradios.dtsi" +#include "cradio.dtsi" &default_transform { col-offset = <17>; }; - - - &bt_unpair_combo { key-positions = <21 32>; }; diff --git a/app/boards/shields/cradios/default.keymap b/app/boards/shields/cradio/default.keymap similarity index 100% rename from app/boards/shields/cradios/default.keymap rename to app/boards/shields/cradio/default.keymap diff --git a/app/boards/shields/cradios/cradios.dtsi b/app/boards/shields/cradios/cradios.dtsi deleted file mode 100644 index 68d1fc57..00000000 --- a/app/boards/shields/cradios/cradios.dtsi +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2020 Pete Johanson - * - * SPDX-License-Identifier: MIT - */ - #include - -/ { - chosen { - zmk,kscan = &kscan0; - zmk,matrix_transform = &default_transform; - }; - - default_transform: keymap_transform_0 { - compatible = "zmk,matrix-transform"; - columns = <34>; - rows = <1>; - map = < -RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) -RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) -RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) -RC(0,15) RC(0,16) RC(0,33) RC(0,32) ->; - - - }; - - kscan0: kscan { - compatible = "zmk,kscan-gpio-direct"; - label = "KSCAN"; - }; - - - - - bt_unpair_combo: bt_unpair_combo { - compatible = "zmk,bt-unpair-combo"; - }; - - - - }; - - - &kscan0 { - input-gpios - = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_a 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> - ; -}; - - diff --git a/app/boards/shields/cradios/cradios.keymap b/app/boards/shields/cradios/cradios.keymap deleted file mode 100644 index c46468dd..00000000 --- a/app/boards/shields/cradios/cradios.keymap +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include - - -/ { - keymap { - compatible = "zmk,keymap"; - - default_layer { - bindings = < - &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P - &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN - &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH - &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 - >; - }; - }; -}; diff --git a/app/boards/shields/cradios/cradios_right.overlay b/app/boards/shields/cradios/cradios_right.overlay deleted file mode 100644 index ef920ac3..00000000 --- a/app/boards/shields/cradios/cradios_right.overlay +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2020 Pete Johanson - * - * SPDX-License-Identifier: MIT - */ -#include "cradios.dtsi" - -&default_transform { - col-offset = <17>; -}; - - - - -&bt_unpair_combo { - key-positions = <21 32>; -}; diff --git a/app/boards/shields/cradios_left.conf b/app/boards/shields/cradios_left.conf deleted file mode 100644 index 1e028a78..00000000 --- a/app/boards/shields/cradios_left.conf +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_ZMK_SPLIT=y -CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y diff --git a/app/boards/shields/cradios_left.overlay b/app/boards/shields/cradios_left.overlay deleted file mode 100644 index b0bdc6fe..00000000 --- a/app/boards/shields/cradios_left.overlay +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2020 Pete Johanson - * - * SPDX-License-Identifier: MIT - */ -#include "cradios.dtsi" - - - - - - -&bt_unpair_combo { - key-positions = <0 16>; -}; diff --git a/app/boards/shields/cradios_right.conf b/app/boards/shields/cradios_right.conf deleted file mode 100644 index 990cf7c0..00000000 --- a/app/boards/shields/cradios_right.conf +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_ZMK_SPLIT=y -CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL=y From 85af75c7f6ac736d2756095853327131732bd496 Mon Sep 17 00:00:00 2001 From: David Barr Date: Wed, 30 Sep 2020 17:10:29 +0100 Subject: [PATCH 109/227] remove .ds_store junk --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e02cca0e..eb4312fd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /tools /zephyr /build +**/.DS_Store From 17bee0223aa90037896d3a83d08fe01db1cab97b Mon Sep 17 00:00:00 2001 From: David Barr Date: Wed, 30 Sep 2020 17:12:39 +0100 Subject: [PATCH 110/227] remove ds_store files --- .DS_Store | Bin 8196 -> 0 bytes app/.DS_Store | Bin 8196 -> 0 bytes app/boards/.DS_Store | Bin 8196 -> 0 bytes app/boards/shields/.DS_Store | Bin 8196 -> 0 bytes 4 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 app/.DS_Store delete mode 100644 app/boards/.DS_Store delete mode 100644 app/boards/shields/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 6b508f3d3ac3d8e154cb8b9356cbeda358ea05b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMTWl3Y82Y%Mi6DcsKM4J8t2@<}4agPTcNPKrjKq%t>nhl&t^ z5P=YZ5P=YZ5P|;#0(55cBCT-l3v1Yh2!sgSmI(0oLyRhyi9pT@>AyOt@vi_R`4zw~ z)MvayG8V{0AZLXn3l$WhBt<9&R}2*4q>lxDi9pT@DZ&AR%LfKCV{k)3e|CC)%y$P& z2pP5^0wDr7BEWw>d7wcCGO5Yy@9&oBdhz(z7|F|DwR(*t%aXiKKG`$oO!j!1mvdXR z>~TIirg>wjpx^5_)#G&gP7x@nL0O`5tlHcUv_ zo_X3dva(zhY3#MNabxbzl2WFYshj4bgzsXk#LA_?T*^F?GrhB74mGw#me^Y-bXrcA zqw^=~zC~4I+a>8Z*SBU3YK2-+D|S(U*6Y%$gJo9TBg@R~eUP?OgerUQm1L&(Sz5}l z0#*HfQXLtX5NHO&5fs614T!FXYJ@^Q&!N>3! zd;#CVkMJ}63ctbc@CW>b63VDx0jjta%W)gVaX&U-BQ{|R9>Js7h27YTCvgOmsNpDP z@C;_r!}ItkK8BCullVNojIZFU_!_>6@8G+572n4X@N@hU=fwIV^JMJ`)*A@?o;tyg zk;oc+OpA=%jI7c2`<0IWhOFNfaE2DG-%z}9bNS9aHFXD?7dCO(zFkitpEZIOK3(SN z;BVei4$^L`Wy+>#AF;}qTI8_c^gP4a8qObyb3?r=x+Tgual~+2bVrm$h}&XV5#6n@ zJYufwJ69?3C|gA&71q5{C6hIa&(6x$^V>tm*6s7 zg%9CV;@ns81N;QPz@Nl784Iz5*j9#7+>Cc)1@6L1+=KhDo|xB&2e2IvVFw;2_Vr>v z4&V?DV;T)Sjbmu~+{@u4PT|9N0Usd-K7r5TbHu_Ih=rH%^<|vvT*kR8i=3P2$=a4< zkCJAdp-Y{^(Jh5Qp2((@-~ZcJ{{DYUuGBt-AZqLe%FpsJw=rl z?l&u>A3}|P9Vh8u$4M^yVMzTLx$>AqAZLXn4V8cWLqMq-p8r1b0{-y)Uj*ZJ>irGE Cjn>8h diff --git a/app/.DS_Store b/app/.DS_Store deleted file mode 100644 index 7b9df9785ffe429ff6989ceea0ab40fc7af0588f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMTTC2P82kW${VP;L1B7USCx=2$tOhe2hhMt%sQ!rX(v`$2ZA61 zK?H&b1Q7@#5Jcer5CJ-~SrOJa_qjG`g9ro>xFsXN-VYI~3}Zena`avu)OaZXAxidaiU&o;{%NihhcL+@16hW=bQODCmt&ei6?c zFvc-xg9ro>SRDcO_!K|_Y)~PclfQqINSTJ?Mx$S1C@+6q!FoXy1#zQzvVY2+?RQl- zP{v6{(xlhTvq1i>*^b;BX#u+3)PYN+S>X9)scp1!@`0nlbB(>4%fHnVGhnxLll6&1A+@UA@&b`;BwDGvexVF6)gscG_+C4CAt#arFCivNLA% z4zhMe47wdNlTo}}xFx)!a&NT0>2Sx=#@mWyN!na8JYzUU!qi7qC#hSSVNDLs8k##b zM)9&-Q`0B?u>&ygjW`%f*sXwTB$k0f%PoPqXGOQIws5`)O0TtF-@aL6o&Y zQ%&fmFKRqUqGQ7|Jet0+F1Uv~(!9{otuE3k{4txOD z;6wNXK7()Id-xH4hF{=U_znI*0Y#Ls5Ea~k6}S_lco3Vg8C$Rok6{n?Vjm9RNu0nq zsyK-$JcDU;@jO0^kKm*DI6jLn;!F54zJjmgTlh9!#dq;N{1iXOB|g7Uma@J6e0{)g zsk7q2B+B|9) zN17}tye(YGMA~zuT-q8QByQ<**O|Lod!xXiVUQd3wiAl7nii*#6$fjwN zpSDcfnk0Fatt(xEtD7t8`-Y)c4xVE zgz71(tT4Mpj-CrOUOG Hi#2}&7R=yI diff --git a/app/boards/.DS_Store b/app/boards/.DS_Store deleted file mode 100644 index f1a7fabe09abafc68e9bade17e3a66f1e4d09db5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 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 yl$4PR7s5pJN8vcj**^@qo{DwpSWZdF8czTEhXC Date: Wed, 30 Sep 2020 21:35:51 -0500 Subject: [PATCH 111/227] Add TG4X rev 2.1 shield --- app/boards/shields/tg4x/Kconfig.defconfig | 9 ++++ app/boards/shields/tg4x/Kconfig.shield | 5 ++ app/boards/shields/tg4x/tg4x.keymap | 58 +++++++++++++++++++++++ app/boards/shields/tg4x/tg4x.overlay | 56 ++++++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 app/boards/shields/tg4x/Kconfig.defconfig create mode 100644 app/boards/shields/tg4x/Kconfig.shield create mode 100644 app/boards/shields/tg4x/tg4x.keymap create mode 100644 app/boards/shields/tg4x/tg4x.overlay diff --git a/app/boards/shields/tg4x/Kconfig.defconfig b/app/boards/shields/tg4x/Kconfig.defconfig new file mode 100644 index 00000000..ca9fa2c3 --- /dev/null +++ b/app/boards/shields/tg4x/Kconfig.defconfig @@ -0,0 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +if SHIELD_TG4X + +config ZMK_KEYBOARD_NAME + default "TG4X" + +endif \ No newline at end of file diff --git a/app/boards/shields/tg4x/Kconfig.shield b/app/boards/shields/tg4x/Kconfig.shield new file mode 100644 index 00000000..7e98b710 --- /dev/null +++ b/app/boards/shields/tg4x/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_TG4X + def_bool $(shields_list_contains,tg4x) diff --git a/app/boards/shields/tg4x/tg4x.keymap b/app/boards/shields/tg4x/tg4x.keymap new file mode 100644 index 00000000..64e98bb3 --- /dev/null +++ b/app/boards/shields/tg4x/tg4x.keymap @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#define DEFAULT 0 +#define LOWER 1 +#define RAISE 2 + +/ { + behaviors { + hm: homerow_mods { + compatible = "zmk,behavior-hold-tap"; + label = "homerow mods"; + #binding-cells = <2>; + tapping_term_ms = <225>; + flavor = "tap-preferred"; + bindings = <&kp>, <&kp>; + }; + }; +}; + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { + bindings = < + &kp GRAV &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SCLN &kp BKSP + &kp TAB &hm LGUI A &hm LALT R &hm LCTL S &hm LSFT T &kp G &kp M &hm RSFT N &hm RCTL E &hm RALT I &hm RGUI O &kp RET + &kp LSFT &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &kp CMMA &kp DOT &kp FSLH &kp QUOT + &kp LCTL &kp LALT &kp LGUI < 1 BKSP < 2 SPC &kp LARW &kp DARW &kp UARW &kp RARW + >; + }; + lower { + bindings = < + &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PRSC + &kp DEL &trans &kp VOLU &trans &trans &trans &trans &kp LARW &kp DARW &kp UARW &kp RARW &trans + &trans &trans &kp VOLD &trans &trans &trans &trans &trans &trans &bt BT_PRV &bt BT_NXT &bt BT_CLR + &bootloader &reset &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 + >; + }; + + raise { + bindings = < + &kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp PRSC + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp TILD &kp HOME &kp PGUP &kp PGDN &kp END + &trans &trans &trans &trans &trans &trans &kp M_NEXT &kp M_VOLD &kp M_VOLU &kp M_PLAY + >; + }; + }; +}; \ No newline at end of file diff --git a/app/boards/shields/tg4x/tg4x.overlay b/app/boards/shields/tg4x/tg4x.overlay new file mode 100644 index 00000000..acab2e31 --- /dev/null +++ b/app/boards/shields/tg4x/tg4x.overlay @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Pete Johanson, Richard Jones + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <7>; + rows = <8>; + map = < + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,5) + RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) + RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4) + RC(3,0) RC(3,1) RC(3,2) RC(3,4) RC(3,5) RC(7,1) RC(7,2) RC(7,3) RC(7,4) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + diode-direction = "col2row"; + + col-gpios + = <&pro_micro_d 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 2 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 3 GPIO_ACTIVE_HIGH> + ; + + row-gpios + = <&pro_micro_a 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_a 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + +}; + From e993378b2a1705f97a5cca95d16810ab766f8d94 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 1 Oct 2020 11:24:57 -0400 Subject: [PATCH 112/227] chore: Fix some accidental formatting issues. --- app/drivers/zephyr/kscan_gpio_matrix.c | 69 ++++++++++++-------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index 5fa618bc..62008e32 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -72,7 +72,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, }; \ struct kscan_gpio_data_##n { \ kscan_callback_t callback; \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \ @@ -100,17 +100,18 @@ static int kscan_gpio_config_interrupts(struct device **devices, return ( \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ } \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ - (static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ - kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ - } \ - static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ - return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ - kscan_gpio_input_configs_##n(dev), INST_INPUT_LEN(n), \ - GPIO_INT_DISABLE); \ - }), ()) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ + ( \ + static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts( \ + kscan_gpio_input_devices_##n(dev), kscan_gpio_input_configs_##n(dev), \ + INST_INPUT_LEN(n), GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ + } static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ + return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ + kscan_gpio_input_configs_##n(dev), \ + INST_INPUT_LEN(n), GPIO_INT_DISABLE); \ + }), \ + ()) \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ @@ -133,8 +134,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, /* Disable our interrupts temporarily while we scan, to avoid */ \ /* re-entry while we iterate columns and set them active one by one */ \ /* to get pressed state for each matrix cell. */ \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ - (kscan_gpio_disable_interrupts_##n(dev);),()) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_disable_interrupts_##n(dev);), \ + ()) \ kscan_gpio_set_output_state_##n(dev, 0); \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ @@ -152,8 +153,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, /* Set all our outputs as active again. */ \ kscan_gpio_set_output_state_##n(dev, 1); \ /*Re-enable interrupts so that they can be triggered again for future press/release*/ \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ - (kscan_gpio_enable_interrupts_##n(dev);), ()) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_enable_interrupts_##n(dev);), ()) \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ bool pressed = read_state[r][c]; \ @@ -201,29 +201,24 @@ static int kscan_gpio_config_interrupts(struct device **devices, return 0; \ }; \ static int kscan_gpio_enable_##n(struct device *dev) { \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ - (int err = kscan_gpio_enable_interrupts_##n(dev); \ - if (err) { \ - return err; \ - } \ - return kscan_gpio_read_##n(dev);), \ - (struct kscan_gpio_data_##n *data = dev->driver_data; \ - k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); \ - return 0;)) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ + (int err = kscan_gpio_enable_interrupts_##n(dev); \ + if (err) { return err; } return kscan_gpio_read_##n(dev);), \ + (struct kscan_gpio_data_##n *data = dev->driver_data; \ + k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); return 0;)) \ }; \ static int kscan_gpio_disable_##n(struct device *dev) { \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ - (return kscan_gpio_disable_interrupts_##n(dev);), \ - (struct kscan_gpio_data_##n *data = dev->driver_data; \ - k_timer_stop(&data->poll_timer); \ - return 0;)) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ + (return kscan_gpio_disable_interrupts_##n(dev);), \ + (struct kscan_gpio_data_##n *data = dev->driver_data; \ + k_timer_stop(&data->poll_timer); return 0;)) \ }; \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ - (static void kscan_gpio_timer_handler(struct k_timer *timer) { \ - struct kscan_gpio_data_##n *data = \ - CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \ - k_work_submit(&data->work.work); \ - })) \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ + (static void kscan_gpio_timer_handler(struct k_timer *timer) { \ + struct kscan_gpio_data_##n *data = \ + CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \ + k_work_submit(&data->work.work); \ + })) \ static int kscan_gpio_init_##n(struct device *dev) { \ struct kscan_gpio_data_##n *data = dev->driver_data; \ int err; \ @@ -268,7 +263,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ } \ data->dev = dev; \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ + COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);)) \ (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \ &data->work, kscan_gpio_work_handler_##n); \ From 694b24ca86d315d6dcf906088a1a3d03d57579c0 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 1 Oct 2020 11:31:02 -0400 Subject: [PATCH 113/227] fix(ci): Lint detected changes to drivers dir. --- .github/workflows/clang-format-lint.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 061bc3da..70ae9863 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -6,11 +6,15 @@ on: - "app/boards/**/*.c" - "app/include/**/*.h" - "app/src/**" + - "app/drivers/**/*.c" + - "app/drivers/**/*.h" pull_request: paths: - "app/boards/**/*.c" - "app/include/**/*.h" - "app/src/**" + - "app/drivers/**/*.c" + - "app/drivers/**/*.h" jobs: build: From 028dfae92e2b0900514182f096959b07a7204ab3 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 1 Oct 2020 11:40:49 -0400 Subject: [PATCH 114/227] chore: Fix remaining formatting issues. --- app/drivers/zephyr/kscan_gpio_direct.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c index c3414fbf..d6dab4d1 100644 --- a/app/drivers/zephyr/kscan_gpio_direct.c +++ b/app/drivers/zephyr/kscan_gpio_direct.c @@ -173,7 +173,7 @@ static const struct kscan_driver_api gpio_driver_api = { #define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios) #define GPIO_INST_INIT(n) \ - COND_CODE_0(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ + COND_CODE_0(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ (static struct kscan_gpio_irq_callback irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \ static struct kscan_gpio_data kscan_gpio_data_##n = { \ .inputs = {[INST_INPUT_LEN(n) - 1] = NULL}}; \ @@ -195,7 +195,7 @@ static const struct kscan_driver_api gpio_driver_api = { return err; \ } \ COND_CODE_0( \ - CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ + CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ (irq_callbacks_##n[i].work = &data->work; \ irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ @@ -208,7 +208,7 @@ static const struct kscan_driver_api gpio_driver_api = { ()) \ } \ data->dev = dev; \ - COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ + COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ if (cfg->debounce_period > 0) { \ k_delayed_work_init(&data->work.delayed, kscan_gpio_work_handler); \ From 9a3d515583997a78b41ab9d2b84e8b56126dda09 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 1 Oct 2020 15:40:39 -0400 Subject: [PATCH 115/227] fix(docs): Link to nice!nano product page itself. --- docs/docs/hardware.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/hardware.md b/docs/docs/hardware.md index 236aa972..faac57c6 100644 --- a/docs/docs/hardware.md +++ b/docs/docs/hardware.md @@ -16,7 +16,7 @@ That being said, there are currently only a few specific [boards](/docs/faq#what ## Boards -- [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/) (`nice_nano`) +- [nice!nano](https://nicekeyboards.com/products/nice-nano-v1-0) (`nice_nano`) - [nrfMicro](https://github.com/joric/nrfmicro) (`nrfmicro_13`, `nrfmicro_11`, `nrfmicro_11_flipped`) - [BlueMicro840](https://store.jpconstantineau.com/#/group/bluemicro) (`bluemicro840_v1`) - [QMK Proton-C](https://qmk.fm/proton-c/) (`proton_c`) From 307a8d09db78b95c858c41bd5549c721da7eb1f8 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 1 Oct 2020 17:18:01 -0400 Subject: [PATCH 116/227] feat(usb): Function to access latest USB status. * To be leveraged by upcoming power management work. --- app/include/zmk/usb_hid.h | 2 ++ app/src/usb_hid.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/include/zmk/usb_hid.h b/app/include/zmk/usb_hid.h index 7ee26298..83a45407 100644 --- a/app/include/zmk/usb_hid.h +++ b/app/include/zmk/usb_hid.h @@ -14,4 +14,6 @@ int zmk_usb_hid_init(); +enum usb_dc_status_code zmk_usb_hid_get_status(); + int zmk_usb_hid_send_report(u8_t *report, size_t len); diff --git a/app/src/usb_hid.c b/app/src/usb_hid.c index 530ffea8..64addaea 100644 --- a/app/src/usb_hid.c +++ b/app/src/usb_hid.c @@ -28,6 +28,8 @@ static const struct hid_ops ops = { .int_in_ready = in_ready_cb, }; +enum usb_dc_status_code zmk_usb_hid_get_status() { return usb_status; } + int zmk_usb_hid_send_report(const u8_t *report, size_t len) { switch (usb_status) { case USB_DC_SUSPEND: From c68e3d3e42b9ff1722b2c2b9728f5d3b85784a45 Mon Sep 17 00:00:00 2001 From: Dev Date: Thu, 1 Oct 2020 11:26:54 +0530 Subject: [PATCH 117/227] Add missing licensing header Fixes #205 --- app/include/dt-bindings/zmk/keys.h | 5 +++++ app/include/dt-bindings/zmk/kscan-mock.h | 6 ++++++ app/include/dt-bindings/zmk/matrix-transform.h | 5 +++++ app/include/dt-bindings/zmk/rgb.h | 5 +++++ app/include/zmk/split/bluetooth/service.h | 6 ++++++ app/include/zmk/split/bluetooth/uuid.h | 6 ++++++ 6 files changed, 33 insertions(+) diff --git a/app/include/dt-bindings/zmk/keys.h b/app/include/dt-bindings/zmk/keys.h index d3dd6341..a3b22297 100644 --- a/app/include/dt-bindings/zmk/keys.h +++ b/app/include/dt-bindings/zmk/keys.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #pragma once diff --git a/app/include/dt-bindings/zmk/kscan-mock.h b/app/include/dt-bindings/zmk/kscan-mock.h index d481899f..eff218b2 100644 --- a/app/include/dt-bindings/zmk/kscan-mock.h +++ b/app/include/dt-bindings/zmk/kscan-mock.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once #define ZMK_MOCK_IS_PRESS(v) ((v & (0x01 << 31)) != 0) diff --git a/app/include/dt-bindings/zmk/matrix-transform.h b/app/include/dt-bindings/zmk/matrix-transform.h index 4fd3e6c9..2989cb60 100644 --- a/app/include/dt-bindings/zmk/matrix-transform.h +++ b/app/include/dt-bindings/zmk/matrix-transform.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #define KT_ROW(item) (item >> 8) #define KT_COL(item) (item & 0xFF) diff --git a/app/include/dt-bindings/zmk/rgb.h b/app/include/dt-bindings/zmk/rgb.h index c2efda88..eb721807 100644 --- a/app/include/dt-bindings/zmk/rgb.h +++ b/app/include/dt-bindings/zmk/rgb.h @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ #define RGB_TOG 0 #define RGB_HUI 1 diff --git a/app/include/zmk/split/bluetooth/service.h b/app/include/zmk/split/bluetooth/service.h index 954e0cdd..c2be512f 100644 --- a/app/include/zmk/split/bluetooth/service.h +++ b/app/include/zmk/split/bluetooth/service.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once int zmk_split_bt_position_pressed(u8_t position); diff --git a/app/include/zmk/split/bluetooth/uuid.h b/app/include/zmk/split/bluetooth/uuid.h index a8dfbf62..a31884d9 100644 --- a/app/include/zmk/split/bluetooth/uuid.h +++ b/app/include/zmk/split/bluetooth/uuid.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #pragma once #include From 38a418a1d16707d721d85900c0c7c637cd1795a3 Mon Sep 17 00:00:00 2001 From: David Barr Date: Fri, 2 Oct 2020 14:16:59 +0100 Subject: [PATCH 118/227] updates as per PR changes (i hope) --- app/boards/shields/cradio/Kconfig.defconfig | 7 +++--- app/boards/shields/cradio/Kconfig.shield | 2 +- app/boards/shields/cradio/cradio.dtsi | 23 ++++++++----------- app/boards/shields/cradio/cradio_left.conf | 3 +++ app/boards/shields/cradio/cradio_left.overlay | 7 +----- app/boards/shields/cradio/cradio_right.conf | 3 +++ .../shields/cradio/cradio_right.overlay | 3 ++- 7 files changed, 23 insertions(+), 25 deletions(-) diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig index ab38e258..46799b9e 100644 --- a/app/boards/shields/cradio/Kconfig.defconfig +++ b/app/boards/shields/cradio/Kconfig.defconfig @@ -1,10 +1,9 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + config ZMK_KEYBOARD_NAME default "cradio" -# Unable to use interrupts as the same pin number is used -# across A & B controllers, and STM32F303CCT6 can't enable -# interrutps for multiple controllers for the same "line" -# for the external interrupts. config ZMK_KSCAN_GPIO_POLLING default y diff --git a/app/boards/shields/cradio/Kconfig.shield b/app/boards/shields/cradio/Kconfig.shield index 0385d23e..71a439e0 100644 --- a/app/boards/shields/cradio/Kconfig.shield +++ b/app/boards/shields/cradio/Kconfig.shield @@ -1,4 +1,4 @@ -# Copyright (c) 2020 Pete Johanson +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT config SHIELD_CRADIO diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi index 19225f90..582f58a4 100644 --- a/app/boards/shields/cradio/cradio.dtsi +++ b/app/boards/shields/cradio/cradio.dtsi @@ -1,8 +1,9 @@ /* * Copyright (c) 2020 Pete Johanson * - * SPDX-License-Identifier: MIT + * Copyright (c) 2020 The ZMK Contributors */ + #include / { @@ -16,31 +17,27 @@ columns = <34>; rows = <1>; map = < -RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) -RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) -RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) -RC(0,15) RC(0,16) RC(0,33) RC(0,32) ->; + RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) + RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) + RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) + RC(0,15) RC(0,16) RC(0,33) RC(0,32) + >; - }; - kscan0: kscan { compatible = "zmk,kscan-gpio-direct"; label = "KSCAN"; }; - - - bt_unpair_combo: bt_unpair_combo { compatible = "zmk,bt-unpair-combo"; }; - }; + }; + }; &kscan0 { input-gpios - = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> + = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> diff --git a/app/boards/shields/cradio/cradio_left.conf b/app/boards/shields/cradio/cradio_left.conf index 1e028a78..405f04db 100644 --- a/app/boards/shields/cradio/cradio_left.conf +++ b/app/boards/shields/cradio/cradio_left.conf @@ -1,2 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y diff --git a/app/boards/shields/cradio/cradio_left.overlay b/app/boards/shields/cradio/cradio_left.overlay index c6600724..6caf8e3d 100644 --- a/app/boards/shields/cradio/cradio_left.overlay +++ b/app/boards/shields/cradio/cradio_left.overlay @@ -1,11 +1,6 @@ /* * Copyright (c) 2020 Pete Johanson * - * SPDX-License-Identifier: MIT + * Copyright (c) 2020 The ZMK Contributors */ -#include "cradio.dtsi" -&bt_unpair_combo { - - key-positions = <0 16>; -}; diff --git a/app/boards/shields/cradio/cradio_right.conf b/app/boards/shields/cradio/cradio_right.conf index 990cf7c0..bd2c93bf 100644 --- a/app/boards/shields/cradio/cradio_right.conf +++ b/app/boards/shields/cradio/cradio_right.conf @@ -1,2 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL=y diff --git a/app/boards/shields/cradio/cradio_right.overlay b/app/boards/shields/cradio/cradio_right.overlay index 3469199b..09efc53b 100644 --- a/app/boards/shields/cradio/cradio_right.overlay +++ b/app/boards/shields/cradio/cradio_right.overlay @@ -1,8 +1,9 @@ /* * Copyright (c) 2020 Pete Johanson * - * SPDX-License-Identifier: MIT + * Copyright (c) 2020 The ZMK Contributors */ + #include "cradio.dtsi" &default_transform { From 260044ae5e8dfc531ed98d08d0a3c9b9328e2ffe Mon Sep 17 00:00:00 2001 From: David Barr Date: Fri, 2 Oct 2020 14:17:35 +0100 Subject: [PATCH 119/227] Delete default.keymap --- app/boards/shields/cradio/default.keymap | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 app/boards/shields/cradio/default.keymap diff --git a/app/boards/shields/cradio/default.keymap b/app/boards/shields/cradio/default.keymap deleted file mode 100644 index 08210052..00000000 --- a/app/boards/shields/cradio/default.keymap +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - - -/ { - keymap0: keymap { - compatible = "zmk,keymap"; - - default_layer { - bindings = < - &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P - &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN - &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH - &kp DEL &kp RET &kp RET &kp SPC - - >; - }; - }; -}; From dfb4f1277d66b58de5473c46ed04cf3d7c102b30 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 2 Oct 2020 23:17:53 -0400 Subject: [PATCH 120/227] fix(docs): Proper emphasis of MUST NOT. --- docs/docs/dev-clean-room.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/dev-clean-room.md b/docs/docs/dev-clean-room.md index c11171c8..2f301ec7 100644 --- a/docs/docs/dev-clean-room.md +++ b/docs/docs/dev-clean-room.md @@ -6,7 +6,7 @@ sidebar_label: Clean Room :::warning -Anyone wanting to contribute code to ZMK _must_ read this, and adhere to the steps outlines in order to not violate any licenses/copyright of other projects +Anyone wanting to contribute code to ZMK _MUST_ read this, and adhere to the steps outlines in order to not violate any licenses/copyright of other projects ::: @@ -22,8 +22,8 @@ or duplicating any of the GPL code found in those other projects, even though th Contributors to ZMK must adhere to the following standard. -- Implementations of features for ZMK _MUST_ not reuse any existing code from any projects not licensed with the MIT license. -- Contributors _MUST_ not study or refer to any GPL licensed source code while working on ZMK. +- Implementations of features for ZMK _MUST NOT_ reuse any existing code from any projects not licensed with the MIT license. +- Contributors _MUST NOT_ study or refer to any GPL licensed source code while working on ZMK. - Contributors _MAY_ read the documentation from other GPL licensed projects, to gain a broad understanding of the behavior of certain features in order to implement equivalent features for ZMK. - Contributors _MAY_ refer to the [QMK Configurator](https://config.qmk.fm/) to inspect existing layouts/keymaps for keyboards, and re-implement them for ZMK. From f6f8abe05514c3588c4aa4a56897462c377bcab6 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sat, 26 Sep 2020 18:39:13 -0500 Subject: [PATCH 121/227] fix(ec11): allow more than one encoder Fixes "device.h:101:11: error: redefinition of '__device_ec11'" in firmware that has more than one encoder. --- app/drivers/zephyr/ec11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/drivers/zephyr/ec11.c b/app/drivers/zephyr/ec11.c index a4e96c24..00d00905 100644 --- a/app/drivers/zephyr/ec11.c +++ b/app/drivers/zephyr/ec11.c @@ -142,7 +142,7 @@ int ec11_init(struct device *dev) { .b_flags = DT_INST_GPIO_FLAGS(n, b_gpios), \ COND_CODE_0(DT_INST_NODE_HAS_PROP(n, resolution), (1), (DT_INST_PROP(n, resolution))), \ }; \ - DEVICE_AND_API_INIT(ec11, DT_INST_LABEL(n), ec11_init, &ec11_data_##n, &ec11_cfg_##n, \ + DEVICE_AND_API_INIT(ec11_##n, DT_INST_LABEL(n), ec11_init, &ec11_data_##n, &ec11_cfg_##n, \ POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, &ec11_driver_api); DT_INST_FOREACH_STATUS_OKAY(EC11_INST) \ No newline at end of file From fc5915b2001c80df5ab2db72b04d86a083e27556 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sun, 4 Oct 2020 12:33:12 -0500 Subject: [PATCH 122/227] improvement(kscan): use ARRAY_SIZE macro --- app/src/kscan_composite.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/kscan_composite.c b/app/src/kscan_composite.c index 02491407..f8e8d604 100644 --- a/app/src/kscan_composite.c +++ b/app/src/kscan_composite.c @@ -38,8 +38,7 @@ struct kscan_composite_data { }; static int kscan_composite_enable_callback(struct device *dev) { - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); - i++) { + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; kscan_enable_callback(device_get_binding(cfg->label)); @@ -48,8 +47,7 @@ static int kscan_composite_enable_callback(struct device *dev) { } static int kscan_composite_disable_callback(struct device *dev) { - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); - i++) { + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; kscan_disable_callback(device_get_binding(cfg->label)); @@ -63,8 +61,7 @@ static void kscan_composite_child_callback(struct device *child_dev, u32_t row, struct device *dev = device_get_binding(DT_INST_LABEL(0)); struct kscan_composite_data *data = dev->driver_data; - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); - i++) { + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; if (device_get_binding(cfg->label) != child_dev) { @@ -82,8 +79,7 @@ static int kscan_composite_configure(struct device *dev, kscan_callback_t callba return -EINVAL; } - for (int i = 0; i < sizeof(kscan_composite_children) / sizeof(kscan_composite_children[0]); - i++) { + for (int i = 0; i < ARRAY_SIZE(kscan_composite_children); i++) { const struct kscan_composite_child_config *cfg = &kscan_composite_children[i]; kscan_config(device_get_binding(cfg->label), &kscan_composite_child_callback); From 4121b07f7f75b81cf1d533632fde858074b0fc03 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sun, 4 Oct 2020 14:03:55 -0500 Subject: [PATCH 123/227] fix(kscan): fix direct GPIO when using interrupts Fixed initializing interrupts for direct GPIO when CONFIG_ZMK_KSCAN_DIRECT_POLLING is not enabled. IS_ENABLED() is needed to map the possibly-undefined value to 0 or 1 so COND_CODE_0() and COND_CODE_1() work. --- app/drivers/zephyr/kscan_gpio_direct.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c index d6dab4d1..4818c995 100644 --- a/app/drivers/zephyr/kscan_gpio_direct.c +++ b/app/drivers/zephyr/kscan_gpio_direct.c @@ -173,7 +173,7 @@ static const struct kscan_driver_api gpio_driver_api = { #define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios) #define GPIO_INST_INIT(n) \ - COND_CODE_0(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ + COND_CODE_0(IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING), \ (static struct kscan_gpio_irq_callback irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \ static struct kscan_gpio_data kscan_gpio_data_##n = { \ .inputs = {[INST_INPUT_LEN(n) - 1] = NULL}}; \ @@ -195,7 +195,7 @@ static const struct kscan_driver_api gpio_driver_api = { return err; \ } \ COND_CODE_0( \ - CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ + IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING), \ (irq_callbacks_##n[i].work = &data->work; \ irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ @@ -208,7 +208,7 @@ static const struct kscan_driver_api gpio_driver_api = { ()) \ } \ data->dev = dev; \ - COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, \ + COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING), \ (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ if (cfg->debounce_period > 0) { \ k_delayed_work_init(&data->work.delayed, kscan_gpio_work_handler); \ From 31e481954f1e22e42bde4b71753e279cdd4c77ed Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 4 Oct 2020 17:03:56 -0700 Subject: [PATCH 124/227] fix(docs): Fixed Python environment variables and commands for Windows setup --- docs/docs/dev-setup.md | 111 +++++++++++++++++++++-------------------- 1 file changed, 57 insertions(+), 54 deletions(-) diff --git a/docs/docs/dev-setup.md b/docs/docs/dev-setup.md index 1d7d703b..2e232f89 100644 --- a/docs/docs/dev-setup.md +++ b/docs/docs/dev-setup.md @@ -12,16 +12,16 @@ groupId="operating-systems" defaultValue="debian" values={[ {label: 'Debian/Ubuntu', value: 'debian'}, -{label: 'Raspberry OS', value: 'raspberryos'}, -{label: 'Fedora', value: 'fedora'}, {label: 'Windows', value: 'win'}, {label: 'macOS', value: 'mac'}, +{label: 'Raspberry OS', value: 'raspberryos'}, +{label: 'Fedora', value: 'fedora'}, ] }>{props.children}); ## Prerequisites -A unix-like environment with the following base packages installed: +ZMK requires the following base packages to first be installed: - Git - Python 3 @@ -34,6 +34,7 @@ A unix-like environment with the following base packages installed: + On Debian and Ubuntu, we'll use `apt` to install our base dependencies: First, if you haven't updated recently, or if this is a new install, @@ -74,7 +75,8 @@ or download and install CMake version 3.13.1 or newer manually. ::: -On Raspberry OS, we'll use apt to install our base dependencies: + +On Raspberry OS, we'll use `apt` to install our base dependencies: First, if you haven't updated recently, or if this is a new install, you should update to get the latest package information: @@ -185,14 +187,39 @@ brew install cmake ninja python3 ccache dtc git wget `west` is the [Zephyr™ meta-tool](https://docs.zephyrproject.org/2.3.0/guides/west/index.html) used to configure and build Zephyr™ applications. -West can be installed by using the `pip` python package manager. +West can be installed by using the `pip` python package manager. The [Zephyr™ instructions](https://docs.zephyrproject.org/latest/guides/west/install.html#installing-west) are summarized here: + + + ```sh pip3 install --user -U west ``` -:::danger pip user packages -If you haven't done so yet, you may need to add the Python Pip user package directory to your `PATH` otherwise your computer will not be able to find the `west` command. + + + +In `cmd.exe` as **Administrator**: + +```sh +pip3 install -U west +``` + +Once `west` is installed, close Command Prompt and open a new session as a **user** for the remainder of the instructions. +:::note +**For Windows, do not use the `--user` argument** that Linux uses otherwise `west` will be installed in a different location and the below instructions for adding Python `pip` will no longer apply. +::: + + + + +:::danger `pip` user packages +If you haven't done so yet, you may need to add the Python `pip` package directory to your `PATH` otherwise your computer will not be able to find the `west` command. ::: 1. See the [Environment Variables](#environment-variables) section on how to get to the Environment Variables page. -3. Click "Edit..." and then "New" to add the directory where your west.exe is located. By default this should be something like `C:\Python38\Scripts`. +2. Under "System variables" select the "Path" variable. Click "Edit..." and then "New" to add the directory where your `west.exe` is located. By default this should be `C:\Python##\Scripts` where ## is your Python version number. +3. Close Command Prompt and open a new session for the changes to take effect, or run `refreshenv`. @@ -279,7 +307,7 @@ The installation will prompt with several questions about installation location, #### GNU ARM Embedded -Since the Zephyr™ SDK is not available for Windows, we recommending following the steps to install the [GNU ARM Embedded](https://docs.zephyrproject.org/2.3.0/getting_started/toolchain_3rd_party_x_compilers.html#gnu-arm-embedded). +Since the Zephyr™ SDK is not available for Windows, we recommending following the [Zephyr documentation](https://docs.zephyrproject.org/2.3.0/getting_started/toolchain_3rd_party_x_compilers.html#gnu-arm-embedded) to install a GNU ARM Embedded build. Note the warnings regarding installing the toolchain into a path with spaces, and make sure to follow the steps to add the environment variables which are also summarized with screenshots in the [Environment Variables](#environment-variables) section below. @@ -308,7 +336,7 @@ The transient instructions must be run to build firmware using the current shell ### Source Code -Next, you'll need to clone the ZMK source repository if you haven't already: +Next, you'll need to clone the ZMK source repository if you haven't already. Navigate to the folder you would like to place your `zmk` directory in and run the following command: ``` git clone https://github.com/zmkfirmware/zmk.git @@ -358,12 +386,17 @@ pip3 install --user -r zephyr/scripts/requirements-base.txt ### Environment Variables + + + #### For GNU ARM Embedded on Windows -On Windows, you will have to set two environment variables for ZMK to build properly: `ZEPHYR_TOOLCHAIN_VARIANT` and `GNUARMEMB_TOOLCHAIN_PATH`. - -

- Steps to Update Environment Variables +On Windows, only two environment variables need to be set for ZMK to build properly: `ZEPHYR_TOOLCHAIN_VARIANT` and `GNUARMEMB_TOOLCHAIN_PATH`. 1. Open Start Menu and type 'env' to find the 'Edit the system environment variables' option. Open it. @@ -381,11 +414,15 @@ On Windows, you will have to set two environment variables for ZMK to build prop ![Adding Zephyr toolchain variable](assets/env-var/zephyr_toolchain.png) -5. Create another variable with variable name 'GNUARMEMB_TOOLCHAIN_PATH' and value set to wherever you installed your toolchain. Click OK to save. +5. Create another variable with variable name 'GNUARMEMB_TOOLCHAIN_PATH' and value set to wherever you installed your toolchain. **Make sure this path does not contain any spaces.** If it does, rename the folder and update here. Click OK to save. ![Adding GNUARMEMB variable](assets/env-var/gnuarmemb.png) -
+6. Close Command Prompt and reopen, or run `refreshenv` to apply the changes. + + + + #### For Zephyr @@ -396,48 +433,10 @@ We suggest two main [options](https://docs.zephyrproject.org/2.3.0/guides/env_va To load the Zephyr environment properly for just one transient shell, run the following from your ZMK checkout directory: - - - ``` source zephyr/zephyr-env.sh ``` - - - - -``` -source zephyr/zephyr-env.sh -``` - - - - - -``` -source zephyr/zephyr-env.sh -``` - - - - - -``` -source zephyr/zephyr-env.sh -``` - - - - - -``` -source zephyr/zephyr-env.cmd -``` - - - - ##### All Shells To load the environment variables for your shell every time, @@ -469,3 +468,7 @@ cat ~/.zephyrrc >> ~/.zshrc + + + + From 6427e64df3e889325ea471ff98f185f5eee27027 Mon Sep 17 00:00:00 2001 From: Kevin Date: Sun, 4 Oct 2020 17:10:34 -0700 Subject: [PATCH 125/227] fix(docs): Reorganized section in Windows setup --- docs/docs/dev-setup.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs/dev-setup.md b/docs/docs/dev-setup.md index 2e232f89..4891f5af 100644 --- a/docs/docs/dev-setup.md +++ b/docs/docs/dev-setup.md @@ -210,11 +210,12 @@ In `cmd.exe` as **Administrator**: pip3 install -U west ``` -Once `west` is installed, close Command Prompt and open a new session as a **user** for the remainder of the instructions. :::note **For Windows, do not use the `--user` argument** that Linux uses otherwise `west` will be installed in a different location and the below instructions for adding Python `pip` will no longer apply. ::: +Once `west` is installed, close Command Prompt and open a new session as a **user** for the remainder of the instructions. + From bbf5a5905a973d6d23457d2e7bf15bf6bac234c3 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 4 Oct 2020 18:18:44 -0400 Subject: [PATCH 126/227] refactor(usb): Report USB status w/o HID output. --- app/CMakeLists.txt | 2 +- app/Kconfig | 6 +++++- app/include/zmk/{usb_hid.h => usb.h} | 6 +++--- app/src/endpoints.c | 2 +- app/src/{usb_hid.c => usb.c} | 19 +++++++++++++------ 5 files changed, 23 insertions(+), 12 deletions(-) rename app/include/zmk/{usb_hid.h => usb.h} (73%) rename app/src/{usb_hid.c => usb.c} (77%) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3e0560b7..5c77c54f 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -54,7 +54,7 @@ target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL app PRIVATE src/split/ target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL app PRIVATE src/split/bluetooth/central.c) target_sources_ifdef(CONFIG_ZMK_KSCAN_MOCK_DRIVER app PRIVATE src/kscan_mock.c) target_sources_ifdef(CONFIG_ZMK_KSCAN_COMPOSITE_DRIVER app PRIVATE src/kscan_composite.c) -target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE src/usb_hid.c) +target_sources_ifdef(CONFIG_USB app PRIVATE src/usb.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c) target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c) target_sources(app PRIVATE src/endpoints.c) diff --git a/app/Kconfig b/app/Kconfig index ccd40da5..9398fce1 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -21,12 +21,16 @@ menuconfig ZMK_USB select USB_DEVICE_STACK select USB_DEVICE_HID -if ZMK_USB +if USB config ZMK_USB_INIT_PRIORITY int "Init Priority" default 50 +endif + +if ZMK_USB + config USB_NUMOF_EP_WRITE_RETRIES default 10 diff --git a/app/include/zmk/usb_hid.h b/app/include/zmk/usb.h similarity index 73% rename from app/include/zmk/usb_hid.h rename to app/include/zmk/usb.h index 83a45407..452fd54d 100644 --- a/app/include/zmk/usb_hid.h +++ b/app/include/zmk/usb.h @@ -12,8 +12,8 @@ #include #include -int zmk_usb_hid_init(); - -enum usb_dc_status_code zmk_usb_hid_get_status(); +enum usb_dc_status_code zmk_usb_get_status(); +#ifdef CONFIG_ZMK_USB int zmk_usb_hid_send_report(u8_t *report, size_t len); +#endif /* CONFIG_ZMK_USB */ \ No newline at end of file diff --git a/app/src/endpoints.c b/app/src/endpoints.c index ae785870..79d294ef 100644 --- a/app/src/endpoints.c +++ b/app/src/endpoints.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/app/src/usb_hid.c b/app/src/usb.c similarity index 77% rename from app/src/usb_hid.c rename to app/src/usb.c index 64addaea..434b3d4d 100644 --- a/app/src/usb_hid.c +++ b/app/src/usb.c @@ -18,6 +18,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static enum usb_dc_status_code usb_status = USB_DC_UNKNOWN; +#ifdef CONFIG_ZMK_USB + static struct device *hid_dev; static K_SEM_DEFINE(hid_sem, 1, 1); @@ -28,8 +30,6 @@ static const struct hid_ops ops = { .int_in_ready = in_ready_cb, }; -enum usb_dc_status_code zmk_usb_hid_get_status() { return usb_status; } - int zmk_usb_hid_send_report(const u8_t *report, size_t len) { switch (usb_status) { case USB_DC_SUSPEND: @@ -51,11 +51,16 @@ int zmk_usb_hid_send_report(const u8_t *report, size_t len) { } } -void usb_hid_status_cb(enum usb_dc_status_code status, const u8_t *params) { usb_status = status; }; +#endif /* CONFIG_ZMK_USB */ -static int zmk_usb_hid_init(struct device *_arg) { +enum usb_dc_status_code zmk_usb_get_status() { return usb_status; } + +void usb_status_cb(enum usb_dc_status_code status, const u8_t *params) { usb_status = status; }; + +static int zmk_usb_init(struct device *_arg) { int usb_enable_ret; +#ifdef CONFIG_ZMK_USB hid_dev = device_get_binding("HID_0"); if (hid_dev == NULL) { LOG_ERR("Unable to locate HID device"); @@ -66,7 +71,9 @@ static int zmk_usb_hid_init(struct device *_arg) { usb_hid_init(hid_dev); - usb_enable_ret = usb_enable(usb_hid_status_cb); +#endif /* CONFIG_ZMK_USB */ + + usb_enable_ret = usb_enable(usb_status_cb); if (usb_enable_ret != 0) { LOG_ERR("Unable to enable USB"); @@ -76,4 +83,4 @@ static int zmk_usb_hid_init(struct device *_arg) { return 0; } -SYS_INIT(zmk_usb_hid_init, APPLICATION, CONFIG_ZMK_USB_INIT_PRIORITY); +SYS_INIT(zmk_usb_init, APPLICATION, CONFIG_ZMK_USB_INIT_PRIORITY); From 9be566603e2eb248fbaa7af65cba42d5c06dbd33 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 6 Aug 2020 09:30:31 -0400 Subject: [PATCH 127/227] feat(kscan): Use PORT events for kscan matrix interrupts * Lower power usage compared to regular interrupts on nrf52. --- app/boards/arm/nice_nano/nice_nano.dts | 4 ++++ app/drivers/zephyr/kscan_gpio_matrix.c | 16 ++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/boards/arm/nice_nano/nice_nano.dts b/app/boards/arm/nice_nano/nice_nano.dts index 2e9556b8..3ffb0ea8 100644 --- a/app/boards/arm/nice_nano/nice_nano.dts +++ b/app/boards/arm/nice_nano/nice_nano.dts @@ -31,6 +31,10 @@ }; +&gpiote { + status = "okay"; +}; + &gpio0 { status = "okay"; }; diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index 62008e32..cd793243 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -64,6 +64,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, struct kscan_gpio_irq_callback_##n { \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) * work; \ struct gpio_callback callback; \ + struct device *dev; \ }; \ static struct kscan_gpio_irq_callback_##n irq_callbacks_##n[INST_INPUT_LEN(n)]; \ struct kscan_gpio_config_##n { \ @@ -105,7 +106,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ return kscan_gpio_config_interrupts( \ kscan_gpio_input_devices_##n(dev), kscan_gpio_input_configs_##n(dev), \ - INST_INPUT_LEN(n), GPIO_INT_DEBOUNCE | GPIO_INT_EDGE_BOTH); \ + INST_INPUT_LEN(n), GPIO_INT_LEVEL_ACTIVE); \ } static int kscan_gpio_disable_interrupts_##n(struct device *dev) { \ return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ kscan_gpio_input_configs_##n(dev), \ @@ -113,10 +114,13 @@ static int kscan_gpio_config_interrupts(struct device **devices, }), \ ()) \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ + int err; \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ struct device *in_dev = kscan_gpio_output_devices_##n(dev)[i]; \ const struct kscan_gpio_item_config *cfg = &kscan_gpio_output_configs_##n(dev)[i]; \ - gpio_pin_set(in_dev, cfg->pin, value); \ + if ((err = gpio_pin_set(in_dev, cfg->pin, value))) { \ + LOG_DBG("FAILED TO SET OUTPUT %d to %d", cfg->pin, err); \ + } \ } \ } \ static void kscan_gpio_set_matrix_state_##n( \ @@ -134,8 +138,6 @@ static int kscan_gpio_config_interrupts(struct device **devices, /* Disable our interrupts temporarily while we scan, to avoid */ \ /* re-entry while we iterate columns and set them active one by one */ \ /* to get pressed state for each matrix cell. */ \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_disable_interrupts_##n(dev);), \ - ()) \ kscan_gpio_set_output_state_##n(dev, 0); \ for (int o = 0; o < INST_OUTPUT_LEN(n); o++) { \ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[o]; \ @@ -152,8 +154,6 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ /* Set all our outputs as active again. */ \ kscan_gpio_set_output_state_##n(dev, 1); \ - /*Re-enable interrupts so that they can be triggered again for future press/release*/ \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (kscan_gpio_enable_interrupts_##n(dev);), ()) \ for (int r = 0; r < INST_MATRIX_ROWS(n); r++) { \ for (int c = 0; c < INST_MATRIX_COLS(n); c++) { \ bool pressed = read_state[r][c]; \ @@ -172,6 +172,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, k_delayed_work_cancel(&data->work); \ k_delayed_work_submit(&data->work, K_MSEC(5)); \ })) \ + } else { \ + kscan_gpio_enable_interrupts_##n(dev); \ } \ return 0; \ } \ @@ -183,6 +185,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, gpio_port_pins_t pin) { \ struct kscan_gpio_irq_callback_##n *data = \ CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ + kscan_gpio_disable_interrupts_##n(data->dev); \ COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ k_delayed_work_cancel(data->work); \ k_delayed_work_submit(data->work, \ @@ -238,6 +241,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, LOG_DBG("Configured pin %d on %s for input", in_cfg->pin, in_cfg->label); \ } \ irq_callbacks_##n[i].work = &data->work; \ + irq_callbacks_##n[i].dev = dev; \ gpio_init_callback(&irq_callbacks_##n[i].callback, \ kscan_gpio_irq_callback_handler_##n, BIT(in_cfg->pin)); \ err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \ From c54decd1443a41bd68905256db6286d51324c8e4 Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Thu, 1 Oct 2020 23:57:16 +0800 Subject: [PATCH 128/227] Added Makerdiary M.2 module --- app/boards/arm/nrf52840_m2/CMakeLists.txt | 13 +++ app/boards/arm/nrf52840_m2/Kconfig | 10 ++ app/boards/arm/nrf52840_m2/Kconfig.board | 10 ++ app/boards/arm/nrf52840_m2/Kconfig.defconfig | 30 ++++++ app/boards/arm/nrf52840_m2/board.cmake | 9 ++ app/boards/arm/nrf52840_m2/nrf52840_m2.dts | 97 +++++++++++++++++++ app/boards/arm/nrf52840_m2/nrf52840_m2.yaml | 15 +++ .../arm/nrf52840_m2/nrf52840_m2_defconfig | 23 +++++ 8 files changed, 207 insertions(+) create mode 100644 app/boards/arm/nrf52840_m2/CMakeLists.txt create mode 100644 app/boards/arm/nrf52840_m2/Kconfig create mode 100644 app/boards/arm/nrf52840_m2/Kconfig.board create mode 100644 app/boards/arm/nrf52840_m2/Kconfig.defconfig create mode 100644 app/boards/arm/nrf52840_m2/board.cmake create mode 100644 app/boards/arm/nrf52840_m2/nrf52840_m2.dts create mode 100644 app/boards/arm/nrf52840_m2/nrf52840_m2.yaml create mode 100644 app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig diff --git a/app/boards/arm/nrf52840_m2/CMakeLists.txt b/app/boards/arm/nrf52840_m2/CMakeLists.txt new file mode 100644 index 00000000..84b2ab99 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/CMakeLists.txt @@ -0,0 +1,13 @@ +# +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +set_property(GLOBAL APPEND PROPERTY extra_post_build_commands + COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/../tools/uf2/utils/uf2conv.py + -c + -b 0x26000 + -f 0xADA52840 + -o ${PROJECT_BINARY_DIR}/${CONFIG_KERNEL_BIN_NAME}.uf2 + ${PROJECT_BINARY_DIR}/${CONFIG_KERNEL_BIN_NAME}.bin +) diff --git a/app/boards/arm/nrf52840_m2/Kconfig b/app/boards/arm/nrf52840_m2/Kconfig new file mode 100644 index 00000000..faff4925 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/Kconfig @@ -0,0 +1,10 @@ +# +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +config BOARD_ENABLE_DCDC + bool "Enable DCDC mode" + select SOC_DCDC_NRF52X + default y + depends on BOARD_NRF52840_M2 diff --git a/app/boards/arm/nrf52840_m2/Kconfig.board b/app/boards/arm/nrf52840_m2/Kconfig.board new file mode 100644 index 00000000..6ade68c1 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/Kconfig.board @@ -0,0 +1,10 @@ +# Maker Diary nrf52840 M.2 board configuration +# +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +config BOARD_NRF52840_M2 + bool "nrf52480_m2" + depends on SOC_NRF52840_QIAA + diff --git a/app/boards/arm/nrf52840_m2/Kconfig.defconfig b/app/boards/arm/nrf52840_m2/Kconfig.defconfig new file mode 100644 index 00000000..98fcd083 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/Kconfig.defconfig @@ -0,0 +1,30 @@ +# +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +if BOARD_NRF52840_M2 + +config BOARD + default "nrf52480_m2" + +if USB + +config USB_NRFX + default y + +config USB_DEVICE_STACK + default y + +endif # USB + +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/board.cmake b/app/boards/arm/nrf52840_m2/board.cmake new file mode 100644 index 00000000..f521e2c0 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/board.cmake @@ -0,0 +1,9 @@ +# +# Copyright (c) 2020 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/nrf52840_m2/nrf52840_m2.dts b/app/boards/arm/nrf52840_m2/nrf52840_m2.dts new file mode 100644 index 00000000..fb5b0ff6 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2.dts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * SPDX-License-Identifier: MIT + */ + +/dts-v1/; +#include + +/ { + model = "Makerdiary nRF52840 M.2 module"; + compatible = "makerdiary,nrf52840_m2"; + + chosen { + zephyr,code-partition = &code_partition; + //zephyr,console = &uart0; + //zephyr,bt-mon-uart = &uart0; + //zephyr,bt-c2h-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + }; + + leds { + compatible = "gpio-leds"; + red_led: led_0 { + gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + label = "Red LED"; + }; + green_led: led_1 { + gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + blue_led: led_2 { + gpios = <&gpio0 31 GPIO_ACTIVE_HIGH>; + label = "Blue LED"; + }; + }; + +}; + +&gpio0 { + status = "okay"; +}; + +&gpio1 { + status = "okay"; +}; + +&uart0 { + compatible = "nordic,nrf-uart"; + status = "okay"; + current-speed = <115200>; + tx-pin = <16>; + rx-pin = <15>; + rts-pin = <14>; + cts-pin = <13>; +}; + +&usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; +}; + + +&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>; + + boot_partition: partition@0 { + label = "adafruit_boot"; + reg = <0x000000000 0x0000C000>; + }; + code_partition: partition@26000 { + label = "code_partition"; + reg = <0x00026000 0x000d2000>; + }; + + /* + * The flash starting at 0x000f8000 and ending at + * 0x000fffff is reserved for use by the application. + */ + + /* + * Storage partition will be used by FCB/LittleFS/NVS + * if enabled. + */ + storage_partition: partition@f8000 { + label = "storage"; + reg = <0x000f8000 0x00008000>; + }; + }; +}; diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2.yaml b/app/boards/arm/nrf52840_m2/nrf52840_m2.yaml new file mode 100644 index 00000000..0a999bbf --- /dev/null +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2.yaml @@ -0,0 +1,15 @@ +identifier: nrf52840_m2 +name: Makerdiary nRF52840 M.2 module +type: mcu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +supported: + - adc + - usb_device + - ble + - ieee802154 + - pwm + - watchdog diff --git a/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig b/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig new file mode 100644 index 00000000..e74438b7 --- /dev/null +++ b/app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig @@ -0,0 +1,23 @@ +# +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +CONFIG_SOC_SERIES_NRF52X=y +CONFIG_SOC_NRF52840_QIAA=y +CONFIG_BOARD_NRF52840_M2=y + +# Enable MPU +CONFIG_ARM_MPU=y + +# enable GPIO +CONFIG_GPIO=y + +CONFIG_USE_DT_CODE_PARTITION=y + +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 From 9d06c730ba8b70429ecb67d3ff502ed1fde584bd Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Fri, 2 Oct 2020 00:18:30 +0800 Subject: [PATCH 129/227] Added Makerdiary M60 keyboard --- app/boards/shields/m60/Kconfig.defconfig | 10 ++++ app/boards/shields/m60/Kconfig.shield | 5 ++ app/boards/shields/m60/m60.conf | 0 app/boards/shields/m60/m60.keymap | 26 ++++++++++ app/boards/shields/m60/m60.overlay | 65 ++++++++++++++++++++++++ app/boards/shields/m60/readme.md | 15 ++++++ 6 files changed, 121 insertions(+) create mode 100644 app/boards/shields/m60/Kconfig.defconfig create mode 100644 app/boards/shields/m60/Kconfig.shield create mode 100644 app/boards/shields/m60/m60.conf create mode 100644 app/boards/shields/m60/m60.keymap create mode 100644 app/boards/shields/m60/m60.overlay create mode 100644 app/boards/shields/m60/readme.md diff --git a/app/boards/shields/m60/Kconfig.defconfig b/app/boards/shields/m60/Kconfig.defconfig new file mode 100644 index 00000000..e358a587 --- /dev/null +++ b/app/boards/shields/m60/Kconfig.defconfig @@ -0,0 +1,10 @@ + +if SHIELD_M60 + +config ZMK_KEYBOARD_NAME + default "m60" + +config ZMK_KSCAN_MATRIX_POLLING + default y + +endif diff --git a/app/boards/shields/m60/Kconfig.shield b/app/boards/shields/m60/Kconfig.shield new file mode 100644 index 00000000..4ed58c49 --- /dev/null +++ b/app/boards/shields/m60/Kconfig.shield @@ -0,0 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT + +config SHIELD_M60 + def_bool $(shields_list_contains,m60) diff --git a/app/boards/shields/m60/m60.conf b/app/boards/shields/m60/m60.conf new file mode 100644 index 00000000..e69de29b diff --git a/app/boards/shields/m60/m60.keymap b/app/boards/shields/m60/m60.keymap new file mode 100644 index 00000000..aa0fa75e --- /dev/null +++ b/app/boards/shields/m60/m60.keymap @@ -0,0 +1,26 @@ +#include +#include +#include + +/ { + keymap0: keymap { + compatible = "zmk,keymap"; + + default_layer { +// ------------------------------------------------------------------------------------------ +// | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | +// | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | +// | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | +// | CTL | WIN | ALT | SPACE | ALT | MO(1) | WIN | CTRL | +// ------------------------------------------------------------------------------------------ + bindings = < + &kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp MINUS &kp EQL &kp BKSP + &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp LBKT &kp RBKT &kp BSLH + &kp CLCK &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp QUOT &kp RET + &kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp RSFT + &kp LCTL &kp LGUI &kp LALT &kp SPC &kp RALT &mo 1 &kp RGUI &kp RCTL + >; + }; + }; +}; diff --git a/app/boards/shields/m60/m60.overlay b/app/boards/shields/m60/m60.overlay new file mode 100644 index 00000000..c20d4525 --- /dev/null +++ b/app/boards/shields/m60/m60.overlay @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&gpio0 5 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio1 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 12 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&gpio0 11 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + col-gpios + = <&gpio0 19 GPIO_ACTIVE_HIGH> + , <&gpio0 20 GPIO_ACTIVE_HIGH> + , <&gpio0 21 GPIO_ACTIVE_HIGH> + , <&gpio0 22 GPIO_ACTIVE_HIGH> + , <&gpio0 23 GPIO_ACTIVE_HIGH> + , <&gpio0 24 GPIO_ACTIVE_HIGH> + , <&gpio0 25 GPIO_ACTIVE_HIGH> + , <&gpio0 26 GPIO_ACTIVE_HIGH> + ; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <8>; + rows = <8>; +// | MX1 | MX2 | MX3 | MX4 | MX5 | MX6 | MX7 | MX8 | MX9 | MX10 | MX11 | MX12 | MX13 | MX14 | +// | MX15 | MX16 | MX17 | MX18 | MX19 | MX20 | MX21 | MX22 | MX23 | MX24 | MX25 | MX26 | MX27 | MX28 | +// | MX29 | MX30 | MX31 | MX32 | MX33 | MX34 | MX35 | MX36 | MX37 | MX38 | MX39 | MX40 | MX41 | +// | MX42 | MX43 | MX44 | MX45 | MX46 | MX47 | MX48 | MX49 | MX50 | MX51 | MX52 | MX53 | +// | MX54 | MX55 | MX56 | MX57 | MX58 | MX59 | MX60 | MX61 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) +RC(3,3) RC(3,2) RC(3,1) RC(3,0) RC(2,7) RC(2,6) RC(2,5) RC(2,4) RC(2,3) RC(2,2) RC(2,1) RC(2,0) RC(1,7) RC(1,6) +RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(5,0) +RC(6,4) RC(6,3) RC(6,2) RC(6,1) RC(6,0) RC(5,7) RC(5,6) RC(5,5) RC(5,4) RC(5,3) RC(5,2) RC(5,1) +RC(6,5) RC(6,6) RC(6,7) RC(7,0) RC(7,1) RC(7,2) RC(7,3) RC(7,4) + >; + }; + + bt_unpair_combo: bt_unpair_combo { + compatible = "zmk,bt-unpair-combo"; + key-positions = <0 53>; + }; + +}; + diff --git a/app/boards/shields/m60/readme.md b/app/boards/shields/m60/readme.md new file mode 100644 index 00000000..7eaf226d --- /dev/null +++ b/app/boards/shields/m60/readme.md @@ -0,0 +1,15 @@ +# [Makerdiary M60](https://wiki.makerdiary.com/m60) + +A 60% ANSI keyboard designed and manufactured by Makerdiary. +http://makerdairy.com + +## Features + +- Per key RGB LED. +- Uses makerdiary M.2 nRF52840 module +- Matrix wiring + +## Hardware Notes + +https://wiki.makerdiary.com/m60/developer_guide/hardware/ + From e2299836bccf21bf56a4d34c5ed2f53a2fa21da2 Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Sat, 3 Oct 2020 17:35:17 +0800 Subject: [PATCH 130/227] Update contributors in all keymap files --- .../clueboard_california/clueboard_california.keymap | 6 ++++++ app/boards/shields/corne/corne.keymap | 6 ++++++ app/boards/shields/iris/iris.keymap | 2 +- app/boards/shields/kyria/kyria.keymap | 6 ++++++ app/boards/shields/lily58/lily58.keymap | 6 ++++++ app/boards/shields/m60/Kconfig.defconfig | 4 ++++ app/boards/shields/m60/Kconfig.shield | 2 ++ app/boards/shields/m60/m60.keymap | 6 ++++++ app/boards/shields/m60/m60.overlay | 1 + app/boards/shields/romac/romac.keymap | 2 +- app/boards/shields/sofle/sofle.keymap | 6 ++++++ app/boards/shields/splitreus62/splitreus62.keymap | 3 ++- 12 files changed, 47 insertions(+), 3 deletions(-) diff --git a/app/boards/shields/clueboard_california/clueboard_california.keymap b/app/boards/shields/clueboard_california/clueboard_california.keymap index 7a84b119..44a0b076 100644 --- a/app/boards/shields/clueboard_california/clueboard_california.keymap +++ b/app/boards/shields/clueboard_california/clueboard_california.keymap @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include diff --git a/app/boards/shields/corne/corne.keymap b/app/boards/shields/corne/corne.keymap index 5f0f15f0..64d4a001 100644 --- a/app/boards/shields/corne/corne.keymap +++ b/app/boards/shields/corne/corne.keymap @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include #include diff --git a/app/boards/shields/iris/iris.keymap b/app/boards/shields/iris/iris.keymap index 6042ad7b..8b06b1b7 100644 --- a/app/boards/shields/iris/iris.keymap +++ b/app/boards/shields/iris/iris.keymap @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson, Kurtis Lew + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/shields/kyria/kyria.keymap b/app/boards/shields/kyria/kyria.keymap index f689ef62..ac0d13f0 100644 --- a/app/boards/shields/kyria/kyria.keymap +++ b/app/boards/shields/kyria/kyria.keymap @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include diff --git a/app/boards/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap index 61c19f86..997a1248 100644 --- a/app/boards/shields/lily58/lily58.keymap +++ b/app/boards/shields/lily58/lily58.keymap @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include #include diff --git a/app/boards/shields/m60/Kconfig.defconfig b/app/boards/shields/m60/Kconfig.defconfig index e358a587..56695b96 100644 --- a/app/boards/shields/m60/Kconfig.defconfig +++ b/app/boards/shields/m60/Kconfig.defconfig @@ -1,3 +1,7 @@ +# +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT +# if SHIELD_M60 diff --git a/app/boards/shields/m60/Kconfig.shield b/app/boards/shields/m60/Kconfig.shield index 4ed58c49..47a28e24 100644 --- a/app/boards/shields/m60/Kconfig.shield +++ b/app/boards/shields/m60/Kconfig.shield @@ -1,5 +1,7 @@ +# # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT +# config SHIELD_M60 def_bool $(shields_list_contains,m60) diff --git a/app/boards/shields/m60/m60.keymap b/app/boards/shields/m60/m60.keymap index aa0fa75e..16ad2470 100644 --- a/app/boards/shields/m60/m60.keymap +++ b/app/boards/shields/m60/m60.keymap @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include #include diff --git a/app/boards/shields/m60/m60.overlay b/app/boards/shields/m60/m60.overlay index c20d4525..babae2db 100644 --- a/app/boards/shields/m60/m60.overlay +++ b/app/boards/shields/m60/m60.overlay @@ -3,6 +3,7 @@ * * SPDX-License-Identifier: MIT */ + #include / { diff --git a/app/boards/shields/romac/romac.keymap b/app/boards/shields/romac/romac.keymap index 97ea9c54..31e1ce82 100644 --- a/app/boards/shields/romac/romac.keymap +++ b/app/boards/shields/romac/romac.keymap @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson, Richard Jones + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/shields/sofle/sofle.keymap b/app/boards/shields/sofle/sofle.keymap index 1cbe742c..e2ebc1aa 100644 --- a/app/boards/shields/sofle/sofle.keymap +++ b/app/boards/shields/sofle/sofle.keymap @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + #include #include #include diff --git a/app/boards/shields/splitreus62/splitreus62.keymap b/app/boards/shields/splitreus62/splitreus62.keymap index 920e61ad..07dd2ad6 100644 --- a/app/boards/shields/splitreus62/splitreus62.keymap +++ b/app/boards/shields/splitreus62/splitreus62.keymap @@ -1,9 +1,10 @@ /* - * Copyright (c) 2020 Derek Schmell + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ + #include #include From b8cb5f939a3c018af13de7727c15d7765ea1f1c1 Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Sat, 3 Oct 2020 18:21:22 +0800 Subject: [PATCH 131/227] M60 keymap update and misc changes * Updated M60 keymap * Make nrfjproj as default runner * Remove the polling config --- app/boards/arm/nrf52840_m2/board.cmake | 2 +- app/boards/shields/m60/Kconfig.defconfig | 3 --- app/boards/shields/m60/m60.keymap | 12 +++++++++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/boards/arm/nrf52840_m2/board.cmake b/app/boards/arm/nrf52840_m2/board.cmake index f521e2c0..55b44e27 100644 --- a/app/boards/arm/nrf52840_m2/board.cmake +++ b/app/boards/arm/nrf52840_m2/board.cmake @@ -5,5 +5,5 @@ board_runner_args(nrfjprog "--nrf-family=NRF52" "--softreset") -include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.board.cmake) diff --git a/app/boards/shields/m60/Kconfig.defconfig b/app/boards/shields/m60/Kconfig.defconfig index 56695b96..e31d5a53 100644 --- a/app/boards/shields/m60/Kconfig.defconfig +++ b/app/boards/shields/m60/Kconfig.defconfig @@ -8,7 +8,4 @@ if SHIELD_M60 config ZMK_KEYBOARD_NAME default "m60" -config ZMK_KSCAN_MATRIX_POLLING - default y - endif diff --git a/app/boards/shields/m60/m60.keymap b/app/boards/shields/m60/m60.keymap index 16ad2470..cbe356c2 100644 --- a/app/boards/shields/m60/m60.keymap +++ b/app/boards/shields/m60/m60.keymap @@ -15,7 +15,7 @@ default_layer { // ------------------------------------------------------------------------------------------ // | ESC | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | BKSP | -// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | "|" | +// | TAB | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | // | CAPS | A | S | D | F | G | H | J | K | L | ; | ' | ENTER | // | SHIFT | Z | X | C | V | B | N | M | , | . | / | SHIFT | // | CTL | WIN | ALT | SPACE | ALT | MO(1) | WIN | CTRL | @@ -28,5 +28,15 @@ &kp LCTL &kp LGUI &kp LALT &kp SPC &kp RALT &mo 1 &kp RGUI &kp RCTL >; }; + + fn_layer { + bindings = < +&kp GRAV &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &bootloader +&trans &bt BT_CLR &none &none &none &none &none &none &none &none &none &none &none &reset +&trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LARW &kp DARW &kp UARW &kp RARW &none &none &trans +&trans &none &none &none &none &none &none &none &none &none &none &trans +&trans &trans &trans &trans &trans &trans &trans &trans + >; + }; }; }; From 4de7cc45de18f791ecbb361bfc2330a45e97d79e Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 5 Oct 2020 09:43:05 -0400 Subject: [PATCH 132/227] feat(setup): Add M.2 and M60 to setup scripts. --- docs/static/setup.ps1 | 10 +++++----- docs/static/setup.sh | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index 3946e66c..dc7b18c9 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -63,8 +63,8 @@ $repo_path = "https://github.com/zmkfirmware/zmk-config-split-template.git" $title = "ZMK Config Setup:" $prompt = "Pick an MCU board" -$options = "nice!nano", "QMK Proton-C", "BlueMicro840 (v1)" -$boards = "nice_nano", "proton_c", "bluemicro840_v1" +$options = "nice!nano", "QMK Proton-C", "BlueMicro840 (v1)", "makerdiary nRF52840 M.2" +$boards = "nice_nano", "proton_c", "bluemicro840_v1", "nrf52840_m2" Write-Host "$title" Write-Host "" @@ -78,9 +78,9 @@ Write-Host "Keyboard Shield Selection:" $prompt = "Pick a keyboard" # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. -$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac" -$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac" -$splits = "y", "y", "y", "y", "y", "y", "n" +$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac", "makerdiary M60" +$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac", "m60" +$splits = "y", "y", "y", "y", "y", "y", "n", "n" $choice = Get-Choice-From-Options -Options $options -Prompt $prompt $shield_title = $($options[$choice]) diff --git a/docs/static/setup.sh b/docs/static/setup.sh index 5bf36451..9e989644 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -26,7 +26,7 @@ repo_path="https://github.com/zmkfirmware/zmk-config-split-template.git" title="ZMK Config Setup:" prompt="Pick an MCU board:" -options=("nice!nano" "QMK Proton-C" "BlueMicro840 (v1)") +options=("nice!nano" "QMK Proton-C" "BlueMicro840 (v1)" "makerdiary nRF52840 M.2") echo "$title" echo "" @@ -39,6 +39,7 @@ select opt in "${options[@]}" "Quit"; do 1 ) board="nice_nano"; break;; 2 ) board="proton_c"; break;; 3 ) board="bluemicro840_v1"; break;; + 3 ) board="nrf52840_m2"; break;; $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;; *) echo "Invalid option. Try another one."; continue;; @@ -50,7 +51,7 @@ echo "" echo "Keyboard Shield Selection:" prompt="Pick an keyboard:" -options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac") +options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac" "makerdiary M60") PS3="$prompt " # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. @@ -66,6 +67,7 @@ select opt in "${options[@]}" "Quit"; do 5 ) shield_title="Sofle" shield="sofle"; split="y"; break;; 6 ) shield_title="Iris" shield="iris"; split="y"; break;; 7 ) shield_title="RoMac" shield="romac"; split="n"; break;; + 7 ) shield_title="M60" shield="m60"; split="n"; break;; # Add link to docs on adding your own custom shield in your ZMK config! # $(( ${#options[@]}+1 )) ) echo "Other!"; break;; From ce59223efe9062ac1da77bae93a3578ce0463b66 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 5 Oct 2020 23:40:29 -0400 Subject: [PATCH 133/227] fix(shields): Typo in makerdiary URL. --- app/boards/shields/m60/readme.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/boards/shields/m60/readme.md b/app/boards/shields/m60/readme.md index 7eaf226d..e801c788 100644 --- a/app/boards/shields/m60/readme.md +++ b/app/boards/shields/m60/readme.md @@ -1,7 +1,7 @@ # [Makerdiary M60](https://wiki.makerdiary.com/m60) A 60% ANSI keyboard designed and manufactured by Makerdiary. -http://makerdairy.com +http://makerdiary.com ## Features @@ -12,4 +12,3 @@ http://makerdairy.com ## Hardware Notes https://wiki.makerdiary.com/m60/developer_guide/hardware/ - From a7496ab06425cab7de5fc7164b4ce5a34dd7107b Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 2 Oct 2020 02:09:38 -0400 Subject: [PATCH 134/227] feat(power): Initial deep sleep work. * New ZMK_SLEEP Kconfig symbol to enable the functionality. * Switch to PORT events that allows wake from deep sleep. * Initial basic power management policy, with idle ms, and ignoring deep sleep if we detect a USB connection. --- app/CMakeLists.txt | 1 + app/Kconfig | 20 +++++++- app/drivers/zephyr/kscan_gpio_matrix.c | 58 ++++++++++++---------- app/include/dt-bindings/zmk/bt.h | 2 +- app/src/power.c | 69 ++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 29 deletions(-) create mode 100644 app/src/power.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 5c77c54f..3e59d751 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_linker_sources(RODATA include/linker/zmk-events.ld) # Add your source file to the "app" target. This must come after # find_package(Zephyr) which defines the target. target_include_directories(app PRIVATE include) +target_sources_ifdef(CONFIG_ZMK_SLEEP app PRIVATE src/power.c) target_sources(app PRIVATE src/kscan.c) target_sources(app PRIVATE src/matrix_transform.c) target_sources(app PRIVATE src/hid.c) diff --git a/app/Kconfig b/app/Kconfig index 9398fce1..edf58670 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -76,6 +76,25 @@ endif endmenu +menuconfig ZMK_SLEEP + bool "Enable deep sleep support" + imply USB + +if ZMK_SLEEP + +config SYS_POWER_DEEP_SLEEP_STATES + default y + +choice SYS_PM_POLICY + default SYS_PM_POLICY_APP +endchoice + +config ZMK_IDLE_SLEEP_TIMEOUT + int "Milliseconds to wait to sleep when going idle" + default 900000 + +endif + config ZMK_DISPLAY bool "ZMK display support" default n @@ -112,7 +131,6 @@ config ZMK_SPLIT_BLE_ROLE_CENTRAL config ZMK_SPLIT_BLE_ROLE_PERIPHERAL bool "Peripheral" - select BT_KEYS_OVERWRITE_OLDEST if ZMK_SPLIT_BLE_ROLE_PERIPHERAL diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index cd793243..a0b22e4a 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -73,7 +73,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, }; \ struct kscan_gpio_data_##n { \ kscan_callback_t callback; \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), (struct k_timer poll_timer;)) \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (struct k_timer poll_timer;), ()) \ struct COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work), (k_delayed_work)) work; \ bool matrix_state[INST_MATRIX_ROWS(n)][INST_MATRIX_COLS(n)]; \ struct device *rows[INST_MATRIX_ROWS(n)]; \ @@ -101,7 +101,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, return ( \ COND_CODE_0(DT_ENUM_IDX(DT_DRV_INST(n), diode_direction), (cfg->rows), (cfg->cols))); \ } \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ ( \ static int kscan_gpio_enable_interrupts_##n(struct device *dev) { \ return kscan_gpio_config_interrupts( \ @@ -111,8 +111,7 @@ static int kscan_gpio_config_interrupts(struct device **devices, return kscan_gpio_config_interrupts(kscan_gpio_input_devices_##n(dev), \ kscan_gpio_input_configs_##n(dev), \ INST_INPUT_LEN(n), GPIO_INT_DISABLE); \ - }), \ - ()) \ + })) \ static void kscan_gpio_set_output_state_##n(struct device *dev, int value) { \ int err; \ for (int i = 0; i < INST_OUTPUT_LEN(n); i++) { \ @@ -173,7 +172,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, k_delayed_work_submit(&data->work, K_MSEC(5)); \ })) \ } else { \ - kscan_gpio_enable_interrupts_##n(dev); \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ + (kscan_gpio_enable_interrupts_##n(dev);)) \ } \ return 0; \ } \ @@ -181,17 +181,20 @@ static int kscan_gpio_config_interrupts(struct device **devices, struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ kscan_gpio_read_##n(data->dev); \ } \ - static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \ - gpio_port_pins_t pin) { \ - struct kscan_gpio_irq_callback_##n *data = \ - CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ - kscan_gpio_disable_interrupts_##n(data->dev); \ - COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ - k_delayed_work_cancel(data->work); \ - k_delayed_work_submit(data->work, \ - K_MSEC(DT_INST_PROP(n, debounce_period))); \ - })) \ - } \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ + (static void kscan_gpio_irq_callback_handler_##n( \ + struct device *dev, struct gpio_callback *cb, gpio_port_pins_t pin) { \ + struct kscan_gpio_irq_callback_##n *data = \ + CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ + kscan_gpio_disable_interrupts_##n(data->dev); \ + COND_CODE_0(DT_INST_PROP(n, debounce_period), \ + ({ k_work_submit(data->work); }), ({ \ + k_delayed_work_cancel(data->work); \ + k_delayed_work_submit( \ + data->work, K_MSEC(DT_INST_PROP(n, debounce_period))); \ + })) \ + })) \ + \ static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \ .rows = {[INST_MATRIX_ROWS(n) - 1] = NULL}, .cols = {[INST_MATRIX_COLS(n) - 1] = NULL}}; \ static int kscan_gpio_configure_##n(struct device *dev, kscan_callback_t callback) { \ @@ -204,24 +207,25 @@ static int kscan_gpio_config_interrupts(struct device **devices, return 0; \ }; \ static int kscan_gpio_enable_##n(struct device *dev) { \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ - (int err = kscan_gpio_enable_interrupts_##n(dev); \ - if (err) { return err; } return kscan_gpio_read_##n(dev);), \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (struct kscan_gpio_data_##n *data = dev->driver_data; \ - k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); return 0;)) \ + k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10)); return 0;), \ + (int err = kscan_gpio_enable_interrupts_##n(dev); \ + if (err) { return err; } return kscan_gpio_read_##n(dev);)) \ }; \ static int kscan_gpio_disable_##n(struct device *dev) { \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ - (return kscan_gpio_disable_interrupts_##n(dev);), \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (struct kscan_gpio_data_##n *data = dev->driver_data; \ - k_timer_stop(&data->poll_timer); return 0;)) \ + k_timer_stop(&data->poll_timer); return 0;), \ + (return kscan_gpio_disable_interrupts_##n(dev);)) \ }; \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ (static void kscan_gpio_timer_handler(struct k_timer *timer) { \ struct kscan_gpio_data_##n *data = \ CONTAINER_OF(timer, struct kscan_gpio_data_##n, poll_timer); \ k_work_submit(&data->work.work); \ - })) \ + }), \ + ()) \ static int kscan_gpio_init_##n(struct device *dev) { \ struct kscan_gpio_data_##n *data = dev->driver_data; \ int err; \ @@ -267,8 +271,8 @@ static int kscan_gpio_config_interrupts(struct device **devices, } \ } \ data->dev = dev; \ - COND_CODE_0(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ - (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);)) \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \ + (k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \ (COND_CODE_0(DT_INST_PROP(n, debounce_period), (k_work_init), (k_delayed_work_init)))( \ &data->work, kscan_gpio_work_handler_##n); \ return 0; \ diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index 05fd65c8..a403d35d 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -18,4 +18,4 @@ defines these aliases up front. #define BT_CLR BT_CLR_CMD 0 #define BT_NXT BT_NXT_CMD 0 #define BT_PRV BT_PRV_CMD 0 -#define BT_SEL BT_SEL_CMD \ No newline at end of file +#define BT_SEL BT_SEL_CMD diff --git a/app/src/power.c b/app/src/power.c new file mode 100644 index 00000000..73b3f123 --- /dev/null +++ b/app/src/power.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +#include + +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include +#include +#include +#include + +static u32_t power_last_uptime; + +#define MAX_IDLE_MS CONFIG_ZMK_IDLE_SLEEP_TIMEOUT + +bool is_usb_power_present() { +#ifdef CONFIG_USB + enum usb_dc_status_code usb_status = zmk_usb_get_status(); + switch (usb_status) { + case USB_DC_DISCONNECTED: + case USB_DC_UNKNOWN: + return false; + default: + return true; + } +#else + return false; +#endif /* CONFIG_USB */ +} + +enum power_states sys_pm_policy_next_state(s32_t ticks) { +#ifdef CONFIG_SYS_POWER_DEEP_SLEEP_STATES +#ifdef CONFIG_HAS_SYS_POWER_STATE_DEEP_SLEEP_1 + s32_t current = k_uptime_get(); + if (power_last_uptime > 0 && !is_usb_power_present() && + current - power_last_uptime > MAX_IDLE_MS) { + return SYS_POWER_STATE_DEEP_SLEEP_1; + } +#endif /* CONFIG_HAS_SYS_POWER_STATE_DEEP_SLEEP_1 */ +#endif /* CONFIG_SYS_POWER_DEEP_SLEEP_STATES */ + + return SYS_POWER_STATE_ACTIVE; +} + +int power_event_listener(const struct zmk_event_header *eh) { + power_last_uptime = k_uptime_get(); + + return 0; +} + +int power_init() { + power_last_uptime = k_uptime_get(); + + return 0; +} + +ZMK_LISTENER(power, power_event_listener); +ZMK_SUBSCRIPTION(power, position_state_changed); +ZMK_SUBSCRIPTION(power, sensor_event); + +SYS_INIT(power_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); \ No newline at end of file From d5d8d79a76a9fbe65981d4f5455097e5258d1564 Mon Sep 17 00:00:00 2001 From: David Barr Date: Wed, 7 Oct 2020 16:23:59 +0100 Subject: [PATCH 135/227] Update cradio_right.overlay --- app/boards/shields/cradio/cradio_right.overlay | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/boards/shields/cradio/cradio_right.overlay b/app/boards/shields/cradio/cradio_right.overlay index 09efc53b..232d7d43 100644 --- a/app/boards/shields/cradio/cradio_right.overlay +++ b/app/boards/shields/cradio/cradio_right.overlay @@ -9,7 +9,3 @@ &default_transform { col-offset = <17>; }; - -&bt_unpair_combo { - key-positions = <21 32>; -}; From 2300ce306afadebd5f1987acf8ded6ac228f68e8 Mon Sep 17 00:00:00 2001 From: Ben Huddleston <40238853+BenHuddleston@users.noreply.github.com> Date: Wed, 7 Oct 2020 22:25:21 +0100 Subject: [PATCH 136/227] Correct typo in previous profile behaviour binding in bluetooth.md --- docs/docs/behavior/bluetooth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/behavior/bluetooth.md b/docs/docs/behavior/bluetooth.md index f802a9a2..8bde71bf 100644 --- a/docs/docs/behavior/bluetooth.md +++ b/docs/docs/behavior/bluetooth.md @@ -66,7 +66,7 @@ The bluetooth behavior completes an bluetooth action given on press. 1. Behavior binding to select the previous profile: ``` - &bt BT_NXT + &bt BT_PRV ``` 1. Behavior binding to select the 2nd profile (passed parameters are [zero based](https://en.wikipedia.org/wiki/Zero-based_numbering)): From f3eaa7e4247321042618a732596f842e5bb104da Mon Sep 17 00:00:00 2001 From: Kellen Carey Date: Wed, 7 Oct 2020 20:40:04 -0700 Subject: [PATCH 137/227] working shield, need to improve default keymap --- app/boards/shields/microdox/Kconfig.defconfig | 58 +++++++++++++++ app/boards/shields/microdox/Kconfig.shield | 9 +++ .../shields/microdox/boards/nice_nano.overlay | 29 ++++++++ app/boards/shields/microdox/microdox.conf | 6 ++ app/boards/shields/microdox/microdox.dtsi | 71 +++++++++++++++++++ app/boards/shields/microdox/microdox.keymap | 57 +++++++++++++++ .../shields/microdox/microdox_left.conf | 2 + .../shields/microdox/microdox_left.overlay | 22 ++++++ .../shields/microdox/microdox_right.conf | 2 + .../shields/microdox/microdox_right.overlay | 26 +++++++ 10 files changed, 282 insertions(+) create mode 100644 app/boards/shields/microdox/Kconfig.defconfig create mode 100644 app/boards/shields/microdox/Kconfig.shield create mode 100644 app/boards/shields/microdox/boards/nice_nano.overlay create mode 100644 app/boards/shields/microdox/microdox.conf create mode 100644 app/boards/shields/microdox/microdox.dtsi create mode 100644 app/boards/shields/microdox/microdox.keymap create mode 100644 app/boards/shields/microdox/microdox_left.conf create mode 100644 app/boards/shields/microdox/microdox_left.overlay create mode 100644 app/boards/shields/microdox/microdox_right.conf create mode 100644 app/boards/shields/microdox/microdox_right.overlay diff --git a/app/boards/shields/microdox/Kconfig.defconfig b/app/boards/shields/microdox/Kconfig.defconfig new file mode 100644 index 00000000..218443f9 --- /dev/null +++ b/app/boards/shields/microdox/Kconfig.defconfig @@ -0,0 +1,58 @@ + +if SHIELD_MICRODOX_LEFT + +config ZMK_KEYBOARD_NAME + default "Microdox Left" + +endif + + +if SHIELD_MICRODOX_RIGHT + +config ZMK_KEYBOARD_NAME + default "Microdox Right" + +endif + +if SHIELD_MICRODOX_LEFT || SHIELD_MICRODOX_RIGHT + +config ZMK_SPLIT + default y + +if ZMK_DISPLAY + +config I2C + default y + +config SSD1306 + default y + +config SSD1306_REVERSE_MODE + default y + +endif # ZMK_DISPLAY + +if LVGL + +config LVGL_HOR_RES + default 128 + +config LVGL_VER_RES + default 32 + +config LVGL_VDB_SIZE + default 64 + +config LVGL_DPI + default 148 + +config LVGL_BITS_PER_PIXEL + default 1 + +choice LVGL_COLOR_DEPTH + default LVGL_COLOR_DEPTH_1 +endchoice + +endif # LVGL + +endif diff --git a/app/boards/shields/microdox/Kconfig.shield b/app/boards/shields/microdox/Kconfig.shield new file mode 100644 index 00000000..7d7148de --- /dev/null +++ b/app/boards/shields/microdox/Kconfig.shield @@ -0,0 +1,9 @@ +# Copyright (c) 2020 Pete Johanson +# Copyright (c) 2020 Kellen Carey +# SPDX-License-Identifier: MIT + +config SHIELD_MICRODOX_LEFT + def_bool $(shields_list_contains,microdox_left) + +config SHIELD_MICRODOX_RIGHT + def_bool $(shields_list_contains,microdox_right) diff --git a/app/boards/shields/microdox/boards/nice_nano.overlay b/app/boards/shields/microdox/boards/nice_nano.overlay new file mode 100644 index 00000000..c7c3eb8e --- /dev/null +++ b/app/boards/shields/microdox/boards/nice_nano.overlay @@ -0,0 +1,29 @@ +&spi1 { + compatible = "nordic,nrf-spi"; + /* Cannot be used together with i2c0. */ + status = "okay"; + mosi-pin = <6>; + // Unused pins, needed for SPI definition, but not used by the ws2812 driver itself. + sck-pin = <5>; + miso-pin = <7>; + + led_strip: ws2812@0 { + compatible = "worldsemi,ws2812-spi"; + label = "SK6812mini"; + + /* SPI */ + reg = <0>; /* ignored, but necessary for SPI bindings */ + spi-max-frequency = <4000000>; + + /* WS2812 */ + chain-length = <6>; /* There are per-key RGB, but the first 6 are underglow */ + spi-one-frame = <0x70>; + spi-zero-frame = <0x40>; + }; +}; + +/ { + chosen { + zmk,underglow = &led_strip; + }; +}; diff --git a/app/boards/shields/microdox/microdox.conf b/app/boards/shields/microdox/microdox.conf new file mode 100644 index 00000000..b79385bd --- /dev/null +++ b/app/boards/shields/microdox/microdox.conf @@ -0,0 +1,6 @@ +# Uncomment the following lines to enable the Corne RGB Underglow +# ZMK_RGB_UNDERGLOW=y +# CONFIG_WS2812_STRIP=y + +# Uncomment the following line to enable the Corne OLED Display +# CONFIG_ZMK_DISPLAY=y diff --git a/app/boards/shields/microdox/microdox.dtsi b/app/boards/shields/microdox/microdox.dtsi new file mode 100644 index 00000000..bf7950df --- /dev/null +++ b/app/boards/shields/microdox/microdox.dtsi @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2020 Kellen Carey + * + * SPDX-License-Identifier: MIT + */ + +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <10>; + rows = <4>; +// | SW1 | SW2 | SW3 | SW4 | SW5 | | SW5 | SW4 | SW3 | SW2 | SW1 | +// | SW6 | SW7 | SW8 | SW9 | SW10 | | SW10 | SW9 | SW8 | SW7 | SW6 | +// | SW11 | SW12 | SW13 | SW14 | SW15 | | SW15 | SW14 | SW13 | SW12 | SW11 | +// | SW16 | SW17 | SW18 | | SW18 | SW17 | SW16 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) + RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro_d 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 10 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 9 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; + + bt_unpair_combo: bt_unpair_combo { + compatible = "zmk,bt-unpair-combo"; + }; + + // TODO: per-key RGB node(s)? +}; + +&pro_micro_i2c { + status = "okay"; + + oled: ssd1306@3c { + compatible = "solomon,ssd1306fb"; + reg = <0x3c>; + label = "DISPLAY"; + width = <128>; + height = <32>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <31>; + segment-remap; + com-invdir; + com-sequential; + prechargep = <0x22>; + }; +}; diff --git a/app/boards/shields/microdox/microdox.keymap b/app/boards/shields/microdox/microdox.keymap new file mode 100644 index 00000000..fa43a637 --- /dev/null +++ b/app/boards/shields/microdox/microdox.keymap @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include + +/ { + keymap { + compatible = "zmk,keymap"; + + default_layer { +// ----------------------------------------------------------------------------------------- +// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | +// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | +// | SHFT | Z | X | C | V | B | | N | M | , | . | / | SHFT | +// | GUI | LWR | SPC | | ENT | RSE | ALT | + bindings = < + &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P + &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN + &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH + &kp LGUI &mo 1 &kp SPC &kp RET &mo 2 &kp RALT + >; + }; + lower_layer { +// ----------------------------------------------------------------------------------------- +// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | +// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | +// | SHFT | | | | | | | | | | | | | +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 + &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LARW &kp DARW &kp UARW &kp RARW &trans + &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans + &kp LGUI &trans &kp SPC &kp RET &trans &kp RALT + >; + }; + + raise_layer { +// ----------------------------------------------------------------------------------------- +// | ESC | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | +// | CTRL | | | | | | | - | = | { | } | "|" | ` | +// | SHFT | | | | | | | _ | + | [ | ] | \ | ~ | // TODO: Fix this row when &mkp is committed +// | GUI | | SPC | | ENT | | ALT | + bindings = < + &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN + &trans &trans &trans &trans &trans &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans &trans &kp BSLH + &kp LGUI &trans &kp SPC &kp RET &trans &kp RALT + >; + }; + }; +}; + diff --git a/app/boards/shields/microdox/microdox_left.conf b/app/boards/shields/microdox/microdox_left.conf new file mode 100644 index 00000000..1e028a78 --- /dev/null +++ b/app/boards/shields/microdox/microdox_left.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y diff --git a/app/boards/shields/microdox/microdox_left.overlay b/app/boards/shields/microdox/microdox_left.overlay new file mode 100644 index 00000000..0a3f823a --- /dev/null +++ b/app/boards/shields/microdox/microdox_left.overlay @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2020 Kellen Carey + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox.dtsi" + +&kscan0 { + col-gpios + = <&pro_micro_a 3 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 2 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> + ; +}; + +&bt_unpair_combo { + key-positions = <0 38>; +}; diff --git a/app/boards/shields/microdox/microdox_right.conf b/app/boards/shields/microdox/microdox_right.conf new file mode 100644 index 00000000..990cf7c0 --- /dev/null +++ b/app/boards/shields/microdox/microdox_right.conf @@ -0,0 +1,2 @@ +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL=y diff --git a/app/boards/shields/microdox/microdox_right.overlay b/app/boards/shields/microdox/microdox_right.overlay new file mode 100644 index 00000000..2638a398 --- /dev/null +++ b/app/boards/shields/microdox/microdox_right.overlay @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2020 Kellen Carey + * + * SPDX-License-Identifier: MIT + */ + +#include "microdox.dtsi" + +&default_transform { + col-offset = <5>; +}; + +&kscan0 { + col-gpios + = <&pro_micro_d 15 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 2 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 3 GPIO_ACTIVE_HIGH> + ; +}; + +&bt_unpair_combo { + key-positions = <9 35>; +}; From ca29c40206031f95525c29750650013efc0e56f1 Mon Sep 17 00:00:00 2001 From: Kellen Carey Date: Wed, 7 Oct 2020 21:22:08 -0700 Subject: [PATCH 138/227] clean up keymap --- app/boards/shields/microdox/microdox.keymap | 52 +++++++++++++-------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/app/boards/shields/microdox/microdox.keymap b/app/boards/shields/microdox/microdox.keymap index fa43a637..916141c7 100644 --- a/app/boards/shields/microdox/microdox.keymap +++ b/app/boards/shields/microdox/microdox.keymap @@ -14,37 +14,37 @@ default_layer { // ----------------------------------------------------------------------------------------- -// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP | -// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' | -// | SHFT | Z | X | C | V | B | | N | M | , | . | / | SHFT | -// | GUI | LWR | SPC | | ENT | RSE | ALT | +// | Q | W | E | R | T | | Y | U | I | O | P | +// | A | S | D | F | G | | H | J | K | L | ; | +// | Z | X | C | V | B | | N | M | , | . | / | +// | GUI | NAV | SHFT | | SPC | SYM | ALT | bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH - &kp LGUI &mo 1 &kp SPC &kp RET &mo 2 &kp RALT + &kp LGUI &mo 1 &kp LSFT &kp SPC &mo 2 &kp RALT >; }; - lower_layer { + nav_layer { // ----------------------------------------------------------------------------------------- -// | ESC | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | BKSP | -// | BTCLR| BT1 | BT2 | BT3 | BT4 | BT5 | | LFT | DWN | UP | RGT | | | -// | SHFT | | | | | | | | | | | | | -// | GUI | | SPC | | ENT | | ALT | +// | | | ESC | ~ | | | TAB | HOME | UP | END | DEL | +// | | GUI | ALT | CTRL | NUM | | / | LEFT | DOWN | RGT | BKSP | +// | | | | | | | \ | ENT | | | | +// | | | | | | | | bindings = < - &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 - &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp LARW &kp DARW &kp UARW &kp RARW &trans - &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans - &kp LGUI &trans &kp SPC &kp RET &trans &kp RALT + &trans &trans &kp ESC &kp TILD &trans &kp TAB &kp HOME &kp UARW &kp END &kp DEL + &trans &kp GUI &kp RALT &kp LCTL &mo 3 &kp FSLH &kp LARW &kp DARW &kp RARW &kp BKSP + &trans &trans &trans &trans &trans &kp BSLH &kp RET &trans &trans &trans + &trans &trans &trans &trans &trans &trans >; }; - raise_layer { + sym_layer { // ----------------------------------------------------------------------------------------- -// | ESC | ! | @ | # | $ | % | | ^ | & | * | ( | ) | BKSP | -// | CTRL | | | | | | | - | = | { | } | "|" | ` | -// | SHFT | | | | | | | _ | + | [ | ] | \ | ~ | // TODO: Fix this row when &mkp is committed -// | GUI | | SPC | | ENT | | ALT | +// | ! | @ | # | $ | % | | ^ | & | * | ( | ) | +// | | | | | | | - | = | { | } | "|" | +// | | | | | | | _ | + | [ | ] | \ | +// | GUI | | SPC | | ENT | | ALT | bindings = < &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &trans &trans &trans &trans &trans &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp PIPE @@ -52,6 +52,20 @@ &kp LGUI &trans &kp SPC &kp RET &trans &kp RALT >; }; + + num_layer { +// ----------------------------------------------------------------------------------------- +// | | | | | | | A | 7 | 8 | 9 | D | +// | | | | | | | B | 4 | 5 | 6 | E | +// | | | | | | | C | 1 | 2 | 3 | F | +// | | | | | 0 | . | | + bindings = < + &trans &trans &trans &trans &trans &kp A &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp D + &trans &trans &trans &trans &trans &kp B &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp E + &trans &trans &trans &trans &trans &kp C &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp F + &trans &trans &trans &kp NUM_0 &kp DOT &trans + >; + }; }; }; From 426b25892f2fd6c569b9d0b983fd7fbaff6c9d93 Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:09:35 +0100 Subject: [PATCH 139/227] rename gpio to direct polling --- app/boards/shields/cradio/Kconfig.defconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig index 46799b9e..43509a47 100644 --- a/app/boards/shields/cradio/Kconfig.defconfig +++ b/app/boards/shields/cradio/Kconfig.defconfig @@ -4,7 +4,7 @@ config ZMK_KEYBOARD_NAME default "cradio" -config ZMK_KSCAN_GPIO_POLLING +config ZMK_KSCAN_DIRECT_POLLING default y From 7d582b6b8e16cf64cadf27dacba050dfb88d543a Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:11:01 +0100 Subject: [PATCH 140/227] remove dupe copyright --- app/boards/shields/cradio/cradio_left.overlay | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/boards/shields/cradio/cradio_left.overlay b/app/boards/shields/cradio/cradio_left.overlay index 6caf8e3d..61fc3bd7 100644 --- a/app/boards/shields/cradio/cradio_left.overlay +++ b/app/boards/shields/cradio/cradio_left.overlay @@ -1,6 +1,4 @@ /* - * Copyright (c) 2020 Pete Johanson - * * Copyright (c) 2020 The ZMK Contributors */ From 95b94009a9b3b9b953220ab48f0276fc5a083499 Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:11:40 +0100 Subject: [PATCH 141/227] remove dupe copyright --- app/boards/shields/cradio/cradio_right.overlay | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/boards/shields/cradio/cradio_right.overlay b/app/boards/shields/cradio/cradio_right.overlay index 232d7d43..1c06006f 100644 --- a/app/boards/shields/cradio/cradio_right.overlay +++ b/app/boards/shields/cradio/cradio_right.overlay @@ -1,6 +1,4 @@ /* - * Copyright (c) 2020 Pete Johanson - * * Copyright (c) 2020 The ZMK Contributors */ From 24e73f68610a9a4a1497c6e7737b615d6181836b Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:12:04 +0100 Subject: [PATCH 142/227] Update cradio.dtsi --- app/boards/shields/cradio/cradio.dtsi | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi index 582f58a4..d32d2ed3 100644 --- a/app/boards/shields/cradio/cradio.dtsi +++ b/app/boards/shields/cradio/cradio.dtsi @@ -1,6 +1,4 @@ /* - * Copyright (c) 2020 Pete Johanson - * * Copyright (c) 2020 The ZMK Contributors */ From a3cdab9e9f9940a854ec68e60622443ae376183e Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:14:46 +0100 Subject: [PATCH 143/227] update header --- app/boards/shields/cradio/cradio.keymap | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/boards/shields/cradio/cradio.keymap b/app/boards/shields/cradio/cradio.keymap index c46468dd..1d11cfd6 100644 --- a/app/boards/shields/cradio/cradio.keymap +++ b/app/boards/shields/cradio/cradio.keymap @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + + #include #include From 55c1f51b3147490d994d846907e9fd99039e4e8b Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:16:08 +0100 Subject: [PATCH 144/227] update header --- app/boards/shields/cradio/cradio_right.overlay | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/boards/shields/cradio/cradio_right.overlay b/app/boards/shields/cradio/cradio_right.overlay index 1c06006f..fea59c23 100644 --- a/app/boards/shields/cradio/cradio_right.overlay +++ b/app/boards/shields/cradio/cradio_right.overlay @@ -1,5 +1,7 @@ /* - * Copyright (c) 2020 The ZMK Contributors + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT */ #include "cradio.dtsi" From eeac54e9a4f24e5a455cbc52ba0930a10d2bcfc9 Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:16:28 +0100 Subject: [PATCH 145/227] Update cradio_left.overlay --- app/boards/shields/cradio/cradio_left.overlay | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/boards/shields/cradio/cradio_left.overlay b/app/boards/shields/cradio/cradio_left.overlay index 61fc3bd7..cac95757 100644 --- a/app/boards/shields/cradio/cradio_left.overlay +++ b/app/boards/shields/cradio/cradio_left.overlay @@ -1,4 +1,5 @@ /* - * Copyright (c) 2020 The ZMK Contributors + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT */ - From a629aa0b42caf6a86152ef5eedc6160b90200627 Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:17:53 +0100 Subject: [PATCH 146/227] Update Kconfig.defconfig --- app/boards/shields/cradio/Kconfig.defconfig | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig index 43509a47..1043c7e9 100644 --- a/app/boards/shields/cradio/Kconfig.defconfig +++ b/app/boards/shields/cradio/Kconfig.defconfig @@ -1,8 +1,20 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT +if SHIELD_CRADIO_LEFT + config ZMK_KEYBOARD_NAME - default "cradio" + default "Cradio Left" + +endif + + +if SHIELD_CRADIO_RIGHT + +config ZMK_KEYBOARD_NAME + default "Cradio Right" + +endif config ZMK_KSCAN_DIRECT_POLLING default y From ad77df59897ae973824377373665a4fdc6542d3c Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:20:22 +0100 Subject: [PATCH 147/227] capital C --- app/boards/shields/cradio/Kconfig.defconfig | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig index 1043c7e9..5f8bb80d 100644 --- a/app/boards/shields/cradio/Kconfig.defconfig +++ b/app/boards/shields/cradio/Kconfig.defconfig @@ -1,20 +1,8 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT -if SHIELD_CRADIO_LEFT - config ZMK_KEYBOARD_NAME - default "Cradio Left" - -endif - - -if SHIELD_CRADIO_RIGHT - -config ZMK_KEYBOARD_NAME - default "Cradio Right" - -endif + default "Cradio" config ZMK_KSCAN_DIRECT_POLLING default y From 2b09174ec1a171e043018cbe28e47d86025ce1de Mon Sep 17 00:00:00 2001 From: David Barr Date: Thu, 8 Oct 2020 11:22:34 +0100 Subject: [PATCH 148/227] update header again based on corne --- app/boards/shields/cradio/cradio.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi index d32d2ed3..ab22e929 100644 --- a/app/boards/shields/cradio/cradio.dtsi +++ b/app/boards/shields/cradio/cradio.dtsi @@ -1,5 +1,7 @@ /* - * Copyright (c) 2020 The ZMK Contributors + * Copyright (c) 2020 Pete Johanson + * + * SPDX-License-Identifier: MIT */ #include From a8d48b043d0913e2f4e15d34547989d78b1b8088 Mon Sep 17 00:00:00 2001 From: Tyler Walker Date: Thu, 8 Oct 2020 18:42:55 -0400 Subject: [PATCH 149/227] add benign uf2 transfer error for macOS to troubleshooting --- .../assets/troubleshooting/filetransfer/mac.png | Bin 0 -> 26499 bytes docs/docs/troubleshooting.md | 4 ++++ 2 files changed, 4 insertions(+) create mode 100644 docs/docs/assets/troubleshooting/filetransfer/mac.png diff --git a/docs/docs/assets/troubleshooting/filetransfer/mac.png b/docs/docs/assets/troubleshooting/filetransfer/mac.png new file mode 100644 index 0000000000000000000000000000000000000000..f28ca8d78369ec7b4cdfb2fd20f7cd3032cb454c GIT binary patch literal 26499 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 K-1SHt4qw0YvK zKP>!>Xk%-u8faH#=;zm1V%iM3=u(S0wsZ+9-v!N8H+eHrrFg`bj*cYPrx848hQDLrtq4~f6++39!a9?5Bga1X% zqD%_n0EaFQOaE=>{{#|BI0~EjN!h=nnZGPSnGiHr^grg~13EZ7G|tyIU!$!TJ0ZqE3BHxTVl=46jH4Zr#JzuK(c!5F{yd1}h;+B~^Z^GN4o{x&8Hj1~{?{rO$_1&eMp1Cruxh>6U+IdW*-AEY z=6!1UQ~mcg`}^}j=AY{TFXsq25+SD<0f%&6D@2K5b)R#~WgnbiozD s6yremh$rlNrBw!%Hq(IW@cR|IqqMH+OVD`db!TWrIaS%x2j(IF2R8r@?f?J) literal 0 HcmV?d00001 diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index deb89b64..2e5e9899 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -19,6 +19,10 @@ Variations of the warnings shown below occur when flashing the `.uf2` | :-------------------------------------------------------------------------------: | | An example of the file transfer error on Linux | +| ![Example Error Screen](../docs/assets/troubleshooting/filetransfer/mac.png) | +| :-------------------------------------------------------------------------------: | +| An example of the file transfer error on MacOS | + ### CMake Error From ea05df029086a47d0b0e33fe882801009e3b6872 Mon Sep 17 00:00:00 2001 From: Kevin Date: Thu, 8 Oct 2020 21:44:32 -0700 Subject: [PATCH 150/227] docs: Added link to clarify where to add sensor-bindings code --- docs/docs/dev-guide-new-shield.md | 10 +++++++--- docs/docs/feature/encoders.md | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 01aad30c..1ba572c5 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -238,7 +238,6 @@ If building locally for split boards, you may need to add these lines to the spe In your device tree file you will need to add the following lines to define the encoder sensor: - ``` left_encoder: encoder_left { compatible = "alps,ec11"; @@ -248,6 +247,7 @@ left_encoder: encoder_left { resolution = <4>; }; ``` + Here you will have to replace PIN_A and PIN_B with the appropriate pins that your PCB utilizes for the encoder(s). For keyboards that use the Pro Micro or any of the Pro Micro replacements, Sparkfun's [Pro Micro Hookup Guide](https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/hardware-overview-pro-micro) has a pinout diagram that can be useful to determine the right pins. Reference either the blue numbers labeled "Arduino" (digital pins) or the green numbers labeled "Analog" (analog pins). For pins that are labeled as both digital and analog, refer to your specific board's .dtsi file to determine how you should refer to that pin. Add additional encoders as necessary by duplicating the above lines, replacing `left` with whatever you would like to call your encoder, and updating the pins. Note that support for peripheral (right) side sensors over BLE is still in progress. @@ -279,12 +279,15 @@ For split keyboards, make sure to add left hand encoders to the left .overlay fi -Add the following line to your keymap file to add default encoder behavior bindings: +Add the following line to each layer of your keymap file to add default encoder behavior bindings: ``` sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD>; ``` -Add additional bindings as necessary to match the default number of encoders on your board. See the [Encoders](/docs/feature/encoders) and [Keymap](/docs/feature/keymaps) feature documentation for more details. + +This should be placed after the regular key bindings but within the layer (see the [Default Keymap section](/docs/dev-guide-new-shield#default-keymap) above for an example of where). + +Add additional bindings as necessary to match the default number of encoders on your board. Details on the syntax can be found in the [Encoders](/docs/feature/encoders) and [Keymap](/docs/feature/keymaps) feature documentation. @@ -333,6 +336,7 @@ jobs: - board: proton_c shield: clueboard_california ``` + :::note Notice that both the left and right halves of a split board need to be added to the list of shields for proper error checking. :::note diff --git a/docs/docs/feature/encoders.md b/docs/docs/feature/encoders.md index 38ff9d31..9caccc2f 100644 --- a/docs/docs/feature/encoders.md +++ b/docs/docs/feature/encoders.md @@ -41,4 +41,4 @@ Here, the left encoder is configured to control volume up and down while the rig ## Adding Encoder Support -See the [New Keyboard Shield](/docs/dev-guide-new-shield) documentation for how to add or modify additional encoders to your shield. +See the [New Keyboard Shield](/docs/dev-guide-new-shield#encoders) documentation for how to add or modify additional encoders to your shield. From 59a804f751a2eec2b62b91fbde1f69535376d63c Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 9 Oct 2020 01:05:50 -0400 Subject: [PATCH 151/227] fix(actions): Upload UF2 for all compatible boards --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 454ab796..60c337de 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,7 +75,7 @@ jobs: args: 'build "-s app -b ${{ matrix.board }} -- -DSHIELD=${{ matrix.shield }}"' - name: Archive Build uses: actions/upload-artifact@v2 - if: ${{ matrix.board == 'nice_nano' }} + if: ${{ matrix.board != 'proton_c' }} with: name: "${{ matrix.board }}-${{ matrix.shield }}-zmk-uf2" path: build/zephyr/zmk.uf2 From a9ec1148e50ff0601f82c9eb55b90c33e7c70dab Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Thu, 8 Oct 2020 22:16:53 -0700 Subject: [PATCH 152/227] Added -DZMK_CONFIG Documentation --- docs/docs/dev-build.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/docs/dev-build.md b/docs/docs/dev-build.md index 816468e2..a7c1cd91 100644 --- a/docs/docs/dev-build.md +++ b/docs/docs/dev-build.md @@ -84,6 +84,19 @@ west build -d build/right -b nice_nano -- -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. +### Building from `zmk-config` Folder + +Instead of building .uf2 files using the default keymap and config files, you can build directly from your [`zmk-config` folder](user-setup.md) by adding +`-DZMK_CONFIG="C:/the/absolute/path/config"` to your `west build` command. **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: + +``` +west build -b nice_nano -- -DSHIELD=kyria_left -DZMK_CONFIG="C:/Users/myUser/Documents/Github/zmk-config/config" +``` + + ## Flashing Once built, the previously supplied parameters will be remembered so you can run the following to flash your From 49315c2f6df6c17966dafa5a97668774a6a65bb0 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Thu, 8 Oct 2020 22:18:53 -0700 Subject: [PATCH 153/227] Addressing Issue #181 --- docs/docs/dev-guide-new-shield.md | 135 ++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 01aad30c..ee489155 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -21,6 +21,10 @@ The high level steps are: It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.3.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing. +:::note +ZMK support for split keyboards requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place. +::: + ## New Shield Directory Shields for Zephyr applications go into the `boards/shields/` directory; since ZMK's Zephyr application lives in the `app/` subdirectory of the repository, that means the new shield directory should be: @@ -45,6 +49,16 @@ config SHIELD_MY_BOARD This will make sure the new configuration `SHIELD_MY_BOARD` is set to true whenever `my_board` is added as a shield in your build. + +**For split boards**, you will need to add configurations for the left and right sides. +``` +config SHIELD_MY_BOARD_LEFT + def_bool $(shields_list_contains,my_board_left) + +config SHIELD_MY_BOARD_RIGHT + def_bool $(shields_list_contains,my_board_right) +``` + ### Kconfig.defconfig The `Kconfig.defconfig` file is where overrides for various configuration settings @@ -63,6 +77,26 @@ config ZMK_KEYBOARD_NAME endif ``` + +Similarly to defining the halves of a split board in `Kconfig.shield` it is important to set the `ZMK_KEYBOARD_NAME` for each half of a split keyboard. + +``` +if SHIELD_MY_BOARD_LEFT + +config ZMK_KEYBOARD_NAME + default "My Awesome Keyboard Left" + +endif + +if SHIELD_MY_BOARD_RIGHT + +config ZMK_KEYBOARD_NAME + default "My Awesome Keyboard Right" + +endif +``` + + ## Shield Overlay ![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) @@ -98,6 +132,74 @@ this might look something like: }; ``` +:::note +For split keyboards, it is preferred to define only the `col-gpios` or `row-gpios` in the common shield .dtsi, depending on the diode-direction. +For `col2row` directed boards like the iris, a sample kscan in the .dtsi folder would look like this: + +``` +kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro_d 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + , <&pro_micro_d 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> + ; + + }; +``` + +The missing `col-gpios` would be defined in your `_left.overlay` and `_right.overlay` files. +Keep in mind that the mirrored position of the GPIOs means that the `col-gpios` will appear reversed when the .overlay files are compared to one another. +This is exemplified with the iris .overlay files. + +``` +// iris_left.overlay + +#include "iris.dtsi" // Notice that the main dtsi files are included in the overlay. + +&kscan0 { + col-gpios + = <&pro_micro_a 1 GPIO_ACTIVE_HIGH> + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> + , <&pro_micro_d 10 GPIO_ACTIVE_HIGH> + ; +}; +``` + +``` +// iris_right.overlay + +#include "iris.dtsi" + +&default_transform { // The matrix transform for this board is 6 columns over because the matrix on the left side is 6 columns wide. + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro_d 10 GPIO_ACTIVE_HIGH> //&pro_micro_a 1 in the left side + , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> //&pro_micro_a 0 in the left side + , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> //&pro_micro_d 15 in the left side + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> //&pro_micro_d 14 in the left side + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> //&pro_micro_d 16 in the left side + , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> //&pro_micro_d 10 in the left side + ; +}; + +``` + +Split keyboards, will often use [Matrix Transform](#optional-matrix-transform) to account for their thumb clusters and other oddities. + +::: + ## (Optional) Matrix Transform Internally ZMK translates all row/column events into "key position" events to maintain a consistent model that works no matter what any possible GPIO matrix may look like for a certain keyboard. This is particularly helpful when: @@ -289,6 +391,39 @@ Add additional bindings as necessary to match the default number of encoders on +## (Split Keyboards Only) .conf files + +While normal boards only have one .conf file that applies configuration characteristics to the entire board, split keyboards are unique in that they contain multiple .conf files +with different scopes. For example, a split board called `my_awesome_split_board` would have the following files: + +* `my_awesome_split_board.conf` - Configuration elements affect both halves +* `my_awesome_split_board_left.conf` - Configuration elements only affect left half +* `my_awesome_split_board_right.conf` - Configuration elements only affect right half + +The discrete .conf files for each half allows the user to define the central and peripheral sides of the split, like so: + +``` +// Central Half + +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y +``` + +``` +// Peripheral Half + +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y +``` + +Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep or _. + +``` +// Global .conf + +CONFIG_ZMK_SLEEP=y +``` + ## Testing Once you've fully created the new keyboard shield definition, From dbda99a3788fb27d258a7c5b9c8f56638f190d65 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Thu, 8 Oct 2020 22:19:26 -0700 Subject: [PATCH 154/227] Addressed Issue #181 --- docs/docs/dev-guide-new-shield.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index ee489155..b8f1a194 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -403,14 +403,14 @@ with different scopes. For example, a split board called `my_awesome_split_board The discrete .conf files for each half allows the user to define the central and peripheral sides of the split, like so: ``` -// Central Half +// Central Half (Usually the left side: my_awesome_split_board_left.conf) CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y ``` ``` -// Peripheral Half +// Peripheral Half (Usually the right side: my_awesome_split_board_right.conf) CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y @@ -419,7 +419,7 @@ CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep or _. ``` -// Global .conf +// my_awesome_split_board.conf CONFIG_ZMK_SLEEP=y ``` From c27d3c66f150a0adfa19a2dd6c2bd64544c261a7 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Thu, 8 Oct 2020 22:21:49 -0700 Subject: [PATCH 155/227] Removed blank space --- docs/docs/dev-guide-new-shield.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index b8f1a194..9c0a2651 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -416,7 +416,7 @@ CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y ``` -Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep or _. +Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep. ``` // my_awesome_split_board.conf From a58a8412c7335df27077cc9647444f014b6a094e Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Fri, 9 Oct 2020 08:15:38 -0700 Subject: [PATCH 156/227] Documented Issue #220 --- docs/docs/bond-reset.md | 4 ++-- docs/docs/troubleshooting.md | 13 +++++++++++++ docs/sidebars.js | 1 - 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/docs/bond-reset.md b/docs/docs/bond-reset.md index 1ba79ee0..504fd72a 100644 --- a/docs/docs/bond-reset.md +++ b/docs/docs/bond-reset.md @@ -1,7 +1,7 @@ --- id: bond-reset -title: Reset BLE Connections -sidebar_label: BLE Reset +title: Reset BLE Connections (DEPRECATED) +sidebar_label: BLE Reset (DEPRECATED) --- Known as a 'bond reset', each keyboard has a special key combination independent of the user defined key map which will diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index deb89b64..8dd12614 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -59,3 +59,16 @@ After opening the `.dts.pre.tmp:` and scrolling down to the | ![Healthy Keymap Temp](../docs/assets/troubleshooting/keymaps/healthyEDIT.png) | | :-------------------------------------------------------------------------------: | | A properly defined keymap with successful compilation. As shown in red, the corrected keycode (`&kp SPC`) references the proper Usage ID defined in the [USB HID Usage Tables](https://www.usb.org/document-library/hid-usage-tables-12)| + +### Split Keyboard Halves Unable to Pair + +The previous method of pairing split keyboard halves involved a **BLE Reset** with a specific combination of held keys that would remove all bluetooth profile information from the keyboard. +Since then, a much simpler procedure of performing a bluetooth reset for split keyboards has come about, without the need for any file modification: + +1. Log into Github and download the "settings clear" UF2 image from latest GH actions from the `main` of ZMK +1. Put both sides into bootloader mode +1. Flash both sides with the "settings clear" UF2 images from step 1. After, put both sides into bootloader mode again. +1. Flash the actual image for each half of the split keyboard + +After completing these steps, pair the halves of the split keyboard together by resetting them at the same time. Most commonly, this is done by grounding the reset pins +for each of your keyboard's microcontrollers or pressing the reset buttons at the same time. \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index ace7fa17..93ce2264 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -6,7 +6,6 @@ module.exports = { "faq", "user-setup", "customization", - "bond-reset", "troubleshooting" ], Features: [ From aca801d90ffcc12076244626dc0d4b239df25ab4 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Fri, 9 Oct 2020 08:19:08 -0700 Subject: [PATCH 157/227] Revert "Removed blank space" This reverts commit c27d3c66f150a0adfa19a2dd6c2bd64544c261a7. --- docs/docs/dev-guide-new-shield.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 9c0a2651..b8f1a194 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -416,7 +416,7 @@ CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y ``` -Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep. +Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep or _. ``` // my_awesome_split_board.conf From 429c9dc464c38bb0604a3ebe55151b451580d8ca Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Fri, 9 Oct 2020 08:19:40 -0700 Subject: [PATCH 158/227] Revert "Addressed Issue #181" This reverts commit dbda99a3788fb27d258a7c5b9c8f56638f190d65. --- docs/docs/dev-guide-new-shield.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index b8f1a194..ee489155 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -403,14 +403,14 @@ with different scopes. For example, a split board called `my_awesome_split_board The discrete .conf files for each half allows the user to define the central and peripheral sides of the split, like so: ``` -// Central Half (Usually the left side: my_awesome_split_board_left.conf) +// Central Half CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y ``` ``` -// Peripheral Half (Usually the right side: my_awesome_split_board_right.conf) +// Peripheral Half CONFIG_ZMK_SPLIT=y CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y @@ -419,7 +419,7 @@ CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep or _. ``` -// my_awesome_split_board.conf +// Global .conf CONFIG_ZMK_SLEEP=y ``` From e03b51fe2ea5dfbedcc7747ac64899b5d0999a04 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Fri, 9 Oct 2020 08:19:46 -0700 Subject: [PATCH 159/227] Revert "Addressing Issue #181" This reverts commit 49315c2f6df6c17966dafa5a97668774a6a65bb0. --- docs/docs/dev-guide-new-shield.md | 135 ------------------------------ 1 file changed, 135 deletions(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index ee489155..01aad30c 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -21,10 +21,6 @@ The high level steps are: It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.3.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing. -:::note -ZMK support for split keyboards requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place. -::: - ## New Shield Directory Shields for Zephyr applications go into the `boards/shields/` directory; since ZMK's Zephyr application lives in the `app/` subdirectory of the repository, that means the new shield directory should be: @@ -49,16 +45,6 @@ config SHIELD_MY_BOARD This will make sure the new configuration `SHIELD_MY_BOARD` is set to true whenever `my_board` is added as a shield in your build. - -**For split boards**, you will need to add configurations for the left and right sides. -``` -config SHIELD_MY_BOARD_LEFT - def_bool $(shields_list_contains,my_board_left) - -config SHIELD_MY_BOARD_RIGHT - def_bool $(shields_list_contains,my_board_right) -``` - ### Kconfig.defconfig The `Kconfig.defconfig` file is where overrides for various configuration settings @@ -77,26 +63,6 @@ config ZMK_KEYBOARD_NAME endif ``` - -Similarly to defining the halves of a split board in `Kconfig.shield` it is important to set the `ZMK_KEYBOARD_NAME` for each half of a split keyboard. - -``` -if SHIELD_MY_BOARD_LEFT - -config ZMK_KEYBOARD_NAME - default "My Awesome Keyboard Left" - -endif - -if SHIELD_MY_BOARD_RIGHT - -config ZMK_KEYBOARD_NAME - default "My Awesome Keyboard Right" - -endif -``` - - ## Shield Overlay ![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) @@ -132,74 +98,6 @@ this might look something like: }; ``` -:::note -For split keyboards, it is preferred to define only the `col-gpios` or `row-gpios` in the common shield .dtsi, depending on the diode-direction. -For `col2row` directed boards like the iris, a sample kscan in the .dtsi folder would look like this: - -``` -kscan0: kscan { - compatible = "zmk,kscan-gpio-matrix"; - label = "KSCAN"; - - diode-direction = "col2row"; - row-gpios - = <&pro_micro_d 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro_d 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro_d 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - , <&pro_micro_d 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> - ; - - }; -``` - -The missing `col-gpios` would be defined in your `_left.overlay` and `_right.overlay` files. -Keep in mind that the mirrored position of the GPIOs means that the `col-gpios` will appear reversed when the .overlay files are compared to one another. -This is exemplified with the iris .overlay files. - -``` -// iris_left.overlay - -#include "iris.dtsi" // Notice that the main dtsi files are included in the overlay. - -&kscan0 { - col-gpios - = <&pro_micro_a 1 GPIO_ACTIVE_HIGH> - , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> - , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> - , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> - , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> - , <&pro_micro_d 10 GPIO_ACTIVE_HIGH> - ; -}; -``` - -``` -// iris_right.overlay - -#include "iris.dtsi" - -&default_transform { // The matrix transform for this board is 6 columns over because the matrix on the left side is 6 columns wide. - col-offset = <6>; -}; - -&kscan0 { - col-gpios - = <&pro_micro_d 10 GPIO_ACTIVE_HIGH> //&pro_micro_a 1 in the left side - , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> //&pro_micro_a 0 in the left side - , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> //&pro_micro_d 15 in the left side - , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> //&pro_micro_d 14 in the left side - , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> //&pro_micro_d 16 in the left side - , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> //&pro_micro_d 10 in the left side - ; -}; - -``` - -Split keyboards, will often use [Matrix Transform](#optional-matrix-transform) to account for their thumb clusters and other oddities. - -::: - ## (Optional) Matrix Transform Internally ZMK translates all row/column events into "key position" events to maintain a consistent model that works no matter what any possible GPIO matrix may look like for a certain keyboard. This is particularly helpful when: @@ -391,39 +289,6 @@ Add additional bindings as necessary to match the default number of encoders on -## (Split Keyboards Only) .conf files - -While normal boards only have one .conf file that applies configuration characteristics to the entire board, split keyboards are unique in that they contain multiple .conf files -with different scopes. For example, a split board called `my_awesome_split_board` would have the following files: - -* `my_awesome_split_board.conf` - Configuration elements affect both halves -* `my_awesome_split_board_left.conf` - Configuration elements only affect left half -* `my_awesome_split_board_right.conf` - Configuration elements only affect right half - -The discrete .conf files for each half allows the user to define the central and peripheral sides of the split, like so: - -``` -// Central Half - -CONFIG_ZMK_SPLIT=y -CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y -``` - -``` -// Peripheral Half - -CONFIG_ZMK_SPLIT=y -CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y -``` - -Using the .conf file that affects both halves of a split board would be for circumstances like deep-sleep or _. - -``` -// Global .conf - -CONFIG_ZMK_SLEEP=y -``` - ## Testing Once you've fully created the new keyboard shield definition, From 7128808bbafd198a2d3b7275a9a029d4a58d5bc6 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Fri, 9 Oct 2020 08:19:50 -0700 Subject: [PATCH 160/227] Revert "Added -DZMK_CONFIG Documentation" This reverts commit a9ec1148e50ff0601f82c9eb55b90c33e7c70dab. --- docs/docs/dev-build.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/docs/docs/dev-build.md b/docs/docs/dev-build.md index a7c1cd91..816468e2 100644 --- a/docs/docs/dev-build.md +++ b/docs/docs/dev-build.md @@ -84,19 +84,6 @@ west build -d build/right -b nice_nano -- -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. -### Building from `zmk-config` Folder - -Instead of building .uf2 files using the default keymap and config files, you can build directly from your [`zmk-config` folder](user-setup.md) by adding -`-DZMK_CONFIG="C:/the/absolute/path/config"` to your `west build` command. **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: - -``` -west build -b nice_nano -- -DSHIELD=kyria_left -DZMK_CONFIG="C:/Users/myUser/Documents/Github/zmk-config/config" -``` - - ## Flashing Once built, the previously supplied parameters will be remembered so you can run the following to flash your From e53320a687a8b402fac3ed972a776993495a2f9a Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 9 Oct 2020 11:57:34 -0400 Subject: [PATCH 161/227] fix(docs): Remove hanging footnote. --- docs/docs/behavior/bluetooth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/behavior/bluetooth.md b/docs/docs/behavior/bluetooth.md index 8bde71bf..be0fb23c 100644 --- a/docs/docs/behavior/bluetooth.md +++ b/docs/docs/behavior/bluetooth.md @@ -24,7 +24,7 @@ Here is a table describing the command for each define: | Define | Action | | ------------ | ---------------------------------------------------------------------------------------------- | -| `BT_CLR_CMD` | Clear bond information between the keyboard and host for the selected profile [^1] | +| `BT_CLR_CMD` | Clear bond information between the keyboard and host for the selected profile. | | `BT_NXT_CMD` | Switch to the next profile, cycling through to the first one when the end is reached. | | `BT_PRV_CMD` | Switch to the previous profile, cycling through to the last one when the beginning is reached. | | `BT_SEL_CMD` | Select the 0-indexed profile by number. | From 01b0bad7a246ac9aef7aa170895dab5ae4790525 Mon Sep 17 00:00:00 2001 From: David Barr Date: Fri, 9 Oct 2020 17:05:09 +0100 Subject: [PATCH 162/227] update headers, spruce up keymap, streamline dtsi. --- app/boards/shields/cradio/Kconfig.defconfig | 2 +- app/boards/shields/cradio/cradio.dtsi | 23 +++++--------- app/boards/shields/cradio/cradio.keymap | 30 +++++++++++++++---- app/boards/shields/cradio/cradio_left.overlay | 4 ++- .../shields/cradio/cradio_right.overlay | 2 +- 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig index 5f8bb80d..43509a47 100644 --- a/app/boards/shields/cradio/Kconfig.defconfig +++ b/app/boards/shields/cradio/Kconfig.defconfig @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT config ZMK_KEYBOARD_NAME - default "Cradio" + default "cradio" config ZMK_KSCAN_DIRECT_POLLING default y diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi index ab22e929..1f2603c2 100644 --- a/app/boards/shields/cradio/cradio.dtsi +++ b/app/boards/shields/cradio/cradio.dtsi @@ -9,9 +9,9 @@ / { chosen { zmk,kscan = &kscan0; - zmk,matrix_transform = &default_transform; + //zmk,matrix_transform = &default_transform; }; - + default_transform: keymap_transform_0 { compatible = "zmk,matrix-transform"; columns = <34>; @@ -19,23 +19,13 @@ map = < RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,21) RC(0,20) RC(0,19) RC(0,18) RC(0,17) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,26) RC(0,25) RC(0,24) RC(0,23) RC(0,22) - RC(0,10)RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) + RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,31) RC(0,30) RC(0,29) RC(0,28) RC(0,27) RC(0,15) RC(0,16) RC(0,33) RC(0,32) >; kscan0: kscan { compatible = "zmk,kscan-gpio-direct"; label = "KSCAN"; - }; - - bt_unpair_combo: bt_unpair_combo { - compatible = "zmk,bt-unpair-combo"; - }; - - }; - }; - - &kscan0 { input-gpios = <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> @@ -55,6 +45,7 @@ , <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> , <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)> ; -}; - - + }; + }; + }; + diff --git a/app/boards/shields/cradio/cradio.keymap b/app/boards/shields/cradio/cradio.keymap index 1d11cfd6..487f6dcf 100644 --- a/app/boards/shields/cradio/cradio.keymap +++ b/app/boards/shields/cradio/cradio.keymap @@ -3,23 +3,41 @@ * * SPDX-License-Identifier: MIT */ - - + #include #include +#include / { keymap { compatible = "zmk,keymap"; - - default_layer { + + default_layer { bindings = < &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp A &kp S &kp D &kp F &kp G &kp H &kp J &kp K &kp L &kp SCLN &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH - &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 - >; + &mo 1 &kp LCTL &kp SPC &mo 2 + >; }; + upper_layer { + bindings = < + &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 + &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &kp H &kp J &kp K &kp L &kp SCLN + &kp LSFT &trans &trans &trans &trans &trans &trans &trans &trans &trans + &mo 1 &kp LCTL &kp SPC &mo 2 + >; + }; + + lower_layer { + bindings = < + &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN + &trans &trans &trans &trans &trans &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans &kp BSLH &kp TILD + &mo 1 &kp LCTL &kp SPC &mo 2 + >; + }; + }; }; diff --git a/app/boards/shields/cradio/cradio_left.overlay b/app/boards/shields/cradio/cradio_left.overlay index cac95757..6a3704a7 100644 --- a/app/boards/shields/cradio/cradio_left.overlay +++ b/app/boards/shields/cradio/cradio_left.overlay @@ -1,5 +1,7 @@ /* - * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ + +#include "cradio.dtsi" diff --git a/app/boards/shields/cradio/cradio_right.overlay b/app/boards/shields/cradio/cradio_right.overlay index fea59c23..01aa1ab6 100644 --- a/app/boards/shields/cradio/cradio_right.overlay +++ b/app/boards/shields/cradio/cradio_right.overlay @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ From 0b125c028c65ff4a5e326760a7d0ac0f8941899c Mon Sep 17 00:00:00 2001 From: Kellen Carey Date: Fri, 9 Oct 2020 11:48:06 -0700 Subject: [PATCH 163/227] address pr comments --- app/boards/shields/microdox/Kconfig.defconfig | 2 ++ app/boards/shields/microdox/Kconfig.shield | 3 +-- .../shields/microdox/boards/nice_nano.overlay | 5 +++++ app/boards/shields/microdox/microdox.dtsi | 7 +------ app/boards/shields/microdox/microdox.keymap | 16 +++++++++------- .../shields/microdox/microdox_left.overlay | 4 ---- .../shields/microdox/microdox_right.overlay | 4 ---- 7 files changed, 18 insertions(+), 23 deletions(-) diff --git a/app/boards/shields/microdox/Kconfig.defconfig b/app/boards/shields/microdox/Kconfig.defconfig index 218443f9..4840eceb 100644 --- a/app/boards/shields/microdox/Kconfig.defconfig +++ b/app/boards/shields/microdox/Kconfig.defconfig @@ -1,3 +1,5 @@ +# Copyright (c) 2020 The ZMK Contributors +# SPDX-License-Identifier: MIT if SHIELD_MICRODOX_LEFT diff --git a/app/boards/shields/microdox/Kconfig.shield b/app/boards/shields/microdox/Kconfig.shield index 7d7148de..ac79eab6 100644 --- a/app/boards/shields/microdox/Kconfig.shield +++ b/app/boards/shields/microdox/Kconfig.shield @@ -1,5 +1,4 @@ -# Copyright (c) 2020 Pete Johanson -# Copyright (c) 2020 Kellen Carey +# Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT config SHIELD_MICRODOX_LEFT diff --git a/app/boards/shields/microdox/boards/nice_nano.overlay b/app/boards/shields/microdox/boards/nice_nano.overlay index c7c3eb8e..58cd8613 100644 --- a/app/boards/shields/microdox/boards/nice_nano.overlay +++ b/app/boards/shields/microdox/boards/nice_nano.overlay @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ &spi1 { compatible = "nordic,nrf-spi"; /* Cannot be used together with i2c0. */ diff --git a/app/boards/shields/microdox/microdox.dtsi b/app/boards/shields/microdox/microdox.dtsi index bf7950df..55c67dd3 100644 --- a/app/boards/shields/microdox/microdox.dtsi +++ b/app/boards/shields/microdox/microdox.dtsi @@ -1,6 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson - * Copyright (c) 2020 Kellen Carey + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -43,10 +42,6 @@ RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) }; - bt_unpair_combo: bt_unpair_combo { - compatible = "zmk,bt-unpair-combo"; - }; - // TODO: per-key RGB node(s)? }; diff --git a/app/boards/shields/microdox/microdox.keymap b/app/boards/shields/microdox/microdox.keymap index 916141c7..5747771b 100644 --- a/app/boards/shields/microdox/microdox.keymap +++ b/app/boards/shields/microdox/microdox.keymap @@ -27,15 +27,15 @@ }; nav_layer { // ----------------------------------------------------------------------------------------- -// | | | ESC | ~ | | | TAB | HOME | UP | END | DEL | -// | | GUI | ALT | CTRL | NUM | | / | LEFT | DOWN | RGT | BKSP | -// | | | | | | | \ | ENT | | | | +// |BTCLR| | ESC | ~ | | | TAB | HOME | UP | END | DEL | +// | BT1 | GUI | ALT | CTRL | NUM | | / | LEFT | DOWN | RGT | BKSP | +// | BT2 | | | | | | \ | ENT | | | | // | | | | | | | | bindings = < - &trans &trans &kp ESC &kp TILD &trans &kp TAB &kp HOME &kp UARW &kp END &kp DEL - &trans &kp GUI &kp RALT &kp LCTL &mo 3 &kp FSLH &kp LARW &kp DARW &kp RARW &kp BKSP - &trans &trans &trans &trans &trans &kp BSLH &kp RET &trans &trans &trans - &trans &trans &trans &trans &trans &trans + &bt BT_CLR &trans &kp ESC &kp TILD &trans &kp TAB &kp HOME &kp UARW &kp END &kp DEL + &bt BT_SEL 0 &kp GUI &kp RALT &kp LCTL &mo 3 &kp FSLH &kp LARW &kp DARW &kp RARW &kp BKSP + &bt BT_SEL 1 &trans &trans &trans &trans &kp BSLH &kp RET &trans &trans &trans + &trans &trans &trans &trans &trans &trans >; }; @@ -53,6 +53,8 @@ >; }; +// This layer is unreachable until "tri layer state" is sorted out. +// Leaving it here for completeness. num_layer { // ----------------------------------------------------------------------------------------- // | | | | | | | A | 7 | 8 | 9 | D | diff --git a/app/boards/shields/microdox/microdox_left.overlay b/app/boards/shields/microdox/microdox_left.overlay index 0a3f823a..07dc0d26 100644 --- a/app/boards/shields/microdox/microdox_left.overlay +++ b/app/boards/shields/microdox/microdox_left.overlay @@ -16,7 +16,3 @@ , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> ; }; - -&bt_unpair_combo { - key-positions = <0 38>; -}; diff --git a/app/boards/shields/microdox/microdox_right.overlay b/app/boards/shields/microdox/microdox_right.overlay index 2638a398..a0d86013 100644 --- a/app/boards/shields/microdox/microdox_right.overlay +++ b/app/boards/shields/microdox/microdox_right.overlay @@ -20,7 +20,3 @@ , <&pro_micro_a 3 GPIO_ACTIVE_HIGH> ; }; - -&bt_unpair_combo { - key-positions = <9 35>; -}; From a695d0d3596817834f7465e029d0205fc9235499 Mon Sep 17 00:00:00 2001 From: Kellen Carey Date: Fri, 9 Oct 2020 12:18:57 -0700 Subject: [PATCH 164/227] oops --- app/boards/shields/microdox/microdox_left.overlay | 3 +-- app/boards/shields/microdox/microdox_right.overlay | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/boards/shields/microdox/microdox_left.overlay b/app/boards/shields/microdox/microdox_left.overlay index 07dc0d26..4d0378e5 100644 --- a/app/boards/shields/microdox/microdox_left.overlay +++ b/app/boards/shields/microdox/microdox_left.overlay @@ -1,6 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson - * Copyright (c) 2020 Kellen Carey + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/boards/shields/microdox/microdox_right.overlay b/app/boards/shields/microdox/microdox_right.overlay index a0d86013..c5622b25 100644 --- a/app/boards/shields/microdox/microdox_right.overlay +++ b/app/boards/shields/microdox/microdox_right.overlay @@ -1,6 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson - * Copyright (c) 2020 Kellen Carey + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ From 81a4ffef7efb45f30c74802dca97d949312a1785 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 9 Oct 2020 15:44:39 -0400 Subject: [PATCH 165/227] feat(setup): Add Microdox to setup scripts. --- docs/static/setup.ps1 | 6 +++--- docs/static/setup.sh | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index dc7b18c9..abdb6981 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -78,9 +78,9 @@ Write-Host "Keyboard Shield Selection:" $prompt = "Pick a keyboard" # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. -$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac", "makerdiary M60" -$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac", "m60" -$splits = "y", "y", "y", "y", "y", "y", "n", "n" +$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac", "makerdiary M60", "Microdox" +$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac", "m60", "microdox" +$splits = "y", "y", "y", "y", "y", "y", "n", "n", "y" $choice = Get-Choice-From-Options -Options $options -Prompt $prompt $shield_title = $($options[$choice]) diff --git a/docs/static/setup.sh b/docs/static/setup.sh index 9e989644..49ed3eb2 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -51,7 +51,7 @@ echo "" echo "Keyboard Shield Selection:" prompt="Pick an keyboard:" -options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac" "makerdiary M60") +options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac" "makerdiary M60" "Microdox") PS3="$prompt " # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. @@ -67,7 +67,8 @@ select opt in "${options[@]}" "Quit"; do 5 ) shield_title="Sofle" shield="sofle"; split="y"; break;; 6 ) shield_title="Iris" shield="iris"; split="y"; break;; 7 ) shield_title="RoMac" shield="romac"; split="n"; break;; - 7 ) shield_title="M60" shield="m60"; split="n"; break;; + 8 ) shield_title="M60" shield="m60"; split="n"; break;; + 9 ) shield_title="Microdox" shield="microdox"; split="y"; break;; # Add link to docs on adding your own custom shield in your ZMK config! # $(( ${#options[@]}+1 )) ) echo "Other!"; break;; From 1f2bdf639f3790ef6d36575c4a477d340b9fd393 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Fri, 9 Oct 2020 12:57:07 -0700 Subject: [PATCH 166/227] Adjusted Wording, Added link to GH Actions --- docs/docs/troubleshooting.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md index 8dd12614..7395ff57 100644 --- a/docs/docs/troubleshooting.md +++ b/docs/docs/troubleshooting.md @@ -62,13 +62,17 @@ After opening the `.dts.pre.tmp:` and scrolling down to the ### Split Keyboard Halves Unable to Pair -The previous method of pairing split keyboard halves involved a **BLE Reset** with a specific combination of held keys that would remove all bluetooth profile information from the keyboard. +Previously, pairing split keyboard halves involved a **BLE Reset** via a combination of held keys that removed all bluetooth profile information from the keyboard. Since then, a much simpler procedure of performing a bluetooth reset for split keyboards has come about, without the need for any file modification: -1. Log into Github and download the "settings clear" UF2 image from latest GH actions from the `main` of ZMK -1. Put both sides into bootloader mode -1. Flash both sides with the "settings clear" UF2 images from step 1. After, put both sides into bootloader mode again. -1. Flash the actual image for each half of the split keyboard +**New Procedure:** + +1. Log into Github and download the "settings clear" UF2 image from the [latest build in Github Actions](https://github.com/zmkfirmware/zmk/actions?query=workflow%3ABuild+branch%3Amain) +1. Put each half of the split keyboard into bootloader mode +1. Flash one of the halves of the split with the "settings clear" UF2 image from step 1. Immediately after flashing "settings clear" to the chosen half, immediately put it into bootloader mode +to avoid accidental bonding between the halves. +1. Repeat step 3 with the other half of the split keyboard +1. Flash the actual image for each half of the split keyboard (e.g `my_board_left.uf2` to the left half, `my_board_right.uf2` to the right half) After completing these steps, pair the halves of the split keyboard together by resetting them at the same time. Most commonly, this is done by grounding the reset pins for each of your keyboard's microcontrollers or pressing the reset buttons at the same time. \ No newline at end of file From 4d81b10ba7047a4dbd63cfe33ac879ecf437e108 Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Tue, 6 Oct 2020 15:52:21 +0800 Subject: [PATCH 167/227] Added driver to control the external power output This PR adds support to control the external power output from controllers like nice!nano, nRFMicro etc I have implemented based on my understanding of Pete suggestion on this feature. Testing done: Tested by enabling and disabling the ext_power from application and verified Verified the application does not crash with boards that does not have ext_power support Note: I did not test this in nice!nano since I don't have the boards. Will get help from others once the behavior PR is up Next Steps: Create a behavior PR to control enable/disable ext_power --- app/CMakeLists.txt | 1 + app/Kconfig | 4 + app/boards/arm/nice_nano/nice_nano.dts | 5 + app/boards/arm/nrfmicro/nrfmicro_11.dts | 5 + .../arm/nrfmicro/nrfmicro_11_flipped.dts | 5 + app/boards/arm/nrfmicro/nrfmicro_13.dts | 5 + app/boards/arm/nrfmicro/pinmux.c | 11 -- .../zmk,behavior-sensor-rotate-key-press.yaml | 2 +- app/dts/bindings/zmk,ext-power-generic.yaml | 20 ++++ app/dts/bindings/zmk,keymap-sensors.yaml | 5 + app/include/drivers/ext_power.h | 104 ++++++++++++++++++ app/src/ext_power_generic.c | 91 +++++++++++++++ app/src/main.c | 9 ++ 13 files changed, 255 insertions(+), 12 deletions(-) create mode 100644 app/dts/bindings/zmk,ext-power-generic.yaml create mode 100644 app/include/drivers/ext_power.h create mode 100644 app/src/ext_power_generic.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3e59d751..31d28f57 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -31,6 +31,7 @@ target_sources(app PRIVATE src/sensors.c) target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c) target_sources(app PRIVATE src/event_manager.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c) +target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c) target_sources(app PRIVATE src/events/position_state_changed.c) target_sources(app PRIVATE src/events/keycode_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c) diff --git a/app/Kconfig b/app/Kconfig index edf58670..fca49124 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -95,6 +95,10 @@ config ZMK_IDLE_SLEEP_TIMEOUT endif +config ZMK_EXT_POWER + bool "Enable support to control external power output" + default y + config ZMK_DISPLAY bool "ZMK display support" default n diff --git a/app/boards/arm/nice_nano/nice_nano.dts b/app/boards/arm/nice_nano/nice_nano.dts index 3ffb0ea8..0538b1df 100644 --- a/app/boards/arm/nice_nano/nice_nano.dts +++ b/app/boards/arm/nice_nano/nice_nano.dts @@ -29,6 +29,11 @@ }; }; + ext-power { + compatible = "zmk,ext-power-generic"; + label = "EXT_POWER"; + control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + }; }; &gpiote { diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.dts b/app/boards/arm/nrfmicro/nrfmicro_11.dts index 95bd8adc..87c650e1 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_11.dts +++ b/app/boards/arm/nrfmicro/nrfmicro_11.dts @@ -26,6 +26,11 @@ }; }; + ext-power { + compatible = "zmk,ext-power-generic"; + label = "EXT_POWER"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; }; &gpio0 { diff --git a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts index 85693a8b..ea15b819 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts +++ b/app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts @@ -26,6 +26,11 @@ }; }; + ext-power { + compatible = "zmk,ext-power-generic"; + label = "EXT_POWER"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>; + }; }; &gpio0 { diff --git a/app/boards/arm/nrfmicro/nrfmicro_13.dts b/app/boards/arm/nrfmicro/nrfmicro_13.dts index 95bd8adc..ef439462 100644 --- a/app/boards/arm/nrfmicro/nrfmicro_13.dts +++ b/app/boards/arm/nrfmicro/nrfmicro_13.dts @@ -26,6 +26,11 @@ }; }; + ext-power { + compatible = "zmk,ext-power-generic"; + label = "EXT_POWER"; + control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; + }; }; &gpio0 { diff --git a/app/boards/arm/nrfmicro/pinmux.c b/app/boards/arm/nrfmicro/pinmux.c index 4e330b65..30117d0f 100644 --- a/app/boards/arm/nrfmicro/pinmux.c +++ b/app/boards/arm/nrfmicro/pinmux.c @@ -14,25 +14,14 @@ static int pinmux_nrfmicro_init(struct device *port) { ARG_UNUSED(port); - struct device *p1 = device_get_binding("GPIO_1"); - #if CONFIG_BOARD_NRFMICRO_13 struct device *p0 = device_get_binding("GPIO_0"); - // enable EXT_VCC (use 0 for nRFMicro 1.3, use 1 for nRFMicro 1.1) - gpio_pin_configure(p1, 9, GPIO_OUTPUT); - gpio_pin_set(p1, 9, 0); - #if CONFIG_BOARD_NRFMICRO_CHARGER gpio_pin_configure(p0, 5, GPIO_OUTPUT); gpio_pin_set(p0, 5, 0); #else gpio_pin_configure(p0, 5, GPIO_INPUT); #endif - -#else - // enable EXT_VCC (use 0 for nRFMicro 1.3, use 1 for nRFMicro 1.1) - gpio_pin_configure(p1, 9, GPIO_OUTPUT); - gpio_pin_set(p1, 9, 1); #endif return 0; } diff --git a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml index bbf35373..6b339107 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml @@ -1,4 +1,4 @@ -# Copyright (c) 2020, Pete Johanson +# Copyright (c) 2020, The ZMK Contributors # SPDX-License-Identifier: MIT description: Sensor rotate key press/release behavior diff --git a/app/dts/bindings/zmk,ext-power-generic.yaml b/app/dts/bindings/zmk,ext-power-generic.yaml new file mode 100644 index 00000000..5a38a09a --- /dev/null +++ b/app/dts/bindings/zmk,ext-power-generic.yaml @@ -0,0 +1,20 @@ +# +# Copyright (c) 2020, The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +description: | + Generic driver for controlling the external power output + by toggling the control-gpio pin status + (Only in supported hardware) + +compatible: "zmk,ext-power-generic" + +properties: + control-gpios: + type: phandle-array + required: true + label: + type: string + required: true + diff --git a/app/dts/bindings/zmk,keymap-sensors.yaml b/app/dts/bindings/zmk,keymap-sensors.yaml index c56361d1..86ae5c22 100644 --- a/app/dts/bindings/zmk,keymap-sensors.yaml +++ b/app/dts/bindings/zmk,keymap-sensors.yaml @@ -1,3 +1,8 @@ +# +# Copyright (c) 2020, The ZMK Contributors +# SPDX-License-Identifier: MIT +# + description: | Allows defining the collection of sensors bound in the keymap layers diff --git a/app/include/drivers/ext_power.h b/app/include/drivers/ext_power.h new file mode 100644 index 00000000..6c1923e8 --- /dev/null +++ b/app/include/drivers/ext_power.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @cond INTERNAL_HIDDEN + * + * Behavior driver API definition and system call entry points. + * + * (Internal use only.) + */ + +typedef int (*ext_power_enable_t)(struct device *dev); +typedef int (*ext_power_disable_t)(struct device *dev); +typedef int (*ext_power_get_t)(struct device *dev); + +__subsystem struct ext_power_api { + ext_power_enable_t enable; + ext_power_disable_t disable; + ext_power_get_t get; +}; +/** + * @endcond + */ + +/** + * @brief Enable the external power output + * @param dev Pointer to the device structure for the driver instance. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int ext_power_enable(struct device *dev); + +static inline int z_impl_ext_power_enable(struct device *dev) { + const struct ext_power_api *api = (const struct ext_power_api *)dev->driver_api; + + if (api->enable == NULL) { + return -ENOTSUP; + } + + return api->enable(dev); +} + +/** + * @brief Disable the external power output + * @param dev Pointer to the device structure for the driver instance. + * + * @retval 0 If successful. + * @retval Negative errno code if failure. + */ +__syscall int ext_power_disable(struct device *dev); + +static inline int z_impl_ext_power_disable(struct device *dev) { + const struct ext_power_api *api = (const struct ext_power_api *)dev->driver_api; + + if (api->disable == NULL) { + return -ENOTSUP; + } + + return api->disable(dev); +} + +/** + * @brief Get the current status of the external power output + * @param dev Pointer to the device structure for the driver instance. + * + * @retval 0 If ext power is disabled. + * @retval 1 if ext power is enabled. + * @retval Negative errno code if failure. + */ +__syscall int ext_power_get(struct device *dev); + +static inline int z_impl_ext_power_get(struct device *dev) { + const struct ext_power_api *api = (const struct ext_power_api *)dev->driver_api; + + if (api->get == NULL) { + return -ENOTSUP; + } + + return api->get(dev); +} + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#include diff --git a/app/src/ext_power_generic.c b/app/src/ext_power_generic.c new file mode 100644 index 00000000..48170304 --- /dev/null +++ b/app/src/ext_power_generic.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_ext_power_generic + +#include +#include +#include +#include + +#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +struct ext_power_generic_config { + const char *label; + const u8_t pin; + const u8_t flags; +}; + +struct ext_power_generic_data { + struct device *gpio; + bool status; +}; + +static int ext_power_generic_enable(struct device *dev) { + struct ext_power_generic_data *data = dev->driver_data; + const struct ext_power_generic_config *config = dev->config_info; + + if (gpio_pin_set(data->gpio, config->pin, 1)) { + LOG_WRN("Failed to set ext-power control pin"); + return -EIO; + } + data->status = true; + return 0; +} + +static int ext_power_generic_disable(struct device *dev) { + struct ext_power_generic_data *data = dev->driver_data; + const struct ext_power_generic_config *config = dev->config_info; + + if (gpio_pin_set(data->gpio, config->pin, 0)) { + LOG_WRN("Failed to clear ext-power control pin"); + return -EIO; + } + data->status = false; + return 0; +} + +static int ext_power_generic_get(struct device *dev) { + struct ext_power_generic_data *data = dev->driver_data; + return data->status; +} + +static int ext_power_generic_init(struct device *dev) { + struct ext_power_generic_data *data = dev->driver_data; + const struct ext_power_generic_config *config = dev->config_info; + + data->gpio = device_get_binding(config->label); + if (data->gpio == NULL) { + LOG_ERR("Failed to get ext-power control device"); + return -EINVAL; + } + + if (gpio_pin_configure(data->gpio, config->pin, config->flags | GPIO_OUTPUT)) { + LOG_ERR("Failed to configure ext-power control pin"); + return -EIO; + } + + return 0; +} + +static const struct ext_power_generic_config config = { + .label = DT_INST_GPIO_LABEL(0, control_gpios), + .pin = DT_INST_GPIO_PIN(0, control_gpios), + .flags = DT_INST_GPIO_FLAGS(0, control_gpios)}; + +static struct ext_power_generic_data data = {.status = false}; + +static const struct ext_power_api api = {.enable = ext_power_generic_enable, + .disable = ext_power_generic_disable, + .get = ext_power_generic_get}; + +DEVICE_AND_API_INIT(ext_power_generic, DT_INST_LABEL(0), ext_power_generic_init, &data, &config, + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &api); + +#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/main.c b/app/src/main.c index dca923e9..0551356d 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -15,16 +15,25 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include #include +#include #define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) void main(void) { + struct device *ext_power; LOG_INF("Welcome to ZMK!\n"); if (zmk_kscan_init(ZMK_KSCAN_DEV) != 0) { return; } + // Enable the external VCC output + ext_power = device_get_binding("EXT_POWER"); + if (ext_power != NULL) { + const struct ext_power_api *ext_power_api = ext_power->driver_api; + ext_power_api->enable(ext_power); + } + #ifdef CONFIG_ZMK_DISPLAY zmk_display_init(); From 10029c297ed8f6d97b582bc7382d9e9558808884 Mon Sep 17 00:00:00 2001 From: Kellen Carey Date: Fri, 9 Oct 2020 18:00:11 -0700 Subject: [PATCH 168/227] exit setup if no write permissions in directory --- docs/static/setup.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/static/setup.sh b/docs/static/setup.sh index 49ed3eb2..96e87688 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -22,6 +22,13 @@ check_exists "command -v curl" "curl is not installed, and is required for this check_exists "git config user.name" "Git username not set!\nRun: git config --global user.name 'My Name'" check_exists "git config user.email" "Git email not set!\nRun: git config --global user.email 'example@myemail.com'" +# Check to see if the user has write permissions in this directory to prevent a cryptic error later on +if [ ! -w `pwd` ]; then + echo 'Sorry, you do not have write permissions in this directory.'; + echo 'Please try running this script again from a directory that you do have write permissions for.'; + exit 1 +fi + repo_path="https://github.com/zmkfirmware/zmk-config-split-template.git" title="ZMK Config Setup:" From 3322c3cab106ee4918ff9200d0dbae83917a68e6 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Fri, 9 Oct 2020 18:51:51 -0700 Subject: [PATCH 169/227] Adressing Issue #138 --- docs/docs/dev-guide-new-shield.md | 200 ++++++++++++++++++++++++++++-- 1 file changed, 192 insertions(+), 8 deletions(-) diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md index 1ba572c5..9f7b23ca 100644 --- a/docs/docs/dev-guide-new-shield.md +++ b/docs/docs/dev-guide-new-shield.md @@ -21,6 +21,10 @@ The high level steps are: It may be helpful to review the upstream [shields documentation](https://docs.zephyrproject.org/2.3.0/guides/porting/shields.html#shields) to get a proper understanding of the underlying system before continuing. +:::note +ZMK support for split keyboards requires a few more files than single boards to ensure proper connectivity between the central and peripheral units. Check the following guides thoroughly to ensure that all the files are in place. +::: + ## New Shield Directory Shields for Zephyr applications go into the `boards/shields/` directory; since ZMK's Zephyr application lives in the `app/` subdirectory of the repository, that means the new shield directory should be: @@ -45,6 +49,16 @@ config SHIELD_MY_BOARD This will make sure the new configuration `SHIELD_MY_BOARD` is set to true whenever `my_board` is added as a shield in your build. + +**For split boards**, you will need to add configurations for the left and right sides. +``` +config SHIELD_MY_BOARD_LEFT + def_bool $(shields_list_contains,my_board_left) + +config SHIELD_MY_BOARD_RIGHT + def_bool $(shields_list_contains,my_board_right) +``` + ### Kconfig.defconfig The `Kconfig.defconfig` file is where overrides for various configuration settings @@ -63,12 +77,41 @@ config ZMK_KEYBOARD_NAME endif ``` -## Shield Overlay + +Similarly to defining the halves of a split board in `Kconfig.shield` it is important to set the `ZMK_KEYBOARD_NAME` for each half of a split keyboard. + +``` +if SHIELD_MY_BOARD_LEFT + +config ZMK_KEYBOARD_NAME + default "My Awesome Keyboard Left" + +endif + +if SHIELD_MY_BOARD_RIGHT + +config ZMK_KEYBOARD_NAME + default "My Awesome Keyboard Right" + +endif +``` + +## Shield Overlays ![Labelled Pro Micro pins](assets/pro-micro/pro-micro-pins-labelled.jpg) + ZMK uses the green color coded pin names to generate devicetree node references. For example, to refer to the node `D0` in the devicetree files, use `&pro_micro_d 0` or to refer to `A1`, use `&pro_micro_a 1`. + + + + The `.overlay` is the devicetree description of the keyboard shield that is merged with the primary board devicetree description before the build. For ZMK, this file at a minimum should include the [chosen]() node named `zmk,kscan` that references a KSCAN driver instance. For a simple 3x3 macropad matrix, this might look something like: @@ -98,6 +141,146 @@ this might look something like: }; ``` + + + + +### .dtsi files and Shield Overlays (Split Shields) + +Unlike unibody keyboards, split keyboards have a core .dtsi file with shield overlays for each half of the keyboard. +It is preferred to define only the `col-gpios` or `row-gpios` in the common shield .dtsi, depending on the `diode-direction` value. +For `col2row` directed boards like the iris, the shared .dtsi file may look like this: + +``` +#include + +/ { + chosen { + zmk,kscan = &kscan0; + zmk,matrix_transform = &default_transform; + }; + + default_transform: keymap_transform_0 { + compatible = "zmk,matrix-transform"; + columns = <16>; + rows = <4>; +// | SW6 | SW5 | SW4 | SW3 | SW2 | SW1 | | SW1 | SW2 | SW3 | SW4 | SW5 | SW6 | +// | SW12 | SW11 | SW10 | SW9 | SW8 | SW7 | | SW7 | SW8 | SW9 | SW10 | SW11 | SW12 | +// | SW18 | SW17 | SW16 | SW15 | SW14 | SW13 | | SW13 | SW14 | SW15 | SW16 | SW17 | SW18 | +// | SW24 | SW23 | SW22 | SW21 | SW20 | SW19 | SW25 | | SW25 | SW19 | SW20 | SW21 | SW22 | SW23 | SW24 | +// | SW29 | SW28 | SW27 | SW26 | | SW26 | SW27 | SW28 | SW29 | + map = < +RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) +RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) +RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) +RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(4,2) RC(4,9) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) + RC(4,3) RC(4,4) RC(4,5) RC(4,6) RC(4,7) RC(4,8) + >; + }; + + kscan0: kscan { + compatible = "zmk,kscan-gpio-matrix"; + label = "KSCAN"; + + diode-direction = "col2row"; + row-gpios + = <&pro_micro_d 6 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row A from the schematic file + , <&pro_micro_d 7 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row B from the schematic file + , <&pro_micro_d 8 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row C from the schematic file + , <&pro_micro_d 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row D from the schematic file + , <&pro_micro_d 4 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)> // Row E from the schematic file + ; + + }; +``` + +:::note +Notice that in addition to the common `row-gpios` that are declared in the kscan, the [matrix transform](#optional-matrix-transform) is defined in the .dtsi. +::: + +The missing `col-gpios` would be defined in your `_left.overlay` and `_right.overlay` files. +Keep in mind that the mirrored position of the GPIOs means that the `col-gpios` will appear reversed when the .overlay files are compared to one another. +Furthermore, the column offset for the [matrix transform](#optional-matrix-transform) should be added to the right half of the keyboard's overlay +because the keyboard's switch matrix is read from left to right, top to bottom. +This is exemplified with the iris .overlay files. + +``` +// iris_left.overlay + +#include "iris.dtsi" // Notice that the main dtsi files are included in the overlay. + +&kscan0 { + col-gpios + = <&pro_micro_a 1 GPIO_ACTIVE_HIGH> // col1 in the schematic + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> // col2 in the schematic + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> // col3 in the schematic + , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> // col4 in the schematic + , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> // col5 in the schematic + , <&pro_micro_d 10 GPIO_ACTIVE_HIGH> // col6 in the schematic + ; +}; +``` + +``` +// iris_right.overlay + +#include "iris.dtsi" + +&default_transform { // The matrix transform for this board is 6 columns over because the left half is 6 columns wide according to the matrix. + col-offset = <6>; +}; + +&kscan0 { + col-gpios + = <&pro_micro_d 10 GPIO_ACTIVE_HIGH> // col6 in the schematic + , <&pro_micro_d 16 GPIO_ACTIVE_HIGH> // col5 in the schematic + , <&pro_micro_d 14 GPIO_ACTIVE_HIGH> // col4 in the schematic + , <&pro_micro_d 15 GPIO_ACTIVE_HIGH> // col3 in the schematic + , <&pro_micro_a 0 GPIO_ACTIVE_HIGH> // col2 in the schematic + , <&pro_micro_a 1 GPIO_ACTIVE_HIGH> // col1 in the schematic + ; +}; + +``` + +### .conf files (Split Shields) + +While unibody boards only have one .conf file that applies configuration characteristics to the entire keyboard, +split keyboards are unique in that they contain multiple .conf files with different scopes. +For example, a split board called `my_awesome_split_board` would have the following files: + +* `my_awesome_split_board.conf` - Configuration elements affect both halves +* `my_awesome_split_board_left.conf` - Configuration elements only affect left half +* `my_awesome_split_board_right.conf` - Configuration elements only affect right half + +For proper communication between keyboard halves and that between the central half and the computer, +the **the central and peripheral halves of the keyboard must be defined**. This can be seen below. + +``` +// Central Half (Usually the left side: my_awesome_split_board_left.conf) + +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL=y +``` + +``` +// Peripheral Half (Usually the right side: my_awesome_split_board_right.conf) + +CONFIG_ZMK_SPLIT=y +CONFIG_ZMK_SPLIT_BLE_ROLE_Peripheral=y +``` + +Using the .conf file that affects both halves of a split board would be for adding features like deep-sleep or rotary encoders. + +``` +// my_awesome_split_board.conf + +CONFIG_ZMK_SLEEP=y +``` + + + + ## (Optional) Matrix Transform Internally ZMK translates all row/column events into "key position" events to maintain a consistent model that works no matter what any possible GPIO matrix may look like for a certain keyboard. This is particularly helpful when: @@ -238,6 +421,7 @@ If building locally for split boards, you may need to add these lines to the spe In your device tree file you will need to add the following lines to define the encoder sensor: + ``` left_encoder: encoder_left { compatible = "alps,ec11"; @@ -247,7 +431,6 @@ left_encoder: encoder_left { resolution = <4>; }; ``` - Here you will have to replace PIN_A and PIN_B with the appropriate pins that your PCB utilizes for the encoder(s). For keyboards that use the Pro Micro or any of the Pro Micro replacements, Sparkfun's [Pro Micro Hookup Guide](https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/hardware-overview-pro-micro) has a pinout diagram that can be useful to determine the right pins. Reference either the blue numbers labeled "Arduino" (digital pins) or the green numbers labeled "Analog" (analog pins). For pins that are labeled as both digital and analog, refer to your specific board's .dtsi file to determine how you should refer to that pin. Add additional encoders as necessary by duplicating the above lines, replacing `left` with whatever you would like to call your encoder, and updating the pins. Note that support for peripheral (right) side sensors over BLE is still in progress. @@ -279,15 +462,12 @@ For split keyboards, make sure to add left hand encoders to the left .overlay fi -Add the following line to each layer of your keymap file to add default encoder behavior bindings: +Add the following line to your keymap file to add default encoder behavior bindings: ``` sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD>; ``` - -This should be placed after the regular key bindings but within the layer (see the [Default Keymap section](/docs/dev-guide-new-shield#default-keymap) above for an example of where). - -Add additional bindings as necessary to match the default number of encoders on your board. Details on the syntax can be found in the [Encoders](/docs/feature/encoders) and [Keymap](/docs/feature/keymaps) feature documentation. +Add additional bindings as necessary to match the default number of encoders on your board. See the [Encoders](/docs/feature/encoders) and [Keymap](/docs/feature/keymaps) feature documentation for more details. @@ -307,6 +487,11 @@ and then flash with: west flash ``` +:::note +Further testing your keyboard shield without altering the root keymap file can be done with the use of `-DZMK_CONFIG` in your `west build` command, +shown [here](dev-build-flash#building-from-zmk-config-folder) +::: + ## Updating `build.yml` Before publishing your shield to the public via a PR, navigate to `build.yml` found in `.github/workflows` and add your shield to the appropriate list. An example edit to `build.yml` is shown below. @@ -336,7 +521,6 @@ jobs: - board: proton_c shield: clueboard_california ``` - :::note Notice that both the left and right halves of a split board need to be added to the list of shields for proper error checking. :::note From b64517943deb3dfe72e2e37ca62319856bc35752 Mon Sep 17 00:00:00 2001 From: Kellen Carey Date: Fri, 9 Oct 2020 18:53:21 -0700 Subject: [PATCH 170/227] add powershell check --- docs/static/setup.ps1 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index abdb6981..1da57378 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -59,6 +59,19 @@ catch [System.Management.Automation.CommandNotFoundException] { Test-Git-Config -Option "user.name" -ErrMsg "Git username not set!`nRun: git config --global user.name 'My Name'" Test-Git-Config -Option "user.email" -ErrMsg "Git email not set!`nRun: git config --global user.name 'example@myemail.com'" +$permission = (Get-Acl $PSScriptRoot).Access | +?{$_.IdentityReference -match $env:UserName ` + -and $_.FileSystemRights -match "Read" ` + -or $_.FileSystemRights -match "Write" } | + + Select IdentityReference,FileSystemRights + +If (-Not $permission){ + Write-Host "Sorry, you do not have write permissions in this directory." + Write-Host "Please try running this script again from a directory that you do have write permissions for." + exit 1 +} + $repo_path = "https://github.com/zmkfirmware/zmk-config-split-template.git" $title = "ZMK Config Setup:" From 9231f6c57beb6bfabc030f9debcb659dd964634e Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Thu, 24 Sep 2020 09:52:00 -0700 Subject: [PATCH 171/227] Add VSCode devcontainer configuration --- .devcontainer/Dockerfile | 1 + .devcontainer/devcontainer.json | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..ba4e1223 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1 @@ +FROM zmkfirmware/zephyr-west-action-arm \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..74505346 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,6 @@ +{ + "name": "ZMK Development", + "dockerFile": "Dockerfile", + "extensions": ["ms-vscode.cpptools"] +} + From 5bd09b586e153185850fe468b19fdd0eb534f35d Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Wed, 30 Sep 2020 23:23:42 -0700 Subject: [PATCH 172/227] Remove Dockerfile in favor of image Per the docs, we can directly specify an image in devcontainer.json: https://code.visualstudio.com/docs/remote/devcontainerjson-reference --- .devcontainer/Dockerfile | 1 - .devcontainer/devcontainer.json | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 .devcontainer/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index ba4e1223..00000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1 +0,0 @@ -FROM zmkfirmware/zephyr-west-action-arm \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 74505346..bbf44bc7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,7 @@ { "name": "ZMK Development", - "dockerFile": "Dockerfile", - "extensions": ["ms-vscode.cpptools"] + "image": "zmkfirmware/zephyr-west-action-arm", + "extensions": ["ms-vscode.cpptools"], + "runArgs": ["--security-opt", "label=disable"] } From 9b29f9b861464a8a0eba78f25058cded118b84d5 Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Thu, 1 Oct 2020 06:52:33 +0000 Subject: [PATCH 173/227] Install SSH and GPG into container Brings back the dockerfile so we can install SSH and GPG into it. This fixes git actions with SSH remotes, and GPG signing now works out of the box. This commit was made from inside the container! --- .devcontainer/Dockerfile | 8 ++++++++ .devcontainer/devcontainer.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..abbe54ac --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,8 @@ +from zmkfirmware/zephyr-west-action-arm + +RUN apt-get -y update && \ + apt-get -y upgrade && \ + apt-get install --no-install-recommends -y \ + ssh \ + gpg && \ + rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index bbf44bc7..f21465df 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,6 @@ { "name": "ZMK Development", - "image": "zmkfirmware/zephyr-west-action-arm", + "dockerFile": "Dockerfile", "extensions": ["ms-vscode.cpptools"], "runArgs": ["--security-opt", "label=disable"] } From 42d1915ced3f7ec8a74cf5be506438d2bf07a7d3 Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Thu, 1 Oct 2020 06:56:18 +0000 Subject: [PATCH 174/227] Use spaces, not tabs --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index abbe54ac..cf62b5a3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,7 +1,7 @@ from zmkfirmware/zephyr-west-action-arm RUN apt-get -y update && \ - apt-get -y upgrade && \ + apt-get -y upgrade && \ apt-get install --no-install-recommends -y \ ssh \ gpg && \ From 15614a946fac635a27ba94a4f32450c67016e5b2 Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Thu, 1 Oct 2020 00:41:33 -0700 Subject: [PATCH 175/227] WIP docs for docker development --- docs/docs/dev-setup.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/docs/dev-setup.md b/docs/docs/dev-setup.md index 4891f5af..be3d6f95 100644 --- a/docs/docs/dev-setup.md +++ b/docs/docs/dev-setup.md @@ -16,6 +16,7 @@ values={[ {label: 'macOS', value: 'mac'}, {label: 'Raspberry OS', value: 'raspberryos'}, {label: 'Fedora', value: 'fedora'}, +{label: 'VS Code & Docker', value: 'docker'}, ] }>{props.children}); @@ -178,6 +179,20 @@ Homebrew is required to install the system dependencies. If you haven't done so, brew install cmake ninja python3 ccache dtc git wget ``` + + + +This setup leverages the same [image which is used by the GitHub action](https://github.com/zmkfirmware/zephyr-west-action) for local development. Beyond the benefits of [dev/prod parity](https://12factor.net/dev-prod-parity), this approach is also the easiest to set up. No toolchain or dependencies are necessary when using Docker; the container image you'll be using already has the toolchain installed and set up to use. + + +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) for your operating system. +2. Install [VS Code](https://code.visualstudio.com/) +3. Install the [Remote - Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + +:::info +The docker container includes `west` and the compilation toolchain. If you're using docker and VS Code, you can skip right to [Source Code](#source-code). +::: + @@ -323,6 +338,11 @@ Please be sure to read the [additional setup instructions](https://docs.zephyrpr ::: + + + +You're already set up: the toolchain is installed and configured inside the docker container. + From 63931a706870652e649346e4052a9fb1b105ff5b Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Tue, 6 Oct 2020 08:51:25 -0700 Subject: [PATCH 176/227] Accept suggestions Co-authored-by: Pete Johanson --- .devcontainer/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index cf62b5a3..160b1481 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,8 +1,8 @@ -from zmkfirmware/zephyr-west-action-arm +FROM zmkfirmware/zephyr-west-action-arm RUN apt-get -y update && \ apt-get -y upgrade && \ apt-get install --no-install-recommends -y \ ssh \ gpg && \ - rm -rf /var/lib/apt/lists/* \ No newline at end of file + rm -rf /var/lib/apt/lists/* From db40fbad598b6f84472cb2921df89f1a46fc6b5c Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Fri, 9 Oct 2020 17:49:42 -0700 Subject: [PATCH 177/227] Conditionally source zephyr-env.sh in .bashrc --- .devcontainer/.bashrc | 6 ++++++ .devcontainer/Dockerfile | 3 +++ 2 files changed, 9 insertions(+) create mode 100644 .devcontainer/.bashrc diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc new file mode 100644 index 00000000..6a6ea691 --- /dev/null +++ b/.devcontainer/.bashrc @@ -0,0 +1,6 @@ +export LS_OPTIONS='-F --color=auto' +eval "`dircolors`" +alias ls='ls $LS_OPTIONS' +if [ -f /workspaces/zmk/zephyr/zephyr-env.sh ]; then + source /workspaces/zmk/zephyr/zephyr-env.sh +fi diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 160b1481..184aae9a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -6,3 +6,6 @@ RUN apt-get -y update && \ ssh \ gpg && \ rm -rf /var/lib/apt/lists/* + +COPY .bashrc tmp +RUN mv /tmp/.bashrc ~/.bashrc From 63ad5b7c089f13a5b5d5514514cc9ad7e798d3e8 Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Sat, 10 Oct 2020 01:42:50 +0000 Subject: [PATCH 178/227] Inject $WORKSPACE_DIR into container This permits users to check ZMK out into arbitrarily-named directories --- .devcontainer/.bashrc | 4 ++-- .devcontainer/devcontainer.json | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc index 6a6ea691..855ea755 100644 --- a/.devcontainer/.bashrc +++ b/.devcontainer/.bashrc @@ -1,6 +1,6 @@ export LS_OPTIONS='-F --color=auto' eval "`dircolors`" alias ls='ls $LS_OPTIONS' -if [ -f /workspaces/zmk/zephyr/zephyr-env.sh ]; then - source /workspaces/zmk/zephyr/zephyr-env.sh +if [ -f "$WORKSPACE_DIR/zephyr/zephyr-env.sh" ]; then + source "$WORKSPACE_DIR/zephyr/zephyr-env.sh" fi diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f21465df..940b78b8 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,6 +2,7 @@ "name": "ZMK Development", "dockerFile": "Dockerfile", "extensions": ["ms-vscode.cpptools"], - "runArgs": ["--security-opt", "label=disable"] + "runArgs": ["--security-opt", "label=disable"], + "containerEnv": {"WORKSPACE_DIR": "${containerWorkspaceFolder}"} } From 5c00c97e9a1647e2676586c303d19c5559e2e2f1 Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Fri, 9 Oct 2020 18:48:41 -0700 Subject: [PATCH 179/227] Wrap up documentation --- .../assets/dev-setup/vscode_devcontainer.png | Bin 0 -> 20773 bytes docs/docs/dev-setup.md | 62 ++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 docs/docs/assets/dev-setup/vscode_devcontainer.png diff --git a/docs/docs/assets/dev-setup/vscode_devcontainer.png b/docs/docs/assets/dev-setup/vscode_devcontainer.png new file mode 100644 index 0000000000000000000000000000000000000000..e5c22b0ac4f8080f47725e570a6bdca990470627 GIT binary patch literal 20773 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 literal 0 HcmV?d00001 diff --git a/docs/docs/dev-setup.md b/docs/docs/dev-setup.md index be3d6f95..6ef0f020 100644 --- a/docs/docs/dev-setup.md +++ b/docs/docs/dev-setup.md @@ -369,12 +369,63 @@ Since ZMK is built as a Zephyr™ application, the next step is to use `west` to initialize and update your workspace. The ZMK Zephyr™ application is in the `app/` source directory: + #### Step into the repository + + + ```sh cd zmk ``` + + + +```sh +cd zmk +``` + + + + +```sh +cd zmk +``` + + + + +```sh +cd zmk +``` + + + + +```sh +cd zmk +``` + + + + + +Open the `zmk` checkout folder in VS Code. The repository includes a configuration for containerized development, so an alert will pop up: + +![VS Code Dev Container Configuration Alert](assets/dev-setup/vscode_devcontainer.png) + +Click `Reopen in Container` in order to reopen the VS Code with the running container. + +The first time you do this on your machine, it will pull the docker image down from the registry and build the container. Subsequent launches are much faster! + +:::caution +All subsequent steps must be performed from the VS Code terminal _inside_ the container. +::: + + + + #### Initialize West ```sh @@ -393,6 +444,17 @@ section again for links to how to do this west update ``` +:::tip +This step pulls down quite a bit of tooling. Go grab a cup of coffee, it can take 10-15 minutes even on a good internet connection! +::: + +:::info +If you're using Docker, you're done with setup! You must restart the container at this point. The easiest way to do so is to close the VS Code window, verify that the container has stopped in Docker Dashboard, and reopen the container with VS Code. + +Once your container is restarted, proceed to [Building and Flashing](./dev-build.md). +::: + + #### Export Zephyr™ Core ```sh From 5401afc002ba086ca964aa7a164fbc6dbd1898b1 Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Fri, 9 Oct 2020 19:10:07 -0700 Subject: [PATCH 180/227] Skip toolchain for docker --- docs/docs/dev-setup.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/docs/dev-setup.md b/docs/docs/dev-setup.md index 6ef0f020..114fe0b3 100644 --- a/docs/docs/dev-setup.md +++ b/docs/docs/dev-setup.md @@ -338,11 +338,6 @@ Please be sure to read the [additional setup instructions](https://docs.zephyrpr ::: - - - -You're already set up: the toolchain is installed and configured inside the docker container. - From fc6c01fd6941ec795710d66ead9e17d5dfbaa19d Mon Sep 17 00:00:00 2001 From: Kurtis Lew Date: Fri, 9 Oct 2020 20:56:52 -0700 Subject: [PATCH 181/227] -DZMK_CONFIG Documentation (#255) feat(docs): `-DZMK_CONFIG` Documentation --- docs/docs/dev-build.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/docs/dev-build.md b/docs/docs/dev-build.md index 816468e2..83ed8cb9 100644 --- a/docs/docs/dev-build.md +++ b/docs/docs/dev-build.md @@ -84,6 +84,19 @@ west build -d build/right -b nice_nano -- -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. +### Building from `zmk-config` Folder + +Instead of building .uf2 files using the default keymap and config files, you can build directly from your [`zmk-config` folder](user-setup#github-repo) by adding +`-DZMK_CONFIG="C:/the/absolute/path/config"` to your `west build` command. **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: + +``` +west build -b nice_nano -- -DSHIELD=kyria_left -DZMK_CONFIG="C:/Users/myUser/Documents/Github/zmk-config/config" +``` + + ## Flashing Once built, the previously supplied parameters will be remembered so you can run the following to flash your From 8d4e80c23a51ab4f1499c21086f76549d56ababd Mon Sep 17 00:00:00 2001 From: Tsquash Date: Fri, 9 Oct 2020 22:09:19 -0500 Subject: [PATCH 182/227] Added Dfu-Util to setup instructions --- docs/docs/dev-setup.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/docs/dev-setup.md b/docs/docs/dev-setup.md index 114fe0b3..521d5d02 100644 --- a/docs/docs/dev-setup.md +++ b/docs/docs/dev-setup.md @@ -168,6 +168,10 @@ Chocolatey is recommended and used for the following instructions. You can manua choco install ninja gperf python git ``` +It is recommended to install `dfu-util` to avoid any later confusion while flashing devices. You can do this by running this command with chocolatey: +``` shell +choco install dfu-util +``` @@ -176,7 +180,7 @@ Chocolatey is recommended and used for the following instructions. You can manua Homebrew is required to install the system dependencies. If you haven't done so, visit [Homebrew](https://brew.sh/) for instructions. Once installed, use it to install the base dependencies: ``` -brew install cmake ninja python3 ccache dtc git wget +brew install cmake ninja python3 ccache dtc git wget dfu-util ``` From 45f4ffc03a98359dd41c0a526dfcfa590cf0ceb4 Mon Sep 17 00:00:00 2001 From: Tsquash Date: Sat, 10 Oct 2020 13:03:34 -0500 Subject: [PATCH 183/227] added PowerShell setup Command --- docs/docs/user-setup.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/docs/user-setup.md b/docs/docs/user-setup.md index 2aade829..e069a14a 100644 --- a/docs/docs/user-setup.md +++ b/docs/docs/user-setup.md @@ -63,6 +63,7 @@ defaultValue="curl" values={[ {label: 'Using curl', value: 'curl'}, {label: 'Using wget', value: 'wget'}, +{label: 'Using PowerShell', value: 'PowerShell'}, ]}> @@ -77,6 +78,12 @@ bash -c "$(curl -fsSL https://zmkfirmware.dev/setup.sh)" bash -c "$(wget https://zmkfirmware.dev/setup.sh -O -)" ``` + + + +``` +iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/CrossR/zmk/CrossR/ShellScriptTidyUp/docs/static/setup.ps1'))" +``` From d79811dd6118357e88ffc6b35b46589799a0c79d Mon Sep 17 00:00:00 2001 From: Tsquash Date: Sat, 10 Oct 2020 14:39:12 -0500 Subject: [PATCH 184/227] Changed setup script url --- docs/docs/user-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/user-setup.md b/docs/docs/user-setup.md index e069a14a..2785096d 100644 --- a/docs/docs/user-setup.md +++ b/docs/docs/user-setup.md @@ -82,7 +82,7 @@ bash -c "$(wget https://zmkfirmware.dev/setup.sh -O -)" ``` -iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/CrossR/zmk/CrossR/ShellScriptTidyUp/docs/static/setup.ps1'))" +iex ((New-Object System.Net.WebClient).DownloadString('https://zmkfirmware.dev/setup.ps1'))" ``` From d38740cebf3be17a7d55fc51f5f06752182f96d8 Mon Sep 17 00:00:00 2001 From: Okke Formsma Date: Sat, 10 Oct 2020 23:32:53 +0200 Subject: [PATCH 185/227] Add timestamps to position and behavior events (#147) * Add timestamps to position events and behaviors. - Take original event timestamps into consideration so nested tap-holds have proper timing. - Add position and timestamp to keycode state changed event so the one-shot behavior can properly identify other keypresses and timings. - Add timestamp to position events received from peripheral * reduce number of arguments to behaviors --- app/include/drivers/behavior.h | 44 ++++--- app/include/zmk/behavior.h | 6 + .../zmk/events/keycode-state-changed.h | 1 - .../zmk/events/position-state-changed.h | 1 + app/include/zmk/keymap.h | 2 +- app/src/behaviors/behavior_bt.c | 18 +-- app/src/behaviors/behavior_hold_tap.c | 114 +++++++++++------- app/src/behaviors/behavior_key_press.c | 19 ++- app/src/behaviors/behavior_momentary_layer.c | 17 +-- app/src/behaviors/behavior_none.c | 10 +- app/src/behaviors/behavior_reset.c | 7 +- app/src/behaviors/behavior_rgb_underglow.c | 6 +- .../behavior_sensor_rotate_key_press.c | 11 +- app/src/behaviors/behavior_toggle_layer.c | 15 +-- app/src/behaviors/behavior_transparent.c | 10 +- app/src/keymap.c | 22 ++-- app/src/kscan.c | 1 + app/src/split/bluetooth/central.c | 1 + .../balanced/many-nested/events.patterns | 4 + .../many-nested/keycode_events.snapshot | 20 +++ .../balanced/many-nested/native_posix.keymap | 41 +++++++ 21 files changed, 248 insertions(+), 122 deletions(-) create mode 100644 app/tests/hold-tap/balanced/many-nested/events.patterns create mode 100644 app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot create mode 100644 app/tests/hold-tap/balanced/many-nested/native_posix.keymap diff --git a/app/include/drivers/behavior.h b/app/include/drivers/behavior.h index 45b8bea7..cf259b13 100644 --- a/app/include/drivers/behavior.h +++ b/app/include/drivers/behavior.h @@ -10,6 +10,7 @@ #include #include #include +#include /** * @cond INTERNAL_HIDDEN @@ -19,10 +20,10 @@ * (Internal use only.) */ -typedef int (*behavior_keymap_binding_callback_t)(struct device *dev, u32_t position, u32_t param1, - u32_t param2); -typedef int (*behavior_sensor_keymap_binding_callback_t)(struct device *dev, struct device *sensor, - u32_t param1, u32_t param2); +typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event); +typedef int (*behavior_sensor_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, + struct device *sensor); __subsystem struct behavior_driver_api { behavior_keymap_binding_callback_t binding_pressed; @@ -42,18 +43,19 @@ __subsystem struct behavior_driver_api { * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_keymap_binding_pressed(struct device *dev, u32_t position, u32_t param1, - u32_t param2); +__syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event); -static inline int z_impl_behavior_keymap_binding_pressed(struct device *dev, u32_t position, - u32_t param1, u32_t param2) { +static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; if (api->binding_pressed == NULL) { return -ENOTSUP; } - return api->binding_pressed(dev, position, param1, param2); + return api->binding_pressed(binding, event); } /** @@ -64,18 +66,19 @@ static inline int z_impl_behavior_keymap_binding_pressed(struct device *dev, u32 * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_keymap_binding_released(struct device *dev, u32_t position, u32_t param1, - u32_t param2); +__syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event); -static inline int z_impl_behavior_keymap_binding_released(struct device *dev, u32_t position, - u32_t param1, u32_t param2) { +static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; if (api->binding_released == NULL) { return -ENOTSUP; } - return api->binding_released(dev, position, param1, param2); + return api->binding_released(binding, event); } /** @@ -88,19 +91,20 @@ static inline int z_impl_behavior_keymap_binding_released(struct device *dev, u3 * @retval 0 If successful. * @retval Negative errno code if failure. */ -__syscall int behavior_sensor_keymap_binding_triggered(struct device *dev, struct device *sensor, - u32_t param1, u32_t param2); +__syscall int behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding, + struct device *sensor); -static inline int z_impl_behavior_sensor_keymap_binding_triggered(struct device *dev, - struct device *sensor, - u32_t param1, u32_t param2) { +static inline int +z_impl_behavior_sensor_keymap_binding_triggered(struct zmk_behavior_binding *binding, + struct device *sensor) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->driver_api; if (api->sensor_binding_triggered == NULL) { return -ENOTSUP; } - return api->sensor_binding_triggered(dev, sensor, param1, param2); + return api->sensor_binding_triggered(binding, sensor); } /** diff --git a/app/include/zmk/behavior.h b/app/include/zmk/behavior.h index 6f5815f1..428ae243 100644 --- a/app/include/zmk/behavior.h +++ b/app/include/zmk/behavior.h @@ -10,4 +10,10 @@ struct zmk_behavior_binding { char *behavior_dev; u32_t param1; u32_t param2; +}; + +struct zmk_behavior_binding_event { + int layer; + u32_t position; + s64_t timestamp; }; \ No newline at end of file diff --git a/app/include/zmk/events/keycode-state-changed.h b/app/include/zmk/events/keycode-state-changed.h index 4c006543..1e2c24e8 100644 --- a/app/include/zmk/events/keycode-state-changed.h +++ b/app/include/zmk/events/keycode-state-changed.h @@ -24,6 +24,5 @@ inline struct keycode_state_changed *create_keycode_state_changed(u8_t usage_pag ev->usage_page = usage_page; ev->keycode = keycode; ev->state = state; - return ev; } \ No newline at end of file diff --git a/app/include/zmk/events/position-state-changed.h b/app/include/zmk/events/position-state-changed.h index f88080d2..e4cbbbe7 100644 --- a/app/include/zmk/events/position-state-changed.h +++ b/app/include/zmk/events/position-state-changed.h @@ -13,6 +13,7 @@ struct position_state_changed { struct zmk_event_header header; u32_t position; bool state; + s64_t timestamp; }; ZMK_EVENT_DECLARE(position_state_changed); \ No newline at end of file diff --git a/app/include/zmk/keymap.h b/app/include/zmk/keymap.h index 61925878..b8f49694 100644 --- a/app/include/zmk/keymap.h +++ b/app/include/zmk/keymap.h @@ -11,4 +11,4 @@ int zmk_keymap_layer_activate(u8_t layer); int zmk_keymap_layer_deactivate(u8_t layer); int zmk_keymap_layer_toggle(u8_t layer); -int zmk_keymap_position_state_changed(u32_t position, bool pressed); +int zmk_keymap_position_state_changed(u32_t position, bool pressed, s64_t timestamp); diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 09fadba2..922c1571 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -8,18 +8,18 @@ #include #include - #include - #include - #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t command, u32_t arg) { - switch (command) { +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { case BT_CLR_CMD: return zmk_ble_clear_bonds(); case BT_NXT_CMD: @@ -27,9 +27,9 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c case BT_PRV_CMD: return zmk_ble_prof_prev(); case BT_SEL_CMD: - return zmk_ble_prof_select(arg); + return zmk_ble_prof_select(binding->param2); default: - LOG_ERR("Unknown BT command: %d", command); + LOG_ERR("Unknown BT command: %d", binding->param1); } return -ENOTSUP; @@ -37,8 +37,8 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c static int behavior_bt_init(struct device *dev) { return 0; }; -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, - u32_t arg) { +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { return 0; } diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c index 8f307a6b..8b3620ef 100644 --- a/app/src/behaviors/behavior_hold_tap.c +++ b/app/src/behaviors/behavior_hold_tap.c @@ -10,7 +10,6 @@ #include #include #include - #include #include #include @@ -18,6 +17,7 @@ #include #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -40,10 +40,8 @@ struct behavior_hold_tap_behaviors { struct zmk_behavior_binding hold; }; -typedef k_timeout_t (*timer_func)(); - struct behavior_hold_tap_config { - timer_func tapping_term_ms; + int tapping_term_ms; struct behavior_hold_tap_behaviors *behaviors; enum flavor flavor; }; @@ -51,8 +49,10 @@ struct behavior_hold_tap_config { // this data is specific for each hold-tap struct active_hold_tap { s32_t position; + // todo: move these params into the config->behaviors->tap and u32_t param_hold; u32_t param_tap; + s64_t timestamp; bool is_decided; bool is_hold; const struct behavior_hold_tap_config *config; @@ -164,6 +164,7 @@ static struct active_hold_tap *find_hold_tap(u32_t position) { } static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, u32_t param_tap, + s64_t timestamp, const struct behavior_hold_tap_config *config) { for (int i = 0; i < ZMK_BHV_HOLD_TAP_MAX_HELD; i++) { if (active_hold_taps[i].position != ZMK_BHV_HOLD_TAP_POSITION_NOT_USED) { @@ -175,6 +176,7 @@ static struct active_hold_tap *store_hold_tap(u32_t position, u32_t param_hold, active_hold_taps[i].config = config; active_hold_taps[i].param_hold = param_hold; active_hold_taps[i].param_tap = param_tap; + active_hold_taps[i].timestamp = timestamp; return &active_hold_taps[i]; } return NULL; @@ -253,7 +255,7 @@ static inline char *flavor_str(enum flavor flavor) { return "UNKNOWN FLAVOR"; } -static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event) { +static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_moment event_type) { if (hold_tap->is_decided) { return; } @@ -265,11 +267,11 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome switch (hold_tap->config->flavor) { case ZMK_BHV_HOLD_TAP_FLAVOR_HOLD_PREFERRED: - decide_hold_preferred(hold_tap, event); + decide_hold_preferred(hold_tap, event_type); case ZMK_BHV_HOLD_TAP_FLAVOR_BALANCED: - decide_balanced(hold_tap, event); + decide_balanced(hold_tap, event_type); case ZMK_BHV_HOLD_TAP_FLAVOR_TAP_PREFERRED: - decide_tap_preferred(hold_tap, event); + decide_tap_preferred(hold_tap, event_type); } if (!hold_tap->is_decided) { @@ -277,26 +279,31 @@ static void decide_hold_tap(struct active_hold_tap *hold_tap, enum decision_mome } LOG_DBG("%d decided %s (%s event %d)", hold_tap->position, hold_tap->is_hold ? "hold" : "tap", - flavor_str(hold_tap->config->flavor), event); + flavor_str(hold_tap->config->flavor), event_type); undecided_hold_tap = NULL; - struct zmk_behavior_binding *behavior; + struct zmk_behavior_binding_event event = { + .position = hold_tap->position, + .timestamp = hold_tap->timestamp, + }; + + struct zmk_behavior_binding binding; if (hold_tap->is_hold) { - behavior = &hold_tap->config->behaviors->hold; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_hold, - 0); + binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev; + binding.param1 = hold_tap->param_hold; + binding.param2 = 0; } else { - behavior = &hold_tap->config->behaviors->tap; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_pressed(behavior_device, hold_tap->position, hold_tap->param_tap, - 0); + binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev; + binding.param1 = hold_tap->param_tap; + binding.param2 = 0; } + behavior_keymap_binding_pressed(&binding, event); release_captured_events(); } -static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t param_hold, - u32_t param_tap) { +static int on_hold_tap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_hold_tap_config *cfg = dev->config_info; if (undecided_hold_tap != NULL) { @@ -305,54 +312,69 @@ static int on_hold_tap_binding_pressed(struct device *dev, u32_t position, u32_t return 0; } - struct active_hold_tap *hold_tap = store_hold_tap(position, param_hold, param_tap, cfg); + struct active_hold_tap *hold_tap = + store_hold_tap(event.position, binding->param1, binding->param2, event.timestamp, cfg); if (hold_tap == NULL) { LOG_ERR("unable to store hold-tap info, did you press more than %d hold-taps?", ZMK_BHV_HOLD_TAP_MAX_HELD); return 0; } - LOG_DBG("%d new undecided hold_tap", position); + LOG_DBG("%d new undecided hold_tap", event.position); undecided_hold_tap = hold_tap; - k_delayed_work_submit(&hold_tap->work, cfg->tapping_term_ms()); - // todo: once we get timing info for keypresses, start the timer relative to the original - // keypress don't forget to simulate a timer-event before the event after that time was handled. + // if this behavior was queued we have to adjust the timer to only + // wait for the remaining time. + s32_t tapping_term_ms_left = (hold_tap->timestamp + cfg->tapping_term_ms) - k_uptime_get(); + if (tapping_term_ms_left > 0) { + k_delayed_work_submit(&hold_tap->work, K_MSEC(tapping_term_ms_left)); + } return 0; } -static int on_hold_tap_binding_released(struct device *dev, u32_t position, u32_t _, u32_t __) { - struct active_hold_tap *hold_tap = find_hold_tap(position); - +static int on_hold_tap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct active_hold_tap *hold_tap = find_hold_tap(event.position); if (hold_tap == NULL) { LOG_ERR("ACTIVE_HOLD_TAP_CLEANED_UP_TOO_EARLY"); return 0; } + // If these events were queued, the timer event may be queued too late or not at all. + // We insert a timer event before the TH_KEY_UP event to verify. int work_cancel_result = k_delayed_work_cancel(&hold_tap->work); + if (event.timestamp > (hold_tap->timestamp + hold_tap->config->tapping_term_ms)) { + decide_hold_tap(hold_tap, HT_TIMER_EVENT); + } + decide_hold_tap(hold_tap, HT_KEY_UP); - struct zmk_behavior_binding *behavior; + // todo: set up the binding and data items inside of the active_hold_tap struct + struct zmk_behavior_binding_event sub_behavior_data = { + .position = hold_tap->position, + .timestamp = hold_tap->timestamp, + }; + + struct zmk_behavior_binding sub_behavior_binding; if (hold_tap->is_hold) { - behavior = &hold_tap->config->behaviors->hold; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_hold, - 0); + sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->hold.behavior_dev; + sub_behavior_binding.param1 = hold_tap->param_hold; + sub_behavior_binding.param2 = 0; } else { - behavior = &hold_tap->config->behaviors->tap; - struct device *behavior_device = device_get_binding(behavior->behavior_dev); - behavior_keymap_binding_released(behavior_device, hold_tap->position, hold_tap->param_tap, - 0); + sub_behavior_binding.behavior_dev = hold_tap->config->behaviors->tap.behavior_dev; + sub_behavior_binding.param1 = hold_tap->param_tap; + sub_behavior_binding.param2 = 0; } + behavior_keymap_binding_released(&sub_behavior_binding, sub_behavior_data); if (work_cancel_result == -EINPROGRESS) { // let the timer handler clean up // if we'd clear now, the timer may call back for an uninitialized active_hold_tap. - LOG_DBG("%d hold-tap timer work in event queue", position); + LOG_DBG("%d hold-tap timer work in event queue", event.position); hold_tap->work_is_cancelled = true; } else { - LOG_DBG("%d cleaning up hold-tap", position); + LOG_DBG("%d cleaning up hold-tap", event.position); clear_hold_tap(hold_tap); } @@ -382,6 +404,14 @@ static int position_state_changed_listener(const struct zmk_event_header *eh) { } } + // If these events were queued, the timer event may be queued too late or not at all. + // We make a timer decision before the other key events are handled if the timer would + // have run out. + if (ev->timestamp > + (undecided_hold_tap->timestamp + undecided_hold_tap->config->tapping_term_ms)) { + decide_hold_tap(undecided_hold_tap, HT_TIMER_EVENT); + } + if (!ev->state && find_captured_keydown_event(ev->position) == NULL) { // no keydown event has been captured, let it bubble. // we'll catch modifiers later in modifier_state_changed_listener @@ -463,6 +493,7 @@ static int behavior_hold_tap_init(struct device *dev) { struct behavior_hold_tap_data {}; static struct behavior_hold_tap_data behavior_hold_tap_data; +/* todo: get rid of unused param1 and param2. */ #define _TRANSFORM_ENTRY(idx, node) \ { \ .behavior_dev = DT_LABEL(DT_INST_PHANDLE_BY_IDX(node, bindings, idx)), \ @@ -473,14 +504,11 @@ static struct behavior_hold_tap_data behavior_hold_tap_data; }, #define KP_INST(n) \ - static k_timeout_t behavior_hold_tap_config_##n##_gettime() { \ - return K_MSEC(DT_INST_PROP(n, tapping_term_ms)); \ - } \ static struct behavior_hold_tap_behaviors behavior_hold_tap_behaviors_##n = { \ .hold = _TRANSFORM_ENTRY(0, n).tap = _TRANSFORM_ENTRY(1, n)}; \ static struct behavior_hold_tap_config behavior_hold_tap_config_##n = { \ .behaviors = &behavior_hold_tap_behaviors_##n, \ - .tapping_term_ms = &behavior_hold_tap_config_##n##_gettime, \ + .tapping_term_ms = DT_INST_PROP(n, tapping_term_ms), \ .flavor = DT_ENUM_IDX(DT_DRV_INST(n), flavor), \ }; \ DEVICE_AND_API_INIT(behavior_hold_tap_##n, DT_INST_LABEL(n), behavior_hold_tap_init, \ diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c index bbfbe369..d691e9fe 100644 --- a/app/src/behaviors/behavior_key_press.c +++ b/app/src/behaviors/behavior_key_press.c @@ -12,6 +12,7 @@ #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -22,18 +23,24 @@ struct behavior_key_press_data {}; static int behavior_key_press_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t keycode, u32_t _) { +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_key_press_config *cfg = dev->config_info; - LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); + LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", event.position, cfg->usage_page, + binding->param1); - return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, true)); + return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, binding->param1, true)); } -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t keycode, u32_t _) { +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_key_press_config *cfg = dev->config_info; - LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", position, cfg->usage_page, keycode); + LOG_DBG("position %d usage_page 0x%02X keycode 0x%02X", event.position, cfg->usage_page, + binding->param1); - return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, keycode, false)); + return ZMK_EVENT_RAISE(create_keycode_state_changed(cfg->usage_page, binding->param1, false)); } static const struct behavior_driver_api behavior_key_press_driver_api = { diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c index 80b7165b..b1fb14b0 100644 --- a/app/src/behaviors/behavior_momentary_layer.c +++ b/app/src/behaviors/behavior_momentary_layer.c @@ -11,6 +11,7 @@ #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -19,16 +20,16 @@ struct behavior_mo_data {}; static int behavior_mo_init(struct device *dev) { return 0; }; -static int mo_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) { - LOG_DBG("position %d layer %d", position, layer); - - return zmk_keymap_layer_activate(layer); +static int mo_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return zmk_keymap_layer_activate(binding->param1); } -static int mo_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) { - LOG_DBG("position %d layer %d", position, layer); - - return zmk_keymap_layer_deactivate(layer); +static int mo_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return zmk_keymap_layer_deactivate(binding->param1); } static const struct behavior_driver_api behavior_mo_driver_api = { diff --git a/app/src/behaviors/behavior_none.c b/app/src/behaviors/behavior_none.c index b548e6f7..96ea9d5d 100644 --- a/app/src/behaviors/behavior_none.c +++ b/app/src/behaviors/behavior_none.c @@ -11,6 +11,8 @@ #include #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); struct behavior_none_config {}; @@ -18,13 +20,13 @@ struct behavior_none_data {}; static int behavior_none_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, - u32_t _param2) { +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { return 0; } -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, - u32_t _param2) { +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { return 0; } diff --git a/app/src/behaviors/behavior_reset.c b/app/src/behaviors/behavior_reset.c index 90de20b0..d1233a51 100644 --- a/app/src/behaviors/behavior_reset.c +++ b/app/src/behaviors/behavior_reset.c @@ -11,6 +11,8 @@ #include #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); struct behavior_reset_config { @@ -19,8 +21,9 @@ struct behavior_reset_config { static int behavior_reset_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, - u32_t _param2) { +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_reset_config *cfg = dev->config_info; // TODO: Correct magic code for going into DFU? diff --git a/app/src/behaviors/behavior_rgb_underglow.c b/app/src/behaviors/behavior_rgb_underglow.c index 621eab5e..2ee6716a 100644 --- a/app/src/behaviors/behavior_rgb_underglow.c +++ b/app/src/behaviors/behavior_rgb_underglow.c @@ -12,13 +12,15 @@ #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int behavior_rgb_underglow_init(struct device *dev) { return 0; } -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t action, u32_t _) { - switch (action) { +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + switch (binding->param1) { case RGB_TOG: return zmk_rgb_underglow_toggle(); case RGB_HUI: diff --git a/app/src/behaviors/behavior_sensor_rotate_key_press.c b/app/src/behaviors/behavior_sensor_rotate_key_press.c index 1a0bf03a..71c4376c 100644 --- a/app/src/behaviors/behavior_sensor_rotate_key_press.c +++ b/app/src/behaviors/behavior_sensor_rotate_key_press.c @@ -23,15 +23,16 @@ struct behavior_sensor_rotate_key_press_data {}; static int behavior_sensor_rotate_key_press_init(struct device *dev) { return 0; }; -static int on_sensor_binding_triggered(struct device *dev, struct device *sensor, - u32_t increment_keycode, u32_t decrement_keycode) { +static int on_sensor_binding_triggered(struct zmk_behavior_binding *binding, + struct device *sensor) { + struct device *dev = device_get_binding(binding->behavior_dev); const struct behavior_sensor_rotate_key_press_config *cfg = dev->config_info; struct sensor_value value; int err; u32_t keycode; struct keycode_state_changed *ev; LOG_DBG("usage_page 0x%02X inc keycode 0x%02X dec keycode 0x%02X", cfg->usage_page, - increment_keycode, decrement_keycode); + binding->param1, binding->param2); err = sensor_channel_get(sensor, SENSOR_CHAN_ROTATION, &value); @@ -42,10 +43,10 @@ static int on_sensor_binding_triggered(struct device *dev, struct device *sensor switch (value.val1) { case 1: - keycode = increment_keycode; + keycode = binding->param1; break; case -1: - keycode = decrement_keycode; + keycode = binding->param2; break; default: return -ENOTSUP; diff --git a/app/src/behaviors/behavior_toggle_layer.c b/app/src/behaviors/behavior_toggle_layer.c index 28194519..b3c69614 100644 --- a/app/src/behaviors/behavior_toggle_layer.c +++ b/app/src/behaviors/behavior_toggle_layer.c @@ -11,6 +11,7 @@ #include #include +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -19,15 +20,15 @@ struct behavior_tog_data {}; static int behavior_tog_init(struct device *dev) { return 0; }; -static int tog_keymap_binding_pressed(struct device *dev, u32_t position, u32_t layer, u32_t _) { - LOG_DBG("position %d layer %d", position, layer); - - return zmk_keymap_layer_toggle(layer); +static int tog_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); + return zmk_keymap_layer_toggle(binding->param1); } -static int tog_keymap_binding_released(struct device *dev, u32_t position, u32_t layer, u32_t _) { - LOG_DBG("position %d layer %d", position, layer); - +static int tog_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { + LOG_DBG("position %d layer %d", event.position, binding->param1); return 0; } diff --git a/app/src/behaviors/behavior_transparent.c b/app/src/behaviors/behavior_transparent.c index f7852f39..cede3699 100644 --- a/app/src/behaviors/behavior_transparent.c +++ b/app/src/behaviors/behavior_transparent.c @@ -11,6 +11,8 @@ #include #include +#include + LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); struct behavior_transparent_config {}; @@ -18,13 +20,13 @@ struct behavior_transparent_data {}; static int behavior_transparent_init(struct device *dev) { return 0; }; -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t _param1, - u32_t _param2) { +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { return 1; } -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t _param1, - u32_t _param2) { +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { return 1; } diff --git a/app/src/keymap.c b/app/src/keymap.c index a87ce04b..74fe60db 100644 --- a/app/src/keymap.c +++ b/app/src/keymap.c @@ -104,9 +104,14 @@ bool is_active_layer(u8_t layer, u32_t layer_state) { return (layer_state & BIT(layer)) == BIT(layer) || layer == zmk_keymap_layer_default; } -int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed) { +int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed, s64_t timestamp) { struct zmk_behavior_binding *binding = &zmk_keymap[layer][position]; struct device *behavior; + struct zmk_behavior_binding_event event = { + .layer = layer, + .position = position, + .timestamp = timestamp, + }; LOG_DBG("layer: %d position: %d, binding name: %s", layer, position, log_strdup(binding->behavior_dev)); @@ -119,20 +124,18 @@ int zmk_keymap_apply_position_state(int layer, u32_t position, bool pressed) { } if (pressed) { - return behavior_keymap_binding_pressed(behavior, position, binding->param1, - binding->param2); + return behavior_keymap_binding_pressed(binding, event); } else { - return behavior_keymap_binding_released(behavior, position, binding->param1, - binding->param2); + return behavior_keymap_binding_released(binding, event); } } -int zmk_keymap_position_state_changed(u32_t position, bool pressed) { +int zmk_keymap_position_state_changed(u32_t position, bool pressed, s64_t timestamp) { for (int layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer >= zmk_keymap_layer_default; layer--) { u32_t layer_state = pressed ? zmk_keymap_layer_state : zmk_keymap_active_behavior_layer[position]; if (is_active_layer(layer, layer_state)) { - int ret = zmk_keymap_apply_position_state(layer, position, pressed); + int ret = zmk_keymap_apply_position_state(layer, position, pressed, timestamp); zmk_keymap_active_behavior_layer[position] = zmk_keymap_layer_state; @@ -171,8 +174,7 @@ int zmk_keymap_sensor_triggered(u8_t sensor_number, struct device *sensor) { continue; } - ret = behavior_sensor_keymap_binding_triggered(behavior, sensor, binding->param1, - binding->param2); + ret = behavior_sensor_keymap_binding_triggered(binding, sensor); if (ret > 0) { LOG_DBG("behavior processing to continue to next layer"); @@ -194,7 +196,7 @@ int zmk_keymap_sensor_triggered(u8_t sensor_number, struct device *sensor) { int keymap_listener(const struct zmk_event_header *eh) { if (is_position_state_changed(eh)) { const struct position_state_changed *ev = cast_position_state_changed(eh); - return zmk_keymap_position_state_changed(ev->position, ev->state); + return zmk_keymap_position_state_changed(ev->position, ev->state, ev->timestamp); #if ZMK_KEYMAP_HAS_SENSORS } else if (is_sensor_event(eh)) { const struct sensor_event *ev = cast_sensor_event(eh); diff --git a/app/src/kscan.c b/app/src/kscan.c index 0046f5ca..8575e708 100644 --- a/app/src/kscan.c +++ b/app/src/kscan.c @@ -52,6 +52,7 @@ void zmk_kscan_process_msgq(struct k_work *item) { pos_ev = new_position_state_changed(); pos_ev->state = pressed; pos_ev->position = position; + pos_ev->timestamp = k_uptime_get(); ZMK_EVENT_RAISE(pos_ev); } } diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c index cb1b68be..ed52ba07 100644 --- a/app/src/split/bluetooth/central.c +++ b/app/src/split/bluetooth/central.c @@ -60,6 +60,7 @@ static u8_t split_central_notify_func(struct bt_conn *conn, struct bt_gatt_subsc struct position_state_changed *pos_ev = new_position_state_changed(); pos_ev->position = position; pos_ev->state = pressed; + pos_ev->timestamp = k_uptime_get(); LOG_DBG("Trigger key position state change for %d", position); ZMK_EVENT_RAISE(pos_ev); diff --git a/app/tests/hold-tap/balanced/many-nested/events.patterns b/app/tests/hold-tap/balanced/many-nested/events.patterns new file mode 100644 index 00000000..fdf2b15c --- /dev/null +++ b/app/tests/hold-tap/balanced/many-nested/events.patterns @@ -0,0 +1,4 @@ +s/.*hid_listener_keycode/kp/p +s/.*mo_keymap_binding/mo/p +s/.*on_hold_tap_binding/ht_binding/p +s/.*decide_hold_tap/ht_decide/p \ No newline at end of file diff --git a/app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot b/app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot new file mode 100644 index 00000000..806896fb --- /dev/null +++ b/app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot @@ -0,0 +1,20 @@ +ht_binding_pressed: 0 new undecided hold_tap +ht_decide: 0 decided hold (balanced event 3) +kp_pressed: usage_page 0x07 keycode 0xe1 +ht_binding_pressed: 1 new undecided hold_tap +ht_decide: 1 decided hold (balanced event 3) +kp_pressed: usage_page 0x07 keycode 0xe0 +ht_binding_pressed: 2 new undecided hold_tap +ht_binding_released: 0 cleaning up hold-tap +ht_decide: 2 decided hold (balanced event 3) +kp_pressed: usage_page 0x07 keycode 0xe3 +ht_binding_pressed: 3 new undecided hold_tap +ht_binding_released: 1 cleaning up hold-tap +ht_decide: 3 decided hold (balanced event 3) +kp_pressed: usage_page 0x07 keycode 0xe2 +kp_released: usage_page 0x07 keycode 0xe1 +kp_released: usage_page 0x07 keycode 0xe0 +kp_released: usage_page 0x07 keycode 0xe3 +ht_binding_released: 2 cleaning up hold-tap +kp_released: usage_page 0x07 keycode 0xe2 +ht_binding_released: 3 cleaning up hold-tap diff --git a/app/tests/hold-tap/balanced/many-nested/native_posix.keymap b/app/tests/hold-tap/balanced/many-nested/native_posix.keymap new file mode 100644 index 00000000..3cb04c34 --- /dev/null +++ b/app/tests/hold-tap/balanced/many-nested/native_posix.keymap @@ -0,0 +1,41 @@ +#include +#include +#include + +/ { + behaviors { + ht_bal: behavior_hold_tap_balanced { + compatible = "zmk,behavior-hold-tap"; + label = "HOLD_TAP_BALANCED"; + #binding-cells = <2>; + flavor = "balanced"; + tapping_term_ms = <300>; + bindings = <&kp>, <&kp>; + }; + }; + + keymap { + compatible = "zmk,keymap"; + label ="Default keymap"; + + default_layer { + bindings = < + &ht_bal LSFT F &ht_bal LCTL J + &ht_bal LGUI H &ht_bal LALT L + >; + }; + }; +}; + +&kscan { + events = < + ZMK_MOCK_PRESS(0,0,100) + ZMK_MOCK_PRESS(0,1,100) + ZMK_MOCK_PRESS(1,0,100) + ZMK_MOCK_PRESS(1,1,100) + ZMK_MOCK_RELEASE(0,0,100) + ZMK_MOCK_RELEASE(0,1,100) + ZMK_MOCK_RELEASE(1,0,100) + ZMK_MOCK_RELEASE(1,1,100) + >; +}; From 7fc7a351170fb2017cb40e8de79b4535a936a6f6 Mon Sep 17 00:00:00 2001 From: Mubeen Khan Date: Sat, 10 Oct 2020 16:51:17 -0500 Subject: [PATCH 186/227] Revised keymap to Qwerty --- app/boards/shields/tg4x/tg4x.keymap | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/app/boards/shields/tg4x/tg4x.keymap b/app/boards/shields/tg4x/tg4x.keymap index 64e98bb3..bee5c87b 100644 --- a/app/boards/shields/tg4x/tg4x.keymap +++ b/app/boards/shields/tg4x/tg4x.keymap @@ -31,27 +31,27 @@ default_layer { bindings = < - &kp GRAV &kp Q &kp W &kp F &kp P &kp B &kp J &kp L &kp U &kp Y &kp SCLN &kp BKSP - &kp TAB &hm LGUI A &hm LALT R &hm LCTL S &hm LSFT T &kp G &kp M &hm RSFT N &hm RCTL E &hm RALT I &hm RGUI O &kp RET - &kp LSFT &kp Z &kp X &kp C &kp D &kp V &kp K &kp H &kp CMMA &kp DOT &kp FSLH &kp QUOT - &kp LCTL &kp LALT &kp LGUI < 1 BKSP < 2 SPC &kp LARW &kp DARW &kp UARW &kp RARW + &kp ESC &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BKSP + &kp TAB &hm LGUI A &hm LALT S &hm LCTL D &hm LSFT F &kp G &kp H &hm RSFT J &hm RCTL K &hm RALT L &hm RGUI SCLN &kp RET + &kp LSFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH &kp QUOT + &kp LCTL &kp LALT &kp LGUI < 1 BKSP < 2 SPC &kp LARW &kp DARW &kp UARW &kp RARW >; }; lower { bindings = < - &kp ESC &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PRSC - &kp DEL &trans &kp VOLU &trans &trans &trans &trans &kp LARW &kp DARW &kp UARW &kp RARW &trans - &trans &trans &kp VOLD &trans &trans &trans &trans &trans &trans &bt BT_PRV &bt BT_NXT &bt BT_CLR - &bootloader &reset &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 + &kp GRAV &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp PRSC + &kp DEL &trans &kp VOLU &trans &trans &trans &trans &kp LARW &kp DARW &kp UARW &kp RARW &trans + &trans &trans &kp VOLD &trans &trans &trans &trans &trans &trans &bt BT_PRV &bt BT_NXT &bt BT_CLR + &bootloader &reset &trans &trans &trans &trans &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 >; }; raise { bindings = < - &kp ESC &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp PRSC - &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp BSLH - &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp TILD &kp HOME &kp PGUP &kp PGDN &kp END - &trans &trans &trans &trans &trans &trans &kp M_NEXT &kp M_VOLD &kp M_VOLU &kp M_PLAY + &kp GRAV &kp NUM_1 &kp NUM_2 &kp NUM_3 &kp NUM_4 &kp NUM_5 &kp NUM_6 &kp NUM_7 &kp NUM_8 &kp NUM_9 &kp NUM_0 &kp PRSC + &kp DEL &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp BSLH + &trans &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp TILD &kp HOME &kp PGUP &kp PGDN &kp END + &trans &trans &trans &trans &trans &trans &kp M_NEXT &kp M_VOLD &kp M_VOLU &kp M_PLAY >; }; }; From 5f58193cdefed39aca16802772f8eefdebc09513 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sat, 10 Oct 2020 21:40:22 +0000 Subject: [PATCH 187/227] fix: check out Bash scripts with LF Always check out Bashs scripts with Unix-style line endings so they work if you run them inside Docker on Windows. --- .gitattributes | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..3d05d86d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +* text=auto + +# Always use Unix-style line endings for Bash scripts so they work in +# Docker on Windows. +.bashrc text eol=lf +*.sh text eol=lf From 4aa45c6f40c3e640cebce58b4d10cd24dc61b8ed Mon Sep 17 00:00:00 2001 From: Kellen Carey Date: Sat, 10 Oct 2020 17:00:13 -0700 Subject: [PATCH 188/227] update setup.ps1 --- docs/static/setup.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index 1da57378..63bd5c0e 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -57,11 +57,11 @@ catch [System.Management.Automation.CommandNotFoundException] { } Test-Git-Config -Option "user.name" -ErrMsg "Git username not set!`nRun: git config --global user.name 'My Name'" -Test-Git-Config -Option "user.email" -ErrMsg "Git email not set!`nRun: git config --global user.name 'example@myemail.com'" +Test-Git-Config -Option "user.email" -ErrMsg "Git email not set!`nRun: git config --global user.email 'example@myemail.com'" -$permission = (Get-Acl $PSScriptRoot).Access | +$permission = (Get-Acl $pwd).Access | ?{$_.IdentityReference -match $env:UserName ` - -and $_.FileSystemRights -match "Read" ` + -and $_.FileSystemRights -match "FullControl" ` -or $_.FileSystemRights -match "Write" } | Select IdentityReference,FileSystemRights From 677746014c61a33040da45eccf76e869c6891f79 Mon Sep 17 00:00:00 2001 From: kurtis-lew Date: Sat, 10 Oct 2020 19:33:47 -0700 Subject: [PATCH 189/227] Addressing #138 - ZMK Config Folders --- docs/docs/customization.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/docs/customization.md b/docs/docs/customization.md index 0bb17941..261c40de 100644 --- a/docs/docs/customization.md +++ b/docs/docs/customization.md @@ -1,10 +1,21 @@ --- id: customization -title: Customizing ZMK +title: Customizing ZMK/`zmk-config` folders sidebar_label: Customizing ZMK --- After verifying you can successfully flash the default firmware, you will probably want to begin customizing your keymap and other keyboard options. +[In the initial setup tutorial](user-setup), you created a Github repository called `zmk-config`. This repository is a discrete filesystem which works +with the main `zmk` firmware repository to build your desired firmware. The main advantage of a discrete configuration folder is ensuring that the +working components of ZMK are kept separate from your personal keyboard settings, reducing the amount of file manipulation in the configuration process. +This makes flashing ZMK to your keyboard much easier, especially because you don't need to keep an up-to-date copy of zmk on your computer at all times. + +On default `zmk-config` folder should contain two files: +* `.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 @@ -26,8 +37,23 @@ 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](dev-build-flash), 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: + +``` +west build -b nice_nano -- -DSHIELD=kyria_left -DZMK_CONFIG="C:/Users/myUser/Documents/Github/zmk-config/config" +``` + ## Flashing Your Changes For normal keyboards, follow the same flashing instructions as before to flash your updated firmware. For split keyboards, only the central (left) side will need to be reflashed if you are just updating your keymap. +More troubleshooting information for split keyboards can be found [here](troubleshooting#split-keyboard-halves-unable-to-pair). From 23e9cbcaf9b00c87953a4a8b4e953ced154e1e4b Mon Sep 17 00:00:00 2001 From: Tsquash Date: Thu, 8 Oct 2020 20:40:28 -0500 Subject: [PATCH 190/227] Added Table and fixed Feature sentence added feature table new feature sentence --- docs/docs/intro.md | 49 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 8c1c043d..02a93e0c 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -13,31 +13,30 @@ feature. ## Features -At this point, ZMK is still missing many features. Currently, the working bits -include: - -- Wireless connectivity via BLE HID Over GATT (HOG) -- USB connectivity -- Low active power usage -- Split keyboard support -- [Keymaps and layers](behavior/layers) -- [Hold-tap](behavior/hold-tap) (which includes [mod-tap](behavior/mod-tap), [layer-tap](behavior/layers)) -- [Basic HID over USB](behavior/key-press) -- [Basic consumer (media) keycodes](behavior/key-press#consumer-key-press) -- [Encoders](feature/encoders) -- Basic [OLED display support](feature/displays) -- [RGB Underglow](feature/underglow) - -## Missing Features - -- One Shot Keys -- Combo keys -- Macros -- Complete split support (encoders and RGB are not supported on the 'peripheral' side) -- Battery reporting -- Low power sleep states -- Low power mode (to toggle LEDs and screen off) -- Shell over BLE +At this point, ZMK is still missing many features compared to more developed firmwares such as QMK. Here is a table comparing supported ZMK and QMK features: + +| | ZMK | QMK | +|----------------------------------------------------------------------------------------------------------|:---------:|:-----------:| +| Wireless Connectivity via BLE | ✅ | | +| USB Connectivity | ✅ | ✅ | +| Low Active Power Usage | ✅ | | +| Split Keyboard Support | ✅ | ✅ | +| [Keymaps and Layers](behavior/layers) | ✅ | ✅ | +| [Hold-tap](behavior/hold-tap) (which includes [mod-tap](behavior/mod-tap), [layer-tap](behavior/layers)) | ✅ | ✅ | +| [Basic HID over USB](behavior/key-press) | ✅ | ✅ | +| [Basic consumer (media) keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | +| [Encoders](feature/encoders) | ✅ | ✅ | +| Basic [OLED display support](feature/displays) | ✅ | ✅ | +| [RGB Underglow](feature/underglow) | ✅ | ✅ | +| One Shot Keys | | ✅ | +| Combo Keys | | ✅ | +| Macros | | ✅ | +| Mouse Keys | | ✅ | +| Battery Reporting | | | +| Low Power Sleep States | | | +| Low Power Mode (VCC Shutoff) | | | +| Shell over BLE | | | +| AVR/8 Bit | | ✅ | ## Code Of Conduct From 90b56a19410302b84aba5b9443f3e2f5b852a380 Mon Sep 17 00:00:00 2001 From: Tsquash Date: Thu, 8 Oct 2020 21:15:50 -0500 Subject: [PATCH 191/227] added in dev --- docs/docs/intro.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 02a93e0c..5d4b50e2 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -13,9 +13,9 @@ feature. ## Features -At this point, ZMK is still missing many features compared to more developed firmwares such as QMK. Here is a table comparing supported ZMK and QMK features: +At this point, ZMK is still missing many features compared to more developed firmware such as QMK. Here is a table comparing supported ZMK and QMK features: -| | ZMK | QMK | +| **Feature** | ZMK | QMK | |----------------------------------------------------------------------------------------------------------|:---------:|:-----------:| | Wireless Connectivity via BLE | ✅ | | | USB Connectivity | ✅ | ✅ | @@ -28,16 +28,17 @@ At this point, ZMK is still missing many features compared to more developed fir | [Encoders](feature/encoders) | ✅ | ✅ | | Basic [OLED display support](feature/displays) | ✅ | ✅ | | [RGB Underglow](feature/underglow) | ✅ | ✅ | -| One Shot Keys | | ✅ | -| Combo Keys | | ✅ | -| Macros | | ✅ | +| One Shot Keys | In Dev | ✅ | +| Combo Keys | In Dev | ✅ | +| Macros | In Dev | ✅ | | Mouse Keys | | ✅ | -| Battery Reporting | | | -| Low Power Sleep States | | | -| Low Power Mode (VCC Shutoff) | | | +| Battery Reporting | In Dev | | +| Low Power Sleep States | In Dev | | +| Low Power Mode (VCC Shutoff) | In Dev | | | Shell over BLE | | | +| Realtime Keymap Updating | In Dev | ✅ | | AVR/8 Bit | | ✅ | - +| Wide Range of ARM Chips Supported | ✅ | | ## Code Of Conduct Please note that this project is released with a From e740a83d68bfce54e2d0018d10b93c3242b3a9d9 Mon Sep 17 00:00:00 2001 From: Tsquash Date: Thu, 8 Oct 2020 23:33:58 -0500 Subject: [PATCH 192/227] Made columns wider --- docs/docs/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 5d4b50e2..62797661 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -15,7 +15,7 @@ feature. At this point, ZMK is still missing many features compared to more developed firmware such as QMK. Here is a table comparing supported ZMK and QMK features: -| **Feature** | ZMK | QMK | +| **Feature** |   ZMK   |   QMK   | |----------------------------------------------------------------------------------------------------------|:---------:|:-----------:| | Wireless Connectivity via BLE | ✅ | | | USB Connectivity | ✅ | ✅ | From 910e207dbcc17fc5120b56550270458a29e0663c Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot <61706196+Tsquash@users.noreply.github.com> Date: Fri, 9 Oct 2020 11:12:10 -0500 Subject: [PATCH 193/227] Update Intro changed intro wording and link to layer tap Update intro.md --- docs/docs/intro.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 62797661..8348c547 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -13,32 +13,35 @@ feature. ## Features -At this point, ZMK is still missing many features compared to more developed firmware such as QMK. Here is a table comparing supported ZMK and QMK features: +At this point, ZMK is still missing many features compared to popular firmware such as QMK. Here is a table comparing supported ZMK and QMK features: | **Feature** |   ZMK   |   QMK   | |----------------------------------------------------------------------------------------------------------|:---------:|:-----------:| -| Wireless Connectivity via BLE | ✅ | | +| Multi-Device BLE Support | ✅ | | | USB Connectivity | ✅ | ✅ | -| Low Active Power Usage | ✅ | | +| Low Active Power Usage | ✅ | | | Split Keyboard Support | ✅ | ✅ | | [Keymaps and Layers](behavior/layers) | ✅ | ✅ | -| [Hold-tap](behavior/hold-tap) (which includes [mod-tap](behavior/mod-tap), [layer-tap](behavior/layers)) | ✅ | ✅ | -| [Basic HID over USB](behavior/key-press) | ✅ | ✅ | +| [Hold-tap](behavior/hold-tap) (which includes [mod-tap](behavior/mod-tap), [layer-tap](behavior/layers/#layer-tap)) | ✅ | ✅ | +| [Basic Keycodes](behavior/key-press) | ✅ | ✅ | | [Basic consumer (media) keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | -| [Encoders](feature/encoders) | ✅ | ✅ | -| Basic [OLED display support](feature/displays) | ✅ | ✅ | +| [Encoders](feature/encoders)[^1] | ✅ | ✅ | +| Proof of Concept [OLED display support](feature/displays) | ✅ | ✅ | | [RGB Underglow](feature/underglow) | ✅ | ✅ | | One Shot Keys | In Dev | ✅ | | Combo Keys | In Dev | ✅ | | Macros | In Dev | ✅ | -| Mouse Keys | | ✅ | +| Mouse Keys | | ✅ | | Battery Reporting | In Dev | | -| Low Power Sleep States | In Dev | | +| Low Power Sleep States | In Dev | | | Low Power Mode (VCC Shutoff) | In Dev | | -| Shell over BLE | | | -| Realtime Keymap Updating | In Dev | ✅ | -| AVR/8 Bit | | ✅ | -| Wide Range of ARM Chips Supported | ✅ | | +| Shell over BLE | | | +| Realtime Keymap Updating | Planned | ✅ | +| AVR/8 Bit | | ✅ | +| Wide Range of ARM Chips Supported | ✅ | | +[^1]:Note: Encoders are not currently supported on peripheral side splits. + + ## Code Of Conduct Please note that this project is released with a From 93c5ae17acd509207e8109e3307b59b9f70aa3d1 Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot <61706196+Tsquash@users.noreply.github.com> Date: Fri, 9 Oct 2020 11:28:23 -0500 Subject: [PATCH 194/227] Uniformed Capitals, Added footnotes --- docs/docs/intro.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 8348c547..f0b15d54 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -22,11 +22,11 @@ At this point, ZMK is still missing many features compared to popular firmware s | Low Active Power Usage | ✅ | | | Split Keyboard Support | ✅ | ✅ | | [Keymaps and Layers](behavior/layers) | ✅ | ✅ | -| [Hold-tap](behavior/hold-tap) (which includes [mod-tap](behavior/mod-tap), [layer-tap](behavior/layers/#layer-tap)) | ✅ | ✅ | +| [Hold-Tap](behavior/hold-tap) (Which Includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | | [Basic Keycodes](behavior/key-press) | ✅ | ✅ | -| [Basic consumer (media) keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | +| [Basic consumer (Media) Keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | | [Encoders](feature/encoders)[^1] | ✅ | ✅ | -| Proof of Concept [OLED display support](feature/displays) | ✅ | ✅ | +| [OLED Display Support](feature/displays)[^2] | In Dev ✅ | | [RGB Underglow](feature/underglow) | ✅ | ✅ | | One Shot Keys | In Dev | ✅ | | Combo Keys | In Dev | ✅ | @@ -39,8 +39,8 @@ At this point, ZMK is still missing many features compared to popular firmware s | Realtime Keymap Updating | Planned | ✅ | | AVR/8 Bit | | ✅ | | Wide Range of ARM Chips Supported | ✅ | | -[^1]:Note: Encoders are not currently supported on peripheral side splits. - +[^1]: Encoders are not currently supported on peripheral side splits. +[2^]: Oleds are currently proof of concept in ZMK. ## Code Of Conduct From e2a845b2eb452abcf3eec500de06172dd08dc58a Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot <61706196+Tsquash@users.noreply.github.com> Date: Fri, 9 Oct 2020 11:29:07 -0500 Subject: [PATCH 195/227] removed checkmark from zmk oled --- docs/docs/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index f0b15d54..2090984a 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -26,7 +26,7 @@ At this point, ZMK is still missing many features compared to popular firmware s | [Basic Keycodes](behavior/key-press) | ✅ | ✅ | | [Basic consumer (Media) Keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | | [Encoders](feature/encoders)[^1] | ✅ | ✅ | -| [OLED Display Support](feature/displays)[^2] | In Dev ✅ | +| [OLED Display Support](feature/displays)[^2] | In Dev | | [RGB Underglow](feature/underglow) | ✅ | ✅ | | One Shot Keys | In Dev | ✅ | | Combo Keys | In Dev | ✅ | From eb9dc37f00759940ab172e0da102f3f303483e6f Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot <61706196+Tsquash@users.noreply.github.com> Date: Fri, 9 Oct 2020 11:30:14 -0500 Subject: [PATCH 196/227] fix table --- docs/docs/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 2090984a..89857a44 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -26,7 +26,7 @@ At this point, ZMK is still missing many features compared to popular firmware s | [Basic Keycodes](behavior/key-press) | ✅ | ✅ | | [Basic consumer (Media) Keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | | [Encoders](feature/encoders)[^1] | ✅ | ✅ | -| [OLED Display Support](feature/displays)[^2] | In Dev | +| [OLED Display Support](feature/displays)[^2] | In Dev | ✅ | | [RGB Underglow](feature/underglow) | ✅ | ✅ | | One Shot Keys | In Dev | ✅ | | Combo Keys | In Dev | ✅ | From d7bfe979c9a0d67b5b2a9a4f87bc496c32c4ff60 Mon Sep 17 00:00:00 2001 From: Tsquash Date: Fri, 9 Oct 2020 19:05:44 -0500 Subject: [PATCH 197/227] Fixed Footnote and added user config repo --- docs/docs/intro.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 89857a44..095ab41e 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -15,11 +15,11 @@ feature. At this point, ZMK is still missing many features compared to popular firmware such as QMK. Here is a table comparing supported ZMK and QMK features: -| **Feature** |   ZMK   |   QMK   | +| **Feature** | ZMK |QMK | |----------------------------------------------------------------------------------------------------------|:---------:|:-----------:| | Multi-Device BLE Support | ✅ | | | USB Connectivity | ✅ | ✅ | -| Low Active Power Usage | ✅ | | +| User Configuration Repositories | ✅ | | | Split Keyboard Support | ✅ | ✅ | | [Keymaps and Layers](behavior/layers) | ✅ | ✅ | | [Hold-Tap](behavior/hold-tap) (Which Includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | @@ -32,15 +32,16 @@ At this point, ZMK is still missing many features compared to popular firmware s | Combo Keys | In Dev | ✅ | | Macros | In Dev | ✅ | | Mouse Keys | | ✅ | -| Battery Reporting | In Dev | | +| Low Active Power Usage | ✅ | | | Low Power Sleep States | In Dev | | | Low Power Mode (VCC Shutoff) | In Dev | | +| Battery Reporting | In Dev | | | Shell over BLE | | | | Realtime Keymap Updating | Planned | ✅ | | AVR/8 Bit | | ✅ | | Wide Range of ARM Chips Supported | ✅ | | -[^1]: Encoders are not currently supported on peripheral side splits. -[2^]: Oleds are currently proof of concept in ZMK. +[^2]: Encoders are not currently supported on peripheral side splits. +[^1]: OLEDs are currently proof of concept in ZMK. ## Code Of Conduct From 21987d338558610ca38a48ca4109d2a1a25a4b53 Mon Sep 17 00:00:00 2001 From: Tsquash Date: Fri, 9 Oct 2020 21:50:35 -0500 Subject: [PATCH 198/227] update intro.md --- docs/docs/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 095ab41e..32222d10 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -19,7 +19,7 @@ At this point, ZMK is still missing many features compared to popular firmware s |----------------------------------------------------------------------------------------------------------|:---------:|:-----------:| | Multi-Device BLE Support | ✅ | | | USB Connectivity | ✅ | ✅ | -| User Configuration Repositories | ✅ | | +| User Configuration Repositories | ✅ | | | Split Keyboard Support | ✅ | ✅ | | [Keymaps and Layers](behavior/layers) | ✅ | ✅ | | [Hold-Tap](behavior/hold-tap) (Which Includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | From 229c8b4358afe4e9ac7dbbe176645ad4bf3cb1a2 Mon Sep 17 00:00:00 2001 From: Tsquash Date: Sat, 10 Oct 2020 12:39:36 -0500 Subject: [PATCH 199/227] Added BlueMicro Collumn --- docs/docs/intro.md | 56 +++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 32222d10..83291812 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -5,41 +5,37 @@ sidebar_label: Introduction --- ZMK Firmware is an open source (MIT) keyboard -firmware built on the [Zephyr™ Project](https://zephyrproject.org/) Real Time Operating System (RTOS). - -The goal is to provide a powerful, featureful keyboard firmware that is free -of licensing issues that prevent upstream BLE support as a first-class -feature. +firmware built on the [Zephyr™ Project](https://zephyrproject.org/) Real Time Operating System (RTOS). ZMK's goal is to provide a modern, wireless, and powerful firmware free of licensing issues. ## Features At this point, ZMK is still missing many features compared to popular firmware such as QMK. Here is a table comparing supported ZMK and QMK features: -| **Feature** | ZMK |QMK | -|----------------------------------------------------------------------------------------------------------|:---------:|:-----------:| -| Multi-Device BLE Support | ✅ | | -| USB Connectivity | ✅ | ✅ | -| User Configuration Repositories | ✅ | | -| Split Keyboard Support | ✅ | ✅ | -| [Keymaps and Layers](behavior/layers) | ✅ | ✅ | -| [Hold-Tap](behavior/hold-tap) (Which Includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | -| [Basic Keycodes](behavior/key-press) | ✅ | ✅ | -| [Basic consumer (Media) Keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | -| [Encoders](feature/encoders)[^1] | ✅ | ✅ | -| [OLED Display Support](feature/displays)[^2] | In Dev | ✅ | -| [RGB Underglow](feature/underglow) | ✅ | ✅ | -| One Shot Keys | In Dev | ✅ | -| Combo Keys | In Dev | ✅ | -| Macros | In Dev | ✅ | -| Mouse Keys | | ✅ | -| Low Active Power Usage | ✅ | | -| Low Power Sleep States | In Dev | | -| Low Power Mode (VCC Shutoff) | In Dev | | -| Battery Reporting | In Dev | | -| Shell over BLE | | | -| Realtime Keymap Updating | Planned | ✅ | -| AVR/8 Bit | | ✅ | -| Wide Range of ARM Chips Supported | ✅ | | +| **Feature** | ZMK | BlueMicro | QMK | +|--------------------------------------------------------------------------------------------------------|:-----------:|:------------:|:-----------:| +| Multi-Device BLE Support | ✅ | ✅ | | +| USB Connectivity | ✅ | | ✅ | +| User Configuration Repositories | ✅ | | | +| Split Keyboard Support | ✅ | ✅ | ✅ | +| [Keymaps and Layers](behavior/layers) | ✅ | ✅ | ✅ | +| [Hold-Tap](behavior/hold-tap) (Which Includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | ✅ | +| [Basic Keycodes](behavior/key-press) | ✅ | ✅ | ✅ | +| [Basic consumer (Media) Keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | ✅ | +| [Encoders](feature/encoders)[^1] | ✅ | | ✅ | +| [OLED Display Support](feature/displays)[^2] | In Dev | In Dev | ✅ | +| [RGB Underglow](feature/underglow) | ✅ | ✅ | ✅ | +| One Shot Keys | In Dev | ✅ | ✅ | +| Combo Keys | In Dev | | ✅ | +| Macros | In Dev | ✅ | ✅ | +| Mouse Keys | | ✅ | ✅ | +| Low Active Power Usage | ✅ | | | +| Low Power Sleep States | In Dev | ✅ | | +| Low Power Mode (VCC Shutoff) | In Dev | | | +| Battery Reporting | In Dev | ✅ | | +| Shell over BLE | | | | +| Realtime Keymap Updating | Planned | | ✅ | +| AVR/8 Bit | | | ✅ | +| Wide Range of ARM Chips Supported | ✅ | | | [^2]: Encoders are not currently supported on peripheral side splits. [^1]: OLEDs are currently proof of concept in ZMK. From 56ab812a6764d6ba0471f41e2806d3a7d076b8c8 Mon Sep 17 00:00:00 2001 From: Tsquash Date: Sat, 10 Oct 2020 12:53:44 -0500 Subject: [PATCH 200/227] fixed BLE part of table --- docs/docs/intro.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 83291812..ab211383 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -9,11 +9,12 @@ firmware built on the [Zephyr™ Project](https://zephyrproject.org/) Real Time ## Features -At this point, ZMK is still missing many features compared to popular firmware such as QMK. Here is a table comparing supported ZMK and QMK features: +At this point, ZMK is still missing many features compared to popular firmware such as QMK. Here is a table comparing supported ZMK, BlueMicro, and QMK features: | **Feature** | ZMK | BlueMicro | QMK | |--------------------------------------------------------------------------------------------------------|:-----------:|:------------:|:-----------:| -| Multi-Device BLE Support | ✅ | ✅ | | +| Low Latency BLE Support | ✅ | ✅ | | +| Multi-Device BLE Support | ✅ | | | | USB Connectivity | ✅ | | ✅ | | User Configuration Repositories | ✅ | | | | Split Keyboard Support | ✅ | ✅ | ✅ | From 593d7ff7812f2ec66d3bbafd577205137c59879f Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot Date: Sat, 10 Oct 2020 22:40:14 -0500 Subject: [PATCH 201/227] made table completely visual; changed feature sentence --- docs/docs/intro.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index ab211383..c5a214d3 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -9,7 +9,8 @@ firmware built on the [Zephyr™ Project](https://zephyrproject.org/) Real Time ## Features -At this point, ZMK is still missing many features compared to popular firmware such as QMK. Here is a table comparing supported ZMK, BlueMicro, and QMK features: +ZMK is currently missing some features found in other popular firmware. This table compares the features supported by ZMK, BlueMicro and QMK: + | **Feature** | ZMK | BlueMicro | QMK | |--------------------------------------------------------------------------------------------------------|:-----------:|:------------:|:-----------:| @@ -19,24 +20,24 @@ At this point, ZMK is still missing many features compared to popular firmware s | User Configuration Repositories | ✅ | | | | Split Keyboard Support | ✅ | ✅ | ✅ | | [Keymaps and Layers](behavior/layers) | ✅ | ✅ | ✅ | -| [Hold-Tap](behavior/hold-tap) (Which Includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | ✅ | +| [Hold-Tap](behavior/hold-tap) (which includes [Mod-Tap](behavior/mod-tap) and [Layer-Tap](behavior/layers/#layer-tap)) | ✅ | ✅ | ✅ | | [Basic Keycodes](behavior/key-press) | ✅ | ✅ | ✅ | | [Basic consumer (Media) Keycodes](behavior/key-press#consumer-key-press) | ✅ | ✅ | ✅ | | [Encoders](feature/encoders)[^1] | ✅ | | ✅ | -| [OLED Display Support](feature/displays)[^2] | In Dev | In Dev | ✅ | +| [OLED Display Support](feature/displays)[^2] | 🚧 | 🚧 | ✅ | | [RGB Underglow](feature/underglow) | ✅ | ✅ | ✅ | -| One Shot Keys | In Dev | ✅ | ✅ | -| Combo Keys | In Dev | | ✅ | -| Macros | In Dev | ✅ | ✅ | +| One Shot Keys | 🚧 | ✅ | ✅ | +| Combo Keys | 🚧 | | ✅ | +| Macros | 🚧 | ✅ | ✅ | | Mouse Keys | | ✅ | ✅ | | Low Active Power Usage | ✅ | | | -| Low Power Sleep States | In Dev | ✅ | | -| Low Power Mode (VCC Shutoff) | In Dev | | | -| Battery Reporting | In Dev | ✅ | | -| Shell over BLE | | | | -| Realtime Keymap Updating | Planned | | ✅ | -| AVR/8 Bit | | | ✅ | -| Wide Range of ARM Chips Supported | ✅ | | | +| Low Power Sleep States | 🚧 | ✅ | | +| Low Power Mode (VCC Shutoff) | 🚧 | | | +| Battery Reporting | 🚧 | ✅ | | +| Shell over BLE | | | | +| Realtime Keymap Updating | 💡 | | ✅ | +| AVR/8 Bit | | | ✅ | +| Wide Range of ARM Chips Supported | ✅ | | | [^2]: Encoders are not currently supported on peripheral side splits. [^1]: OLEDs are currently proof of concept in ZMK. From 1ef21c57ea4d186290b1a47110885a5e2bf2f043 Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot Date: Sat, 10 Oct 2020 23:03:07 -0500 Subject: [PATCH 202/227] added links to see progress of features. --- docs/docs/intro.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index c5a214d3..60fe0d22 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -31,13 +31,13 @@ ZMK is currently missing some features found in other popular firmware. This tab | Macros | 🚧 | ✅ | ✅ | | Mouse Keys | | ✅ | ✅ | | Low Active Power Usage | ✅ | | | -| Low Power Sleep States | 🚧 | ✅ | | -| Low Power Mode (VCC Shutoff) | 🚧 | | | -| Battery Reporting | 🚧 | ✅ | | +| [Low Power Sleep States](https://github.com/zmkfirmware/zmk/pull/211) | 🚧 | ✅ | | +| [Low Power Mode (VCC Shutoff)](https://github.com/zmkfirmware/zmk/pull/242) | 🚧 | | | +| [Battery Reporting](https://github.com/zmkfirmware/zmk/issues/47) | 🚧 | ✅ | | | Shell over BLE | | | | | Realtime Keymap Updating | 💡 | | ✅ | | AVR/8 Bit | | | ✅ | -| Wide Range of ARM Chips Supported | ✅ | | | +| [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | [^2]: Encoders are not currently supported on peripheral side splits. [^1]: OLEDs are currently proof of concept in ZMK. From 78cb6c8b2115b5eebeddc03d7d8ecff6ba2574a7 Mon Sep 17 00:00:00 2001 From: Nuxiom <61762260+nuxiom@users.noreply.github.com> Date: Sun, 11 Oct 2020 16:57:26 +1100 Subject: [PATCH 203/227] Fix kscan_gpio_irq_callback_handler_##n conditional macro --- app/drivers/zephyr/kscan_gpio_matrix.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index a0b22e4a..ea07ee88 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -181,19 +181,19 @@ static int kscan_gpio_config_interrupts(struct device **devices, struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ kscan_gpio_read_##n(data->dev); \ } \ - COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ - (static void kscan_gpio_irq_callback_handler_##n( \ - struct device *dev, struct gpio_callback *cb, gpio_port_pins_t pin) { \ - struct kscan_gpio_irq_callback_##n *data = \ - CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ - kscan_gpio_disable_interrupts_##n(data->dev); \ - COND_CODE_0(DT_INST_PROP(n, debounce_period), \ - ({ k_work_submit(data->work); }), ({ \ - k_delayed_work_cancel(data->work); \ - k_delayed_work_submit( \ - data->work, K_MSEC(DT_INST_PROP(n, debounce_period))); \ - })) \ - })) \ + static void kscan_gpio_irq_callback_handler_##n( \ + struct device *dev, struct gpio_callback *cb, gpio_port_pins_t pin) { \ + struct kscan_gpio_irq_callback_##n *data = \ + CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ + COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ + (kscan_gpio_disable_interrupts_##n(data->dev);)) \ + COND_CODE_0(DT_INST_PROP(n, debounce_period), \ + ({ k_work_submit(data->work); }), ({ \ + k_delayed_work_cancel(data->work); \ + k_delayed_work_submit( \ + data->work, K_MSEC(DT_INST_PROP(n, debounce_period))); \ + })) \ + } \ \ static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \ .rows = {[INST_MATRIX_ROWS(n) - 1] = NULL}, .cols = {[INST_MATRIX_COLS(n) - 1] = NULL}}; \ From 1c0c02e09773413752e5f166a30178073c570349 Mon Sep 17 00:00:00 2001 From: Nuxiom <61762260+nuxiom@users.noreply.github.com> Date: Sun, 11 Oct 2020 17:51:06 +1100 Subject: [PATCH 204/227] Reformatted according to clang-format lint --- app/drivers/zephyr/kscan_gpio_matrix.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/drivers/zephyr/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c index ea07ee88..ec4fb39a 100644 --- a/app/drivers/zephyr/kscan_gpio_matrix.c +++ b/app/drivers/zephyr/kscan_gpio_matrix.c @@ -181,17 +181,16 @@ static int kscan_gpio_config_interrupts(struct device **devices, struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \ kscan_gpio_read_##n(data->dev); \ } \ - static void kscan_gpio_irq_callback_handler_##n( \ - struct device *dev, struct gpio_callback *cb, gpio_port_pins_t pin) { \ + static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \ + gpio_port_pins_t pin) { \ struct kscan_gpio_irq_callback_##n *data = \ CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \ COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \ (kscan_gpio_disable_interrupts_##n(data->dev);)) \ - COND_CODE_0(DT_INST_PROP(n, debounce_period), \ - ({ k_work_submit(data->work); }), ({ \ + COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \ k_delayed_work_cancel(data->work); \ - k_delayed_work_submit( \ - data->work, K_MSEC(DT_INST_PROP(n, debounce_period))); \ + k_delayed_work_submit(data->work, \ + K_MSEC(DT_INST_PROP(n, debounce_period))); \ })) \ } \ \ From 7798c974f697afb43d13cf8692802caf87210b02 Mon Sep 17 00:00:00 2001 From: Joel Spadin Date: Sun, 11 Oct 2020 14:58:24 -0500 Subject: [PATCH 205/227] fix: don't leak bt_conn refs bt_conn_lookup_addr_le() gives us a new reference that must be released with bt_conn_unref() --- app/src/hog.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/hog.c b/app/src/hog.c index 11349acd..bcd652d2 100644 --- a/app/src/hog.c +++ b/app/src/hog.c @@ -164,8 +164,10 @@ int zmk_hog_send_keypad_report(struct zmk_hid_keypad_report_body *report) { LOG_DBG("Sending to NULL? %s", conn == NULL ? "yes" : "no"); - return bt_gatt_notify(conn, &hog_svc.attrs[5], report, - sizeof(struct zmk_hid_keypad_report_body)); + int err = + bt_gatt_notify(conn, &hog_svc.attrs[5], report, sizeof(struct zmk_hid_keypad_report_body)); + bt_conn_unref(conn); + return err; }; int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { @@ -174,6 +176,8 @@ int zmk_hog_send_consumer_report(struct zmk_hid_consumer_report_body *report) { return -ENOTCONN; } - return bt_gatt_notify(conn, &hog_svc.attrs[10], report, - sizeof(struct zmk_hid_consumer_report_body)); + int err = bt_gatt_notify(conn, &hog_svc.attrs[10], report, + sizeof(struct zmk_hid_consumer_report_body)); + bt_conn_unref(conn); + return err; }; From b5e1c8a7addc186d0bd542082482157ffb2d1f5a Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Sat, 10 Oct 2020 09:29:07 +0800 Subject: [PATCH 206/227] New behavior for ext power control --- app/CMakeLists.txt | 1 + app/boards/shields/lily58/lily58.keymap | 11 ++-- app/dts/behaviors.dtsi | 3 +- app/dts/behaviors/ext_power.dtsi | 9 ++++ .../behaviors/zmk,behavior-ext-power.yaml | 10 ++++ app/include/dt-bindings/zmk/ext_power.h | 16 ++++++ app/src/behaviors/behavior_ext_power.c | 54 +++++++++++++++++++ 7 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 app/dts/behaviors/ext_power.dtsi create mode 100644 app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml create mode 100644 app/include/dt-bindings/zmk/ext_power.h create mode 100644 app/src/behaviors/behavior_ext_power.c diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 31d28f57..39509edf 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -46,6 +46,7 @@ if (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) target_sources(app PRIVATE src/behaviors/behavior_transparent.c) target_sources(app PRIVATE src/behaviors/behavior_none.c) target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c) + target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c) target_sources(app PRIVATE src/keymap.c) endif() target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c) diff --git a/app/boards/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap index 997a1248..90dec236 100644 --- a/app/boards/shields/lily58/lily58.keymap +++ b/app/boards/shields/lily58/lily58.keymap @@ -7,6 +7,7 @@ #include #include #include +#include / { keymap { @@ -38,11 +39,11 @@ // | | | | | | | | | | | _ | + | { | } | "|" | // | | | | | | | | | | bindings = < -&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans -&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 -&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD -&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE - &trans &trans &trans &trans &trans &trans &trans &trans +&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans +&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 +&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD +&trans &ext_power EP_ON &ext_power EP_OFF &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE + &trans &trans &trans &trans &trans &trans &trans &trans >; sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD>; diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi index 202202b4..36c918cf 100644 --- a/app/dts/behaviors.dtsi +++ b/app/dts/behaviors.dtsi @@ -8,4 +8,5 @@ #include #include #include -#include \ No newline at end of file +#include +#include diff --git a/app/dts/behaviors/ext_power.dtsi b/app/dts/behaviors/ext_power.dtsi new file mode 100644 index 00000000..c4d8714e --- /dev/null +++ b/app/dts/behaviors/ext_power.dtsi @@ -0,0 +1,9 @@ +/ { + behaviors { + ext_power: behavior_ext_power { + compatible = "zmk,behavior-ext-power"; + label = "EXT_POWER_BEHAVIOR"; + #binding-cells = <2>; + }; + }; +}; diff --git a/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml b/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml new file mode 100644 index 00000000..b9abd92c --- /dev/null +++ b/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml @@ -0,0 +1,10 @@ +# +# Copyright (c) 2020, The ZMK Contributors +# SPDX-License-Identifier: MIT +# + +description: External power control Behavior + +compatible: "zmk,behavior-ext-power" + +include: two_param.yaml diff --git a/app/include/dt-bindings/zmk/ext_power.h b/app/include/dt-bindings/zmk/ext_power.h new file mode 100644 index 00000000..a72b6571 --- /dev/null +++ b/app/include/dt-bindings/zmk/ext_power.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define EXT_POWER_OFF_CMD 0 +#define EXT_POWER_ON_CMD 1 + +/* + * Note: Some future commands might include additional parameters, so we + * defines these aliases up front. + */ + +#define EP_ON EXT_POWER_ON_CMD 0 +#define EP_OFF EXT_POWER_OFF_CMD 0 diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c new file mode 100644 index 00000000..2bd93ee0 --- /dev/null +++ b/app/src/behaviors/behavior_ext_power.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#define DT_DRV_COMPAT zmk_behavior_ext_power + +#include +#include +#include + +#include + +#include +LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); + +#include + +static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t command, u32_t arg) { + const struct device *ext_power = device_get_binding("EXT_POWER"); + if (ext_power == NULL) { + LOG_ERR("Unable to retrieve ext_power device: %d", command); + return -EIO; + } + const struct ext_power_api *ext_power_api = ext_power->driver_api; + + switch (command) { + case EXT_POWER_OFF_CMD: + return ext_power_api->disable(ext_power); + case EXT_POWER_ON_CMD: + return ext_power_api->enable(ext_power); + default: + LOG_ERR("Unknown ext_power command: %d", command); + } + + return -ENOTSUP; +} + +static int behavior_ext_power_init(struct device *dev) { return 0; }; + +static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, + u32_t arg) { + return 0; +} + +static const struct behavior_driver_api behavior_ext_power_driver_api = { + .binding_pressed = on_keymap_binding_pressed, + .binding_released = on_keymap_binding_released, +}; + +DEVICE_AND_API_INIT(behavior_ext_power, DT_INST_LABEL(0), behavior_ext_power_init, NULL, NULL, + APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, + &behavior_ext_power_driver_api); From 5d1c083959967b6f55ce7cff3c83442bc71d23cb Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Mon, 12 Oct 2020 00:30:51 +0800 Subject: [PATCH 207/227] Added toggle and removed a param --- app/include/dt-bindings/zmk/ext_power.h | 11 ++++------- app/src/behaviors/behavior_ext_power.c | 5 +++++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/include/dt-bindings/zmk/ext_power.h b/app/include/dt-bindings/zmk/ext_power.h index a72b6571..2a3e8460 100644 --- a/app/include/dt-bindings/zmk/ext_power.h +++ b/app/include/dt-bindings/zmk/ext_power.h @@ -6,11 +6,8 @@ #define EXT_POWER_OFF_CMD 0 #define EXT_POWER_ON_CMD 1 +#define EXT_POWER_TOGGLE_CMD 2 -/* - * Note: Some future commands might include additional parameters, so we - * defines these aliases up front. - */ - -#define EP_ON EXT_POWER_ON_CMD 0 -#define EP_OFF EXT_POWER_OFF_CMD 0 +#define EP_ON EXT_POWER_ON_CMD +#define EP_OFF EXT_POWER_OFF_CMD +#define EP_TOG EXT_POWER_TOGGLE_CMD diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c index 2bd93ee0..7f06e1dd 100644 --- a/app/src/behaviors/behavior_ext_power.c +++ b/app/src/behaviors/behavior_ext_power.c @@ -30,6 +30,11 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c return ext_power_api->disable(ext_power); case EXT_POWER_ON_CMD: return ext_power_api->enable(ext_power); + case EXT_POWER_TOGGLE_CMD: + if(ext_power_api->get(ext_power) > 0) + return ext_power_api->disable(ext_power); + else + return ext_power_api->enable(ext_power); default: LOG_ERR("Unknown ext_power command: %d", command); } From 4adcb396ff01bf4a8ab98799139ed3f3339d207c Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Mon, 12 Oct 2020 23:50:54 +0800 Subject: [PATCH 208/227] Rebased and fixed nasty code --- app/boards/shields/lily58/lily58.keymap | 2 +- app/src/behaviors/behavior_ext_power.c | 32 +++++++++++-------------- app/src/behaviors/behavior_key_press.c | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/app/boards/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap index 90dec236..d44b3fe8 100644 --- a/app/boards/shields/lily58/lily58.keymap +++ b/app/boards/shields/lily58/lily58.keymap @@ -42,7 +42,7 @@ &bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12 &kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD -&trans &ext_power EP_ON &ext_power EP_OFF &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE +&trans &ext_power EP_ON &ext_power EP_OFF &ext_power EP_TOG &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE &trans &trans &trans &trans &trans &trans &trans &trans >; diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c index 7f06e1dd..e8190c17 100644 --- a/app/src/behaviors/behavior_ext_power.c +++ b/app/src/behaviors/behavior_ext_power.c @@ -9,32 +9,29 @@ #include #include #include - -#include +#include #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); -#include - -static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t command, u32_t arg) { +static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { const struct device *ext_power = device_get_binding("EXT_POWER"); if (ext_power == NULL) { LOG_ERR("Unable to retrieve ext_power device: %d", command); return -EIO; } - const struct ext_power_api *ext_power_api = ext_power->driver_api; - switch (command) { + switch (binding->param1) { case EXT_POWER_OFF_CMD: - return ext_power_api->disable(ext_power); + return ext_power_disable(ext_power); case EXT_POWER_ON_CMD: - return ext_power_api->enable(ext_power); + return ext_power_enable(ext_power); case EXT_POWER_TOGGLE_CMD: - if(ext_power_api->get(ext_power) > 0) - return ext_power_api->disable(ext_power); + if (ext_power_get(ext_power) > 0) + return ext_power_disable(ext_power); else - return ext_power_api->enable(ext_power); + return ext_power_enable(ext_power); default: LOG_ERR("Unknown ext_power command: %d", command); } @@ -42,18 +39,17 @@ static int on_keymap_binding_pressed(struct device *dev, u32_t position, u32_t c return -ENOTSUP; } -static int behavior_ext_power_init(struct device *dev) { return 0; }; - -static int on_keymap_binding_released(struct device *dev, u32_t position, u32_t command, - u32_t arg) { +static int on_keymap_binding_released(struct zmk_behavior_binding *binding, + struct zmk_behavior_binding_event event) { return 0; } +static int behavior_ext_power_init(struct device *dev) { return 0; }; + static const struct behavior_driver_api behavior_ext_power_driver_api = { .binding_pressed = on_keymap_binding_pressed, .binding_released = on_keymap_binding_released, }; DEVICE_AND_API_INIT(behavior_ext_power, DT_INST_LABEL(0), behavior_ext_power_init, NULL, NULL, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, - &behavior_ext_power_driver_api); + APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, &behavior_ext_power_driver_api); diff --git a/app/src/behaviors/behavior_key_press.c b/app/src/behaviors/behavior_key_press.c index d691e9fe..923b0982 100644 --- a/app/src/behaviors/behavior_key_press.c +++ b/app/src/behaviors/behavior_key_press.c @@ -54,4 +54,4 @@ static const struct behavior_driver_api behavior_key_press_driver_api = { &behavior_key_press_data_##n, &behavior_key_press_config_##n, APPLICATION, \ CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_press_driver_api); -DT_INST_FOREACH_STATUS_OKAY(KP_INST) \ No newline at end of file +DT_INST_FOREACH_STATUS_OKAY(KP_INST) From 2e649b7fd4113ff2f0e6ffdfa1ac6ede5feaebf6 Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Tue, 13 Oct 2020 00:09:57 +0800 Subject: [PATCH 209/227] Fix compilation errors and minor tweaks --- app/dts/behaviors/ext_power.dtsi | 2 +- app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml | 2 +- app/src/behaviors/behavior_ext_power.c | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/dts/behaviors/ext_power.dtsi b/app/dts/behaviors/ext_power.dtsi index c4d8714e..92f00352 100644 --- a/app/dts/behaviors/ext_power.dtsi +++ b/app/dts/behaviors/ext_power.dtsi @@ -3,7 +3,7 @@ ext_power: behavior_ext_power { compatible = "zmk,behavior-ext-power"; label = "EXT_POWER_BEHAVIOR"; - #binding-cells = <2>; + #binding-cells = <1>; }; }; }; diff --git a/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml b/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml index b9abd92c..d86c6f9f 100644 --- a/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml +++ b/app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml @@ -7,4 +7,4 @@ description: External power control Behavior compatible: "zmk,behavior-ext-power" -include: two_param.yaml +include: one_param.yaml diff --git a/app/src/behaviors/behavior_ext_power.c b/app/src/behaviors/behavior_ext_power.c index e8190c17..825f9834 100644 --- a/app/src/behaviors/behavior_ext_power.c +++ b/app/src/behaviors/behavior_ext_power.c @@ -11,14 +11,16 @@ #include #include +#include + #include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { - const struct device *ext_power = device_get_binding("EXT_POWER"); + struct device *ext_power = device_get_binding("EXT_POWER"); if (ext_power == NULL) { - LOG_ERR("Unable to retrieve ext_power device: %d", command); + LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1); return -EIO; } @@ -33,7 +35,7 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, else return ext_power_enable(ext_power); default: - LOG_ERR("Unknown ext_power command: %d", command); + LOG_ERR("Unknown ext_power command: %d", binding->param1); } return -ENOTSUP; From 6d9aa4f5ea033d08e6db8c368242e80e205b6f1a Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 12 Oct 2020 13:03:10 -0400 Subject: [PATCH 210/227] fix: Updated copyright headers to single author file. --- app/include/dt-bindings/zmk/bt.h | 2 +- app/include/zmk/ble/profile.h | 2 +- app/include/zmk/events/ble-active-profile-changed.h | 2 +- app/src/behaviors/behavior_bt.c | 2 +- app/src/events/ble_active_profile_changed.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h index a403d35d..8ca10606 100644 --- a/app/include/dt-bindings/zmk/bt.h +++ b/app/include/dt-bindings/zmk/bt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/ble/profile.h b/app/include/zmk/ble/profile.h index 9a79c6d3..1df27436 100644 --- a/app/include/zmk/ble/profile.h +++ b/app/include/zmk/ble/profile.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/include/zmk/events/ble-active-profile-changed.h b/app/include/zmk/events/ble-active-profile-changed.h index 66f40c77..1e3a198b 100644 --- a/app/include/zmk/events/ble-active-profile-changed.h +++ b/app/include/zmk/events/ble-active-profile-changed.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c index 922c1571..066c4371 100644 --- a/app/src/behaviors/behavior_bt.c +++ b/app/src/behaviors/behavior_bt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ diff --git a/app/src/events/ble_active_profile_changed.c b/app/src/events/ble_active_profile_changed.c index a270a144..06988e23 100644 --- a/app/src/events/ble_active_profile_changed.c +++ b/app/src/events/ble_active_profile_changed.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Peter Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ From eee8eb6e776c81192e81f685bd24a3795467ec91 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Mon, 12 Oct 2020 13:04:24 -0400 Subject: [PATCH 211/227] fix: Single author file copyright header fix. --- app/boards/shields/tg4x/tg4x.overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/boards/shields/tg4x/tg4x.overlay b/app/boards/shields/tg4x/tg4x.overlay index acab2e31..10ce524a 100644 --- a/app/boards/shields/tg4x/tg4x.overlay +++ b/app/boards/shields/tg4x/tg4x.overlay @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson, Richard Jones + * Copyright (c) 2020 The ZMK Contrbutors * * SPDX-License-Identifier: MIT */ From 737283bcbcbd771767a82fb8abbdbd087c691808 Mon Sep 17 00:00:00 2001 From: Idan Gazit Date: Mon, 12 Oct 2020 14:23:34 -0700 Subject: [PATCH 212/227] Behave properly in GH Codespaces --- .devcontainer/.bashrc | 4 +++- .devcontainer/devcontainer.json | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc index 855ea755..9fdb8f69 100644 --- a/.devcontainer/.bashrc +++ b/.devcontainer/.bashrc @@ -1,6 +1,8 @@ export LS_OPTIONS='-F --color=auto' -eval "`dircolors`" alias ls='ls $LS_OPTIONS' +if [ "${CODESPACES}" = "true" ]; then + export WORKSPACE_DIR="$HOME/workspace/zmk" +fi if [ -f "$WORKSPACE_DIR/zephyr/zephyr-env.sh" ]; then source "$WORKSPACE_DIR/zephyr/zephyr-env.sh" fi diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 940b78b8..14feeff4 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,6 +3,9 @@ "dockerFile": "Dockerfile", "extensions": ["ms-vscode.cpptools"], "runArgs": ["--security-opt", "label=disable"], - "containerEnv": {"WORKSPACE_DIR": "${containerWorkspaceFolder}"} + "containerEnv": {"WORKSPACE_DIR": "${containerWorkspaceFolder}"}, + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, } From d4b83c3ebf6a51c563a4bdebacae65e9cb17465b Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot Date: Mon, 12 Oct 2020 18:52:29 -0500 Subject: [PATCH 213/227] Increased Comprehension of Oled Footnote --- docs/docs/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index 60fe0d22..fc598987 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -39,7 +39,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | AVR/8 Bit | | | ✅ | | [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | [^2]: Encoders are not currently supported on peripheral side splits. -[^1]: OLEDs are currently proof of concept in ZMK. +[^1]: OLEDs are currently a proof of concept in ZMK. ## Code Of Conduct From e4752606641c8f8393a2ac345511ac17f227fa0e Mon Sep 17 00:00:00 2001 From: Caleb Lightfoot Date: Mon, 12 Oct 2020 19:06:40 -0500 Subject: [PATCH 214/227] Revert "Increased Comprehension of Oled Footnote" This reverts commit d4b83c3ebf6a51c563a4bdebacae65e9cb17465b. --- docs/docs/intro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/intro.md b/docs/docs/intro.md index fc598987..60fe0d22 100644 --- a/docs/docs/intro.md +++ b/docs/docs/intro.md @@ -39,7 +39,7 @@ ZMK is currently missing some features found in other popular firmware. This tab | AVR/8 Bit | | | ✅ | | [Wide Range of ARM Chips Supported](https://docs.zephyrproject.org/latest/boards/index.html) | ✅ | | | [^2]: Encoders are not currently supported on peripheral side splits. -[^1]: OLEDs are currently a proof of concept in ZMK. +[^1]: OLEDs are currently proof of concept in ZMK. ## Code Of Conduct From 59e8c58051298175bc1c77593f1b24d9394aa848 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 13 Oct 2020 00:11:08 -0400 Subject: [PATCH 215/227] fix: Copyright header for cradio.dtsi --- app/boards/shields/cradio/cradio.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi index 1f2603c2..43f90493 100644 --- a/app/boards/shields/cradio/cradio.dtsi +++ b/app/boards/shields/cradio/cradio.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020 Pete Johanson + * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ @@ -48,4 +48,3 @@ }; }; }; - From 94bc2c31b14d5ace4c51f409f934ef077323eb32 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 13 Oct 2020 00:23:25 -0400 Subject: [PATCH 216/227] feat: Add a couple missing shields to user setup. --- docs/static/setup.ps1 | 6 +++--- docs/static/setup.sh | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index 63bd5c0e..1686be25 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -91,9 +91,9 @@ Write-Host "Keyboard Shield Selection:" $prompt = "Pick a keyboard" # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. -$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac", "makerdiary M60", "Microdox" -$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac", "m60", "microdox" -$splits = "y", "y", "y", "y", "y", "y", "n", "n", "y" +$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac", "RoMac+", "makerdiary M60", "Microdox", "TG4X" +$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac", "romac_plus", "m60", "microdox", "tg4x" +$splits = "y", "y", "y", "y", "y", "y", "n", "n", "n", "y", "n" $choice = Get-Choice-From-Options -Options $options -Prompt $prompt $shield_title = $($options[$choice]) diff --git a/docs/static/setup.sh b/docs/static/setup.sh index 96e87688..d7e2b8cd 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -58,7 +58,7 @@ echo "" echo "Keyboard Shield Selection:" prompt="Pick an keyboard:" -options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac" "makerdiary M60" "Microdox") +options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac" "RoMac+" "makerdiary M60" "Microdox" "TG4X") PS3="$prompt " # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. @@ -74,8 +74,10 @@ select opt in "${options[@]}" "Quit"; do 5 ) shield_title="Sofle" shield="sofle"; split="y"; break;; 6 ) shield_title="Iris" shield="iris"; split="y"; break;; 7 ) shield_title="RoMac" shield="romac"; split="n"; break;; - 8 ) shield_title="M60" shield="m60"; split="n"; break;; - 9 ) shield_title="Microdox" shield="microdox"; split="y"; break;; + 8 ) shield_title="RoMac+" shield="romac_plus"; split="n"; break;; + 9 ) shield_title="M60" shield="m60"; split="n"; break;; + 10 ) shield_title="Microdox" shield="microdox"; split="y"; break;; + 11 ) shield_title="TG4X" shield="tg4x"; split="n"; break;; # Add link to docs on adding your own custom shield in your ZMK config! # $(( ${#options[@]}+1 )) ) echo "Other!"; break;; From cc21167d57665a9bf0b413a4a85984f771d7812f Mon Sep 17 00:00:00 2001 From: Mega Mind <68985133+megamind4089@users.noreply.github.com> Date: Wed, 14 Oct 2020 00:27:32 +0800 Subject: [PATCH 217/227] Added docs for external power output --- docs/docs/behavior/power.md | 64 +++++++++++++++++++++++++++++++++++++ docs/sidebars.js | 1 + 2 files changed, 65 insertions(+) create mode 100644 docs/docs/behavior/power.md diff --git a/docs/docs/behavior/power.md b/docs/docs/behavior/power.md new file mode 100644 index 00000000..6b8237be --- /dev/null +++ b/docs/docs/behavior/power.md @@ -0,0 +1,64 @@ +--- +title: Power Management Behaviors +sidebar_label: Power Management +--- + +## Summary + +These page contains some of the power management behaviors currently supported by ZMK. + +## External Power Control + +The External power control behavior allows enabling or disabling the VCC power output +to save power. Some of the LEDs will consume power even in OFF state. To preserve +battery life in this scenario, some controller boards have support to disable the +external power completely. + +The following boards currently support this feature: +- nRFMicro +- nice!nano + +## External Power Control Command Defines + +External power control command defines are provided through the [`dt-bindings/zmk/ext_power.h`](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/ext_power.h) header, +which is added at the top of the keymap file: + +``` +#include +``` + +This will allow you to reference the actions defined in this header such as `EXT_POWER_OFF_CMD`. + +Here is a table describing the command for each define: + +| Define | Action | Alias | +| ------------ | -------------------------------------- | -------- | +| `EXT_POWER_OFF_CMD` | Disable the external power. | `EP_OFF` | +| `EXT_POWER_ON_CMD` | Enable the external power. | `EP_ON` | +| `EXT_POWER_TOGGLE_CMD` | Toggle the external power. | `EP_TOG` | + +### Behavior Binding + +- Reference: `&ext_power` +- Parameter#1: Command, e.g `EP_ON` + +### Example: + +1. Behavior binding to enable the external power + + ``` + &ext_power EP_ON + ``` + +1. Behavior binding to disable the external power + + ``` + &ext_power EP_OFF + ``` + +1. Behavior binding to toggle the external power + + ``` + &ext_power EP_TOG + ``` + diff --git a/docs/sidebars.js b/docs/sidebars.js index 93ce2264..12b4a6e3 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -23,6 +23,7 @@ module.exports = { "behavior/reset", "behavior/bluetooth", "behavior/lighting", + "behavior/power", ], Development: [ "dev-clean-room", From 43c900f94a9394bc09bdfc646bfd3f42f947d927 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 13 Oct 2020 19:46:02 -0400 Subject: [PATCH 218/227] feat: Add qaz to setup scripts. --- docs/static/setup.ps1 | 6 +++--- docs/static/setup.sh | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1 index 1686be25..5ebd3768 100644 --- a/docs/static/setup.ps1 +++ b/docs/static/setup.ps1 @@ -91,9 +91,9 @@ Write-Host "Keyboard Shield Selection:" $prompt = "Pick a keyboard" # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. -$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac", "RoMac+", "makerdiary M60", "Microdox", "TG4X" -$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac", "romac_plus", "m60", "microdox", "tg4x" -$splits = "y", "y", "y", "y", "y", "y", "n", "n", "n", "y", "n" +$options = "Kyria", "Lily58", "Corne", "Splitreus62", "Sofle", "Iris", "RoMac", "RoMac+", "makerdiary M60", "Microdox", "TG4X", "QAZ" +$names = "kyria", "lily58", "corne", "splitreus62", "sofle", "iris", "romac", "romac_plus", "m60", "microdox", "tg4x", "qaz" +$splits = "y", "y", "y", "y", "y", "y", "n", "n", "n", "y", "n", "n" $choice = Get-Choice-From-Options -Options $options -Prompt $prompt $shield_title = $($options[$choice]) diff --git a/docs/static/setup.sh b/docs/static/setup.sh index d7e2b8cd..e45a7ed7 100644 --- a/docs/static/setup.sh +++ b/docs/static/setup.sh @@ -58,7 +58,7 @@ echo "" echo "Keyboard Shield Selection:" prompt="Pick an keyboard:" -options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac" "RoMac+" "makerdiary M60" "Microdox" "TG4X") +options=("Kyria" "Lily58" "Corne" "Splitreus62" "Sofle" "Iris" "RoMac" "RoMac+" "makerdiary M60" "Microdox" "TG4X" "QAZ") PS3="$prompt " # TODO: Add support for "Other" and linking to docs on adding custom shields in user config repos. @@ -78,6 +78,7 @@ select opt in "${options[@]}" "Quit"; do 9 ) shield_title="M60" shield="m60"; split="n"; break;; 10 ) shield_title="Microdox" shield="microdox"; split="y"; break;; 11 ) shield_title="TG4X" shield="tg4x"; split="n"; break;; + 12 ) shield_title="QAZ" shield="qaz"; split="n"; break;; # Add link to docs on adding your own custom shield in your ZMK config! # $(( ${#options[@]}+1 )) ) echo "Other!"; break;; From b2cad7e597a2cbadf78b2544734b9a6dd50c45a2 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 13 Oct 2020 19:50:24 -0400 Subject: [PATCH 219/227] fix(docs): Proper block for romac shield. --- docs/docs/hardware.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/hardware.md b/docs/docs/hardware.md index faac57c6..fe229dfe 100644 --- a/docs/docs/hardware.md +++ b/docs/docs/hardware.md @@ -29,7 +29,7 @@ That being said, there are currently only a few specific [boards](/docs/faq#what - [Sofle](https://github.com/josefadamcik/SofleKeyboard) (`sofle_left` and `sofle_right`) - [Splitreus62](https://github.com/Na-Cly/splitreus62) (`splitreus62_left` and `splitreus62_right`) - [RoMac+ v4](https://www.littlekeyboards.com/products/romac) (`romac_plus`) -- [RoMac v2](https://mechboards.co.uk/shop/kits/romac-macro-pad/) (`romac') +- [RoMac v2](https://mechboards.co.uk/shop/kits/romac-macro-pad/) (`romac`) - [QAZ](https://www.cbkbd.com/product/qaz-keyboard-kit) (`qaz`) ## Other Hardware From 3186a553a5d18f24fc6fbac2987cf8054afadcbb Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Tue, 13 Oct 2020 21:00:54 -0400 Subject: [PATCH 220/227] fix(shields): Add default qaz.conf file. --- app/boards/shields/qaz/qaz.conf | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/boards/shields/qaz/qaz.conf diff --git a/app/boards/shields/qaz/qaz.conf b/app/boards/shields/qaz/qaz.conf new file mode 100644 index 00000000..e69de29b From 204d1300ba6b13041e9a69cc297c06ac189f1f0d Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 15 Oct 2020 00:00:37 -0400 Subject: [PATCH 221/227] fix(ble): Only advertise when needed.* Once we have a peer connected to for the active profile, don't continue advertising. --- app/src/ble.c | 139 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 113 insertions(+), 26 deletions(-) diff --git a/app/src/ble.c b/app/src/ble.c index 49e2b3b0..8cc42bcd 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -45,6 +45,18 @@ static u8_t passkey_digit = 0; #define PROFILE_COUNT CONFIG_BT_MAX_PAIRED #endif +enum advertising_type { + ZMK_ADV_NONE, + ZMK_ADV_DIR, + ZMK_ADV_CONN, +} advertising_status; + +#define CURR_ADV(adv) (adv << 4) + +#define ZMK_ADV_CONN_NAME \ + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_USE_NAME, \ + BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL) + static struct zmk_ble_profile profiles[PROFILE_COUNT]; static u8_t active_profile; @@ -92,28 +104,96 @@ void set_profile_address(u8_t index, const bt_addr_le_t *addr) { raise_profile_changed_event(); } -int zmk_ble_adv_pause() { - int err = bt_le_adv_stop(); - if (err) { - LOG_ERR("Failed to stop advertising (err %d)", err); - return err; +bool active_profile_is_connected() { + struct bt_conn *conn; + bt_addr_le_t *addr = zmk_ble_active_profile_addr(); + if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) { + return false; + } else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) { + return false; + } + + bt_conn_unref(conn); + + return true; +} + +#define CHECKED_ADV_STOP() \ + err = bt_le_adv_stop(); \ + advertising_status = ZMK_ADV_NONE; \ + if (err) { \ + LOG_ERR("Failed to stop advertising (err %d)", err); \ + return err; \ + } + +#define CHECKED_DIR_ADV() \ + addr = zmk_ble_active_profile_addr(); \ + conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr); \ + if (conn != NULL) { /* TODO: Check status of connection */ \ + LOG_DBG("Skipping advertising, profile host is already connected"); \ + bt_conn_unref(conn); \ + return 0; \ + } \ + err = bt_le_adv_start(BT_LE_ADV_CONN_DIR_LOW_DUTY(addr), zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), \ + NULL, 0); \ + if (err) { \ + LOG_ERR("Advertising failed to start (err %d)", err); \ + return err; \ + } \ + advertising_status = ZMK_ADV_DIR; + +#define CHECKED_OPEN_ADV() \ + err = bt_le_adv_start(ZMK_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); \ + if (err) { \ + LOG_ERR("Advertising failed to start (err %d)", err); \ + return err; \ + } \ + advertising_status = ZMK_ADV_CONN; + +int update_advertising() { + int err = 0; + bt_addr_le_t *addr; + struct bt_conn *conn; + enum advertising_type desired_adv = ZMK_ADV_NONE; + + if (active_profile_is_open() || !active_profile_is_connected()) { + desired_adv = ZMK_ADV_CONN; + } else if (!active_profile_is_connected()) { + desired_adv = ZMK_ADV_CONN; + // Need to fix directed advertising for privacy centrals. See + // https://github.com/zephyrproject-rtos/zephyr/pull/14984 char + // addr_str[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(zmk_ble_active_profile_addr(), addr_str, + // sizeof(addr_str)); + + // LOG_DBG("Directed advertising to %s", log_strdup(addr_str)); + // desired_adv = ZMK_ADV_DIR; + } + LOG_DBG("advertising from %d to %d", advertising_status, desired_adv); + + switch (desired_adv + CURR_ADV(advertising_status)) { + case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR): + case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN): + CHECKED_ADV_STOP(); + CHECKED_DIR_ADV(); + break; + case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_NONE): + CHECKED_DIR_ADV(); + break; + case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_DIR): + CHECKED_ADV_STOP(); + CHECKED_OPEN_ADV(); + break; + case ZMK_ADV_CONN + CURR_ADV(ZMK_ADV_NONE): + CHECKED_OPEN_ADV(); + break; } return 0; }; -int zmk_ble_adv_resume() { - LOG_DBG("active_profile %d, directed? %s", active_profile, - active_profile_is_open() ? "no" : "yes"); +static void update_advertising_callback(struct k_work *work) { update_advertising(); } - int err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0); - if (err) { - LOG_ERR("Advertising failed to start (err %d)", err); - return err; - } - - return 0; -}; +K_WORK_DEFINE(update_advertising_work, update_advertising_callback); int zmk_ble_clear_bonds() { LOG_DBG(""); @@ -124,6 +204,8 @@ int zmk_ble_clear_bonds() { set_profile_address(active_profile, BT_ADDR_LE_ANY); } + update_advertising(); + return 0; }; @@ -134,9 +216,13 @@ int zmk_ble_prof_select(u8_t index) { } active_profile = index; - return settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); + settings_save_one("ble/active_profile", &active_profile, sizeof(active_profile)); + + update_advertising(); raise_profile_changed_event(); + + return 0; }; int zmk_ble_prof_next() { @@ -234,8 +320,11 @@ static void connected(struct bt_conn *conn, u8_t err) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + advertising_status = ZMK_ADV_NONE; + if (err) { LOG_WRN("Failed to connect to %s (%u)", log_strdup(addr), err); + update_advertising(); return; } @@ -250,6 +339,8 @@ static void connected(struct bt_conn *conn, u8_t err) { if (bt_conn_set_security(conn, BT_SECURITY_L2)) { LOG_ERR("Failed to set security"); } + + update_advertising(); } static void disconnected(struct bt_conn *conn, u8_t reason) { @@ -259,14 +350,9 @@ static void disconnected(struct bt_conn *conn, u8_t reason) { LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason); -#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) - // if (bt_addr_le_cmp(&peripheral_addr, BT_ADDR_LE_ANY) && bt_addr_le_cmp(&peripheral_addr, - // bt_conn_get_dst(conn))) { - // zmk_ble_adv_resume(); - // } -#else - // zmk_ble_adv_resume(); -#endif + // We need to do this in a work callback, otherwise the advertising update will still see the + // connection for a profile as active, and not start advertising yet. + k_work_submit(&update_advertising_work); } static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) { @@ -361,6 +447,7 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) { #endif /* !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) */ set_profile_address(active_profile, dst); + update_advertising(); }; static struct bt_conn_auth_cb zmk_ble_auth_cb_display = { @@ -383,7 +470,7 @@ static void zmk_ble_ready(int err) { return; } - zmk_ble_adv_resume(); + update_advertising(); } static int zmk_ble_init(struct device *_arg) { From f7912eb9decc2048c204818defc717a71135edc6 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 15 Oct 2020 17:08:25 -0400 Subject: [PATCH 222/227] fix: Remove conflicting gitignore entry. --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index eb4312fd..e02cca0e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ /tools /zephyr /build -**/.DS_Store From e468677c4ea5f382a8e48793eda87ecd3d07a4dd Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Thu, 15 Oct 2020 20:29:00 -0400 Subject: [PATCH 223/227] fix(shields): Proper cradio Kconfig setup. --- app/boards/shields/cradio/Kconfig.defconfig | 17 +++++++++++++++-- app/boards/shields/cradio/Kconfig.shield | 7 +++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig index 43509a47..4d200c95 100644 --- a/app/boards/shields/cradio/Kconfig.defconfig +++ b/app/boards/shields/cradio/Kconfig.defconfig @@ -1,10 +1,23 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT +if SHIELD_CRADIO_LEFT + config ZMK_KEYBOARD_NAME - default "cradio" + default "cradio left" + +endif + +if SHIELD_CRADIO_RIGHT + +config ZMK_KEYBOARD_NAME + default "cradio right" + +endif + +if SHIELD_CRADIO_RIGHT || SHIELD_CRADIO_LEFT config ZMK_KSCAN_DIRECT_POLLING default y - +endif diff --git a/app/boards/shields/cradio/Kconfig.shield b/app/boards/shields/cradio/Kconfig.shield index 71a439e0..bb5f0735 100644 --- a/app/boards/shields/cradio/Kconfig.shield +++ b/app/boards/shields/cradio/Kconfig.shield @@ -1,5 +1,8 @@ # Copyright (c) 2020 The ZMK Contributors # SPDX-License-Identifier: MIT -config SHIELD_CRADIO - def_bool $(shields_list_contains,cradio) +config SHIELD_CRADIO_LEFT + def_bool $(shields_list_contains,cradio_left) + +config SHIELD_CRADIO_RIGHT + def_bool $(shields_list_contains,cradio_right) From 818f0a1f91020f3315ae09f70ddda6f8362fab98 Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 16 Oct 2020 00:48:53 -0400 Subject: [PATCH 224/227] fix(bluetooth): Advertise name + appearance. * Properly put device name and GAP appearance in advertising packets, for proper display in macOS, Android, etc. * Closes #124 --- app/src/ble.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/ble.c b/app/src/ble.c index 8cc42bcd..ddc92e99 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -54,13 +54,18 @@ enum advertising_type { #define CURR_ADV(adv) (adv << 4) #define ZMK_ADV_CONN_NAME \ - BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME | BT_LE_ADV_OPT_USE_NAME, \ - BT_GAP_ADV_FAST_INT_MIN_2, BT_GAP_ADV_FAST_INT_MAX_2, NULL) + BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, BT_GAP_ADV_FAST_INT_MIN_2, \ + BT_GAP_ADV_FAST_INT_MAX_2, NULL) static struct zmk_ble_profile profiles[PROFILE_COUNT]; static u8_t active_profile; +#define DEVICE_NAME CONFIG_BT_DEVICE_NAME +#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) + static const struct bt_data zmk_ble_ad[] = { + BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), + BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, 0xC1, 0x03), BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID16_SOME, #if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) From b07475b7d475a592ad974bb36a5580b1c863344f Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 16 Oct 2020 00:56:05 -0400 Subject: [PATCH 225/227] fix(bluetooth): Stop adv on connected profile. --- app/src/ble.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/ble.c b/app/src/ble.c index ddc92e99..1b25ca2a 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -176,6 +176,10 @@ int update_advertising() { LOG_DBG("advertising from %d to %d", advertising_status, desired_adv); switch (desired_adv + CURR_ADV(advertising_status)) { + case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_DIR): + case ZMK_ADV_NONE + CURR_ADV(ZMK_ADV_CONN): + CHECKED_ADV_STOP(); + break; case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_DIR): case ZMK_ADV_DIR + CURR_ADV(ZMK_ADV_CONN): CHECKED_ADV_STOP(); From 9d512eaef01d92b930054d6528279944afe221ce Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Fri, 16 Oct 2020 09:49:28 -0400 Subject: [PATCH 226/227] fix(bluetooth): Add adv data in non-peripherals. --- app/src/ble.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/ble.c b/app/src/ble.c index 1b25ca2a..9090582c 100644 --- a/app/src/ble.c +++ b/app/src/ble.c @@ -64,8 +64,10 @@ static u8_t active_profile; #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) static const struct bt_data zmk_ble_ad[] = { +#if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), BT_DATA_BYTES(BT_DATA_GAP_APPEARANCE, 0xC1, 0x03), +#endif BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID16_SOME, #if !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL) From 36d3d01a22a46cdc4f1ebcabe27666dec4afface Mon Sep 17 00:00:00 2001 From: Pete Johanson Date: Sun, 18 Oct 2020 13:24:37 -0400 Subject: [PATCH 227/227] feat(usb): Add proper USB product ID. * Use openmoko product ID from: https://github.com/openmoko/openmoko-usb-oui/pull/15 --- app/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/Kconfig b/app/Kconfig index fca49124..4cd01eba 100644 --- a/app/Kconfig +++ b/app/Kconfig @@ -9,6 +9,15 @@ config USB_DEVICE_PRODUCT config BT_DEVICE_NAME default ZMK_KEYBOARD_NAME +config USB_DEVICE_VID + default 0x1D50 + +config USB_DEVICE_PID + default 0x615E + +config USB_DEVICE_MANUFACTURER + default "ZMK Project" + config ZMK_KSCAN_EVENT_QUEUE_SIZE int "Size of the event queue for KSCAN events to buffer events" default 4