summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.devcontainer/.bashrc8
-rw-r--r--.devcontainer/Dockerfile11
-rw-r--r--.devcontainer/devcontainer.json11
-rw-r--r--.gitattributes6
-rw-r--r--.github/workflows/build.yml7
-rw-r--r--.github/workflows/clang-format-lint.yml4
-rw-r--r--CONTRIBUTING.md120
-rw-r--r--app/CMakeLists.txt5
-rw-r--r--app/Kconfig55
-rw-r--r--app/boards/arm/nice_nano/nice_nano.dts9
-rw-r--r--app/boards/arm/nrf52840_m2/CMakeLists.txt13
-rw-r--r--app/boards/arm/nrf52840_m2/Kconfig10
-rw-r--r--app/boards/arm/nrf52840_m2/Kconfig.board10
-rw-r--r--app/boards/arm/nrf52840_m2/Kconfig.defconfig30
-rw-r--r--app/boards/arm/nrf52840_m2/board.cmake9
-rw-r--r--app/boards/arm/nrf52840_m2/nrf52840_m2.dts97
-rw-r--r--app/boards/arm/nrf52840_m2/nrf52840_m2.yaml15
-rw-r--r--app/boards/arm/nrf52840_m2/nrf52840_m2_defconfig23
-rw-r--r--app/boards/arm/nrfmicro/nrfmicro_11.dts5
-rw-r--r--app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts5
-rw-r--r--app/boards/arm/nrfmicro/nrfmicro_13.dts5
-rw-r--r--app/boards/arm/nrfmicro/pinmux.c11
-rw-r--r--app/boards/arm/planck/Kconfig.defconfig3
-rw-r--r--app/boards/arm/planck/board.cmake3
-rw-r--r--app/boards/shields/Kconfig.defconfig14
-rw-r--r--app/boards/shields/Kconfig.shield5
-rw-r--r--app/boards/shields/clueboard_california/Kconfig.defconfig2
-rw-r--r--app/boards/shields/clueboard_california/clueboard_california.keymap6
-rw-r--r--app/boards/shields/corne/corne.keymap6
-rw-r--r--app/boards/shields/cradio/Kconfig.defconfig23
-rw-r--r--app/boards/shields/cradio/Kconfig.shield8
-rw-r--r--app/boards/shields/cradio/cradio.dtsi50
-rw-r--r--app/boards/shields/cradio/cradio.keymap43
-rw-r--r--app/boards/shields/cradio/cradio_left.conf5
-rw-r--r--app/boards/shields/cradio/cradio_left.overlay7
-rw-r--r--app/boards/shields/cradio/cradio_right.conf5
-rw-r--r--app/boards/shields/cradio/cradio_right.overlay11
-rw-r--r--app/boards/shields/iris/iris.keymap7
-rw-r--r--app/boards/shields/kyria/kyria.keymap6
-rw-r--r--app/boards/shields/lily58/lily58.keymap17
-rw-r--r--app/boards/shields/m60/Kconfig.defconfig11
-rw-r--r--app/boards/shields/m60/Kconfig.shield7
-rw-r--r--app/boards/shields/m60/m60.conf0
-rw-r--r--app/boards/shields/m60/m60.keymap42
-rw-r--r--app/boards/shields/m60/m60.overlay66
-rw-r--r--app/boards/shields/m60/readme.md14
-rw-r--r--app/boards/shields/microdox/Kconfig.defconfig60
-rw-r--r--app/boards/shields/microdox/Kconfig.shield8
-rw-r--r--app/boards/shields/microdox/boards/nice_nano.overlay34
-rw-r--r--app/boards/shields/microdox/microdox.conf6
-rw-r--r--app/boards/shields/microdox/microdox.dtsi66
-rw-r--r--app/boards/shields/microdox/microdox.keymap73
-rw-r--r--app/boards/shields/microdox/microdox_left.conf2
-rw-r--r--app/boards/shields/microdox/microdox_left.overlay17
-rw-r--r--app/boards/shields/microdox/microdox_right.conf2
-rw-r--r--app/boards/shields/microdox/microdox_right.overlay21
-rw-r--r--app/boards/shields/qaz/qaz.conf0
-rw-r--r--app/boards/shields/quefrency/Kconfig.defconfig17
-rw-r--r--app/boards/shields/quefrency/Kconfig.shield8
-rw-r--r--app/boards/shields/quefrency/quefrency.conf0
-rw-r--r--app/boards/shields/quefrency/quefrency.dtsi32
-rw-r--r--app/boards/shields/quefrency/quefrency.keymap51
-rw-r--r--app/boards/shields/quefrency/quefrency_left.conf2
-rw-r--r--app/boards/shields/quefrency/quefrency_left.overlay37
-rw-r--r--app/boards/shields/quefrency/quefrency_right.conf2
-rw-r--r--app/boards/shields/quefrency/quefrency_right.overlay45
-rw-r--r--app/boards/shields/romac/romac.keymap2
-rw-r--r--app/boards/shields/romac_plus/Kconfig.defconfig9
-rw-r--r--app/boards/shields/romac_plus/Kconfig.shield5
-rw-r--r--app/boards/shields/romac_plus/boards/nice_nano.overlay28
-rw-r--r--app/boards/shields/romac_plus/romac_plus.conf6
-rw-r--r--app/boards/shields/romac_plus/romac_plus.dtsi56
-rw-r--r--app/boards/shields/romac_plus/romac_plus.keymap49
-rw-r--r--app/boards/shields/romac_plus/romac_plus.overlay31
-rw-r--r--app/boards/shields/sofle/sofle.keymap6
-rw-r--r--app/boards/shields/splitreus62/splitreus62.keymap3
-rw-r--r--app/boards/shields/tg4x/Kconfig.defconfig9
-rw-r--r--app/boards/shields/tg4x/Kconfig.shield5
-rw-r--r--app/boards/shields/tg4x/tg4x.keymap58
-rw-r--r--app/boards/shields/tg4x/tg4x.overlay56
-rw-r--r--app/drivers/zephyr/Kconfig8
-rw-r--r--app/drivers/zephyr/ec11.c2
-rw-r--r--app/drivers/zephyr/kscan_gpio_direct.c18
-rw-r--r--app/drivers/zephyr/kscan_gpio_matrix.c73
-rw-r--r--app/dts/behaviors.dtsi3
-rw-r--r--app/dts/behaviors/ext_power.dtsi9
-rw-r--r--app/dts/bindings/behaviors/zmk,behavior-ext-power.yaml10
-rw-r--r--app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml2
-rw-r--r--app/dts/bindings/zmk,ext-power-generic.yaml20
-rw-r--r--app/dts/bindings/zmk,keymap-sensors.yaml5
-rw-r--r--app/include/drivers/behavior.h44
-rw-r--r--app/include/drivers/ext_power.h104
-rw-r--r--app/include/dt-bindings/zmk/bt.h4
-rw-r--r--app/include/dt-bindings/zmk/ext_power.h13
-rw-r--r--app/include/dt-bindings/zmk/keys.h5
-rw-r--r--app/include/dt-bindings/zmk/kscan-mock.h6
-rw-r--r--app/include/dt-bindings/zmk/matrix-transform.h5
-rw-r--r--app/include/dt-bindings/zmk/rgb.h5
-rw-r--r--app/include/zmk/behavior.h6
-rw-r--r--app/include/zmk/ble/profile.h2
-rw-r--r--app/include/zmk/events/ble-active-profile-changed.h2
-rw-r--r--app/include/zmk/events/keycode-state-changed.h1
-rw-r--r--app/include/zmk/events/position-state-changed.h1
-rw-r--r--app/include/zmk/keymap.h2
-rw-r--r--app/include/zmk/split/bluetooth/service.h6
-rw-r--r--app/include/zmk/split/bluetooth/uuid.h6
-rw-r--r--app/include/zmk/usb.h (renamed from app/include/zmk/usb_hid.h)4
-rw-r--r--app/src/behaviors/behavior_bt.c20
-rw-r--r--app/src/behaviors/behavior_ext_power.c57
-rw-r--r--app/src/behaviors/behavior_hold_tap.c114
-rw-r--r--app/src/behaviors/behavior_key_press.c21
-rw-r--r--app/src/behaviors/behavior_momentary_layer.c17
-rw-r--r--app/src/behaviors/behavior_none.c10
-rw-r--r--app/src/behaviors/behavior_reset.c7
-rw-r--r--app/src/behaviors/behavior_rgb_underglow.c6
-rw-r--r--app/src/behaviors/behavior_sensor_rotate_key_press.c11
-rw-r--r--app/src/behaviors/behavior_toggle_layer.c15
-rw-r--r--app/src/behaviors/behavior_transparent.c10
-rw-r--r--app/src/ble.c146
-rw-r--r--app/src/endpoints.c2
-rw-r--r--app/src/events/ble_active_profile_changed.c2
-rw-r--r--app/src/ext_power_generic.c91
-rw-r--r--app/src/hog.c12
-rw-r--r--app/src/keymap.c22
-rw-r--r--app/src/kscan.c1
-rw-r--r--app/src/kscan_composite.c12
-rw-r--r--app/src/main.c9
-rw-r--r--app/src/power.c69
-rw-r--r--app/src/split/bluetooth/central.c1
-rw-r--r--app/src/usb.c (renamed from app/src/usb_hid.c)17
-rw-r--r--app/tests/hold-tap/balanced/many-nested/events.patterns4
-rw-r--r--app/tests/hold-tap/balanced/many-nested/keycode_events.snapshot20
-rw-r--r--app/tests/hold-tap/balanced/many-nested/native_posix.keymap41
-rw-r--r--docs/blog/2020-09-21-zmk-sotf-2.md106
-rw-r--r--docs/docs/assets/dev-setup/vscode_devcontainer.pngbin0 -> 20773 bytes
-rw-r--r--docs/docs/assets/troubleshooting/filetransfer/mac.pngbin0 -> 26499 bytes
-rw-r--r--docs/docs/behavior/bluetooth.md4
-rw-r--r--docs/docs/behavior/power.md64
-rw-r--r--docs/docs/bond-reset.md4
-rw-r--r--docs/docs/customization.md28
-rw-r--r--docs/docs/dev-build.md13
-rw-r--r--docs/docs/dev-clean-room.md6
-rw-r--r--docs/docs/dev-guide-new-shield.md224
-rw-r--r--docs/docs/dev-setup.md195
-rw-r--r--docs/docs/feature/encoders.md2
-rw-r--r--docs/docs/hardware.md7
-rw-r--r--docs/docs/intro.md62
-rw-r--r--docs/docs/troubleshooting.md21
-rw-r--r--docs/docs/user-setup.md7
-rw-r--r--docs/sidebars.js2
-rw-r--r--docs/static/setup.ps1206
-rw-r--r--docs/static/setup.sh112
152 files changed, 3436 insertions, 366 deletions
diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc
new file mode 100644
index 0000000..9fdb8f6
--- /dev/null
+++ b/.devcontainer/.bashrc
@@ -0,0 +1,8 @@
+export LS_OPTIONS='-F --color=auto'
+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/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 0000000..184aae9
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,11 @@
+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/*
+
+COPY .bashrc tmp
+RUN mv /tmp/.bashrc ~/.bashrc
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 0000000..14feeff
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,11 @@
+{
+ "name": "ZMK Development",
+ "dockerFile": "Dockerfile",
+ "extensions": ["ms-vscode.cpptools"],
+ "runArgs": ["--security-opt", "label=disable"],
+ "containerEnv": {"WORKSPACE_DIR": "${containerWorkspaceFolder}"},
+ "settings": {
+ "terminal.integrated.shell.linux": "/bin/bash"
+ },
+}
+
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..3d05d86
--- /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
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 02657c0..60c337d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -16,8 +16,13 @@ jobs:
- kyria_right
- lily58_left
- lily58_right
+ - iris_left
+ - iris_right
- romac
+ - romac_plus
- settings_reset
+ - quefrency_left
+ - quefrency_right
include:
- board: proton_c
shield: clueboard_california
@@ -70,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
diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml
index 061bc3d..70ae986 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:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..3ea8c78
--- /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
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 8c21687..8a3971e 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)
@@ -30,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)
@@ -44,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)
@@ -54,7 +57,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 a9d4f34..285ed91 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
@@ -21,12 +30,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
@@ -72,6 +85,29 @@ 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_EXT_POWER
+ bool "Enable support to control external power output"
+ default y
+
config ZMK_DISPLAY
bool "ZMK display support"
default n
@@ -108,7 +144,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
@@ -132,16 +167,30 @@ 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
config ZMK_KSCAN_MOCK_DRIVER
diff --git a/app/boards/arm/nice_nano/nice_nano.dts b/app/boards/arm/nice_nano/nice_nano.dts
index 2e9556b..0538b1d 100644
--- a/app/boards/arm/nice_nano/nice_nano.dts
+++ b/app/boards/arm/nice_nano/nice_nano.dts
@@ -29,6 +29,15 @@
};
};
+ ext-power {
+ compatible = "zmk,ext-power-generic";
+ label = "EXT_POWER";
+ control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+ };
+};
+
+&gpiote {
+ status = "okay";
};
&gpio0 {
diff --git a/app/boards/arm/nrf52840_m2/CMakeLists.txt b/app/boards/arm/nrf52840_m2/CMakeLists.txt
new file mode 100644
index 0000000..84b2ab9
--- /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 0000000..faff492
--- /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 0000000..6ade68c
--- /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 0000000..98fcd08
--- /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 0000000..55b44e2
--- /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/nrfjprog.board.cmake)
+include(${ZEPHYR_BASE}/boards/common/blackmagicprobe.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 0000000..fb5b0ff
--- /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 <nordic/nrf52840_qiaa.dtsi>
+
+/ {
+ 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 0000000..0a999bb
--- /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 0000000..e74438b
--- /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
diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.dts b/app/boards/arm/nrfmicro/nrfmicro_11.dts
index 95bd8ad..87c650e 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 85693a8..ea15b81 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 95bd8ad..ef43946 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 4e330b6..30117d0 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/boards/arm/planck/Kconfig.defconfig b/app/boards/arm/planck/Kconfig.defconfig
index 6f5bf52..913c1c1 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/arm/planck/board.cmake b/app/boards/arm/planck/board.cmake
index 4843c41..772796d 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)
diff --git a/app/boards/shields/Kconfig.defconfig b/app/boards/shields/Kconfig.defconfig
new file mode 100644
index 0000000..5b9ca9a
--- /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 0000000..844d433
--- /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/clueboard_california/Kconfig.defconfig b/app/boards/shields/clueboard_california/Kconfig.defconfig
index 2408f9f..e101ea7 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/boards/shields/clueboard_california/clueboard_california.keymap b/app/boards/shields/clueboard_california/clueboard_california.keymap
index 7a84b11..44a0b07 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 <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
diff --git a/app/boards/shields/corne/corne.keymap b/app/boards/shields/corne/corne.keymap
index 5f0f15f..64d4a00 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 <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
diff --git a/app/boards/shields/cradio/Kconfig.defconfig b/app/boards/shields/cradio/Kconfig.defconfig
new file mode 100644
index 0000000..4d200c9
--- /dev/null
+++ b/app/boards/shields/cradio/Kconfig.defconfig
@@ -0,0 +1,23 @@
+# 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
+
+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
new file mode 100644
index 0000000..bb5f073
--- /dev/null
+++ b/app/boards/shields/cradio/Kconfig.shield
@@ -0,0 +1,8 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+config SHIELD_CRADIO_LEFT
+ def_bool $(shields_list_contains,cradio_left)
+
+config SHIELD_CRADIO_RIGHT
+ def_bool $(shields_list_contains,cradio_right)
diff --git a/app/boards/shields/cradio/cradio.dtsi b/app/boards/shields/cradio/cradio.dtsi
new file mode 100644
index 0000000..43f9049
--- /dev/null
+++ b/app/boards/shields/cradio/cradio.dtsi
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+ #include <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ 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";
+ 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/cradio/cradio.keymap b/app/boards/shields/cradio/cradio.keymap
new file mode 100644
index 0000000..487f6dc
--- /dev/null
+++ b/app/boards/shields/cradio/cradio.keymap
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/bt.h>
+
+
+/ {
+ 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
+ &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.conf b/app/boards/shields/cradio/cradio_left.conf
new file mode 100644
index 0000000..405f04d
--- /dev/null
+++ b/app/boards/shields/cradio/cradio_left.conf
@@ -0,0 +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
new file mode 100644
index 0000000..6a3704a
--- /dev/null
+++ b/app/boards/shields/cradio/cradio_left.overlay
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "cradio.dtsi"
diff --git a/app/boards/shields/cradio/cradio_right.conf b/app/boards/shields/cradio/cradio_right.conf
new file mode 100644
index 0000000..bd2c93b
--- /dev/null
+++ b/app/boards/shields/cradio/cradio_right.conf
@@ -0,0 +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
new file mode 100644
index 0000000..01aa1ab
--- /dev/null
+++ b/app/boards/shields/cradio/cradio_right.overlay
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "cradio.dtsi"
+
+&default_transform {
+ col-offset = <17>;
+};
diff --git a/app/boards/shields/iris/iris.keymap b/app/boards/shields/iris/iris.keymap
index 3bd74ed..8b06b1b 100644
--- a/app/boards/shields/iris/iris.keymap
+++ b/app/boards/shields/iris/iris.keymap
@@ -1,5 +1,8 @@
-# Copyright (c) 2020 Pete Johanson, Kurtis Lew
-# SPDX-License-Identifier: MIT
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
diff --git a/app/boards/shields/kyria/kyria.keymap b/app/boards/shields/kyria/kyria.keymap
index f689ef6..ac0d13f 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 <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
diff --git a/app/boards/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap
index 61c19f8..d44b3fe 100644
--- a/app/boards/shields/lily58/lily58.keymap
+++ b/app/boards/shields/lily58/lily58.keymap
@@ -1,6 +1,13 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/ext_power.h>
/ {
keymap {
@@ -32,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 &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
>;
sensor-bindings = <&inc_dec_cp M_VOLU M_VOLD>;
diff --git a/app/boards/shields/m60/Kconfig.defconfig b/app/boards/shields/m60/Kconfig.defconfig
new file mode 100644
index 0000000..e31d5a5
--- /dev/null
+++ b/app/boards/shields/m60/Kconfig.defconfig
@@ -0,0 +1,11 @@
+#
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+#
+
+if SHIELD_M60
+
+config ZMK_KEYBOARD_NAME
+ default "m60"
+
+endif
diff --git a/app/boards/shields/m60/Kconfig.shield b/app/boards/shields/m60/Kconfig.shield
new file mode 100644
index 0000000..47a28e2
--- /dev/null
+++ b/app/boards/shields/m60/Kconfig.shield
@@ -0,0 +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.conf b/app/boards/shields/m60/m60.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/boards/shields/m60/m60.conf
diff --git a/app/boards/shields/m60/m60.keymap b/app/boards/shields/m60/m60.keymap
new file mode 100644
index 0000000..cbe356c
--- /dev/null
+++ b/app/boards/shields/m60/m60.keymap
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/bt.h>
+
+/ {
+ 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
+ >;
+ };
+
+ 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
+ >;
+ };
+ };
+};
diff --git a/app/boards/shields/m60/m60.overlay b/app/boards/shields/m60/m60.overlay
new file mode 100644
index 0000000..babae2d
--- /dev/null
+++ b/app/boards/shields/m60/m60.overlay
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ 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 0000000..e801c78
--- /dev/null
+++ b/app/boards/shields/m60/readme.md
@@ -0,0 +1,14 @@
+# [Makerdiary M60](https://wiki.makerdiary.com/m60)
+
+A 60% ANSI keyboard designed and manufactured by Makerdiary.
+http://makerdiary.com
+
+## Features
+
+- Per key RGB LED.
+- Uses makerdiary M.2 nRF52840 module
+- Matrix wiring
+
+## Hardware Notes
+
+https://wiki.makerdiary.com/m60/developer_guide/hardware/
diff --git a/app/boards/shields/microdox/Kconfig.defconfig b/app/boards/shields/microdox/Kconfig.defconfig
new file mode 100644
index 0000000..4840ece
--- /dev/null
+++ b/app/boards/shields/microdox/Kconfig.defconfig
@@ -0,0 +1,60 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+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 0000000..ac79eab
--- /dev/null
+++ b/app/boards/shields/microdox/Kconfig.shield
@@ -0,0 +1,8 @@
+# Copyright (c) 2020 The ZMK Contributors
+# 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 0000000..58cd861
--- /dev/null
+++ b/app/boards/shields/microdox/boards/nice_nano.overlay
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+&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 0000000..b79385b
--- /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 0000000..55c67dd
--- /dev/null
+++ b/app/boards/shields/microdox/microdox.dtsi
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ 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)>
+ ;
+
+ };
+
+ // 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 0000000..5747771
--- /dev/null
+++ b/app/boards/shields/microdox/microdox.keymap
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/bt.h>
+
+/ {
+ keymap {
+ compatible = "zmk,keymap";
+
+ default_layer {
+// -----------------------------------------------------------------------------------------
+// | 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 LSFT &kp SPC &mo 2 &kp RALT
+ >;
+ };
+ nav_layer {
+// -----------------------------------------------------------------------------------------
+// |BTCLR| | ESC | ~ | | | TAB | HOME | UP | END | DEL |
+// | BT1 | GUI | ALT | CTRL | NUM | | / | LEFT | DOWN | RGT | BKSP |
+// | BT2 | | | | | | \ | ENT | | | |
+// | | | | | | | |
+ bindings = <
+ &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
+ >;
+ };
+
+ sym_layer {
+// -----------------------------------------------------------------------------------------
+// | ! | @ | # | $ | % | | ^ | & | * | ( | ) |
+// | | | | | | | - | = | { | } | "|" |
+// | | | | | | | _ | + | [ | ] | \ |
+// | 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
+ >;
+ };
+
+// This layer is unreachable until "tri layer state" is sorted out.
+// Leaving it here for completeness.
+ 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
+ >;
+ };
+ };
+};
+
diff --git a/app/boards/shields/microdox/microdox_left.conf b/app/boards/shields/microdox/microdox_left.conf
new file mode 100644
index 0000000..1e028a7
--- /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 0000000..4d0378e
--- /dev/null
+++ b/app/boards/shields/microdox/microdox_left.overlay
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * 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>
+ ;
+};
diff --git a/app/boards/shields/microdox/microdox_right.conf b/app/boards/shields/microdox/microdox_right.conf
new file mode 100644
index 0000000..990cf7c
--- /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 0000000..c5622b2
--- /dev/null
+++ b/app/boards/shields/microdox/microdox_right.overlay
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * 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>
+ ;
+};
diff --git a/app/boards/shields/qaz/qaz.conf b/app/boards/shields/qaz/qaz.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/boards/shields/qaz/qaz.conf
diff --git a/app/boards/shields/quefrency/Kconfig.defconfig b/app/boards/shields/quefrency/Kconfig.defconfig
new file mode 100644
index 0000000..2b00cb6
--- /dev/null
+++ b/app/boards/shields/quefrency/Kconfig.defconfig
@@ -0,0 +1,17 @@
+#Copyright (c) 2020 The ZMK Contributors
+#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 0000000..d205e58
--- /dev/null
+++ b/app/boards/shields/quefrency/Kconfig.shield
@@ -0,0 +1,8 @@
+# Copyright (c) 2020 The ZMK Contributors
+# 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 0000000..e69de29
--- /dev/null
+++ b/app/boards/shields/quefrency/quefrency.conf
diff --git a/app/boards/shields/quefrency/quefrency.dtsi b/app/boards/shields/quefrency/quefrency.dtsi
new file mode 100644
index 0000000..5f1e908
--- /dev/null
+++ b/app/boards/shields/quefrency/quefrency.dtsi
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ chosen {
+ zmk,kscan = &kscan0;
+
+ 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>;
+ 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 0000000..21c5ed4
--- /dev/null
+++ b/app/boards/shields/quefrency/quefrency.keymap
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+
+/ {
+ 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 0000000..1e028a7
--- /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 0000000..a385cc5
--- /dev/null
+++ b/app/boards/shields/quefrency/quefrency_left.overlay
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#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";
+ 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 0000000..990cf7c
--- /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 0000000..53e0f77
--- /dev/null
+++ b/app/boards/shields/quefrency/quefrency_right.overlay
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include "quefrency.dtsi"
+
+&default_transform {
+ col-offset = <7>;
+};
+
+/ {
+
+ /* 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";
+ 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)>
+ ;
+ };
+};
diff --git a/app/boards/shields/romac/romac.keymap b/app/boards/shields/romac/romac.keymap
index 97ea9c5..31e1ce8 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/romac_plus/Kconfig.defconfig b/app/boards/shields/romac_plus/Kconfig.defconfig
new file mode 100644
index 0000000..c4efdb9
--- /dev/null
+++ b/app/boards/shields/romac_plus/Kconfig.defconfig
@@ -0,0 +1,9 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+if SHIELD_ROMAC_PLUS
+
+config ZMK_KEYBOARD_NAME
+ default "RoMac+ 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 0000000..a7c7c61
--- /dev/null
+++ b/app/boards/shields/romac_plus/Kconfig.shield
@@ -0,0 +1,5 @@
+# Copyright (c) 2020 The ZMK Contributors
+# 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 0000000..a8dafa2
--- /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 0000000..d784dc4
--- /dev/null
+++ b/app/boards/shields/romac_plus/romac_plus.conf
@@ -0,0 +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
new file mode 100644
index 0000000..9b148ca
--- /dev/null
+++ b/app/boards/shields/romac_plus/romac_plus.dtsi
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ 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>;
+ };
+
+ // 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 0000000..d8d1f78
--- /dev/null
+++ b/app/boards/shields/romac_plus/romac_plus.keymap
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/keys.h>
+
+/ {
+ keymap {
+ compatible = "zmk,keymap";
+
+ default_layer {
+// --------------------------
+// | 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 &mo 1
+ >;
+
+ sensor-bindings = <&inc_dec_cp M_NEXT M_PREV>;
+ };
+
+ 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>;
+ };
+ };
+}; \ 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 0000000..8643034
--- /dev/null
+++ b/app/boards/shields/romac_plus/romac_plus.overlay
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * 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>
+ ;
+ };
+
+};
+
+&left_encoder {
+ status = "okay";
+}; \ No newline at end of file
diff --git a/app/boards/shields/sofle/sofle.keymap b/app/boards/shields/sofle/sofle.keymap
index 1cbe742..e2ebc1a 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 <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
diff --git a/app/boards/shields/splitreus62/splitreus62.keymap b/app/boards/shields/splitreus62/splitreus62.keymap
index 920e61a..07dd2ad 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 <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
diff --git a/app/boards/shields/tg4x/Kconfig.defconfig b/app/boards/shields/tg4x/Kconfig.defconfig
new file mode 100644
index 0000000..ca9fa2c
--- /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 0000000..7e98b71
--- /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 0000000..bee5c87
--- /dev/null
+++ b/app/boards/shields/tg4x/tg4x.keymap
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/keys.h>
+#include <dt-bindings/zmk/bt.h>
+
+#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 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 &lt 1 BKSP &lt 2 SPC &kp LARW &kp DARW &kp UARW &kp RARW
+ >;
+ };
+ lower {
+ 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 &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 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
+ >;
+ };
+ };
+}; \ 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 0000000..10ce524
--- /dev/null
+++ b/app/boards/shields/tg4x/tg4x.overlay
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2020 The ZMK Contrbutors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ 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)>
+ ;
+
+ };
+
+};
+
diff --git a/app/drivers/zephyr/Kconfig b/app/drivers/zephyr/Kconfig
index 0237846..0534cab 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/ec11.c b/app/drivers/zephyr/ec11.c
index a4e96c2..00d0090 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
diff --git a/app/drivers/zephyr/kscan_gpio_direct.c b/app/drivers/zephyr/kscan_gpio_direct.c
index 1e5ab59..4818c99 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(CONFIG_ZMK_KSCAN_DIRECT_POLLING)
struct k_timer poll_timer;
-#endif /* defined(CONFIG_ZMK_KSCAN_GPIO_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(CONFIG_ZMK_KSCAN_GPIO_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(CONFIG_ZMK_KSCAN_GPIO_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(CONFIG_ZMK_KSCAN_GPIO_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(CONFIG_ZMK_KSCAN_GPIO_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_GPIO_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_GPIO_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); \
@@ -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 634f694..ec4fb39 100644
--- a/app/drivers/zephyr/kscan_gpio_matrix.c
+++ b/app/drivers/zephyr/kscan_gpio_matrix.c
@@ -31,6 +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)
+#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) {
@@ -48,6 +49,8 @@ static int kscan_gpio_config_interrupts(struct device **devices,
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)
#define INST_OUTPUT_LEN(n) \
@@ -61,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 { \
@@ -69,6 +73,7 @@ static int kscan_gpio_config_interrupts(struct device **devices,
}; \
struct kscan_gpio_data_##n { \
kscan_callback_t callback; \
+ 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)]; \
@@ -96,21 +101,25 @@ 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); \
- } \
+ COND_CODE_1(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_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), \
+ 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++) { \
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( \
@@ -128,7 +137,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. */ \
- 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 +151,8 @@ 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); \
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]; \
@@ -165,6 +171,9 @@ 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 { \
+ COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \
+ (kscan_gpio_enable_interrupts_##n(dev);)) \
} \
return 0; \
} \
@@ -176,12 +185,15 @@ 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); \
+ 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}}; \
static int kscan_gpio_configure_##n(struct device *dev, kscan_callback_t callback) { \
@@ -190,15 +202,29 @@ 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_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;), \
+ (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_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, \
+ (struct kscan_gpio_data_##n *data = dev->driver_data; \
+ k_timer_stop(&data->poll_timer); return 0;), \
+ (return kscan_gpio_disable_interrupts_##n(dev);)) \
}; \
+ 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; \
@@ -214,8 +240,11 @@ 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; \
+ 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); \
@@ -241,6 +270,8 @@ static int kscan_gpio_config_interrupts(struct device **devices,
} \
} \
data->dev = dev; \
+ 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; \
@@ -248,7 +279,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)}, \
diff --git a/app/dts/behaviors.dtsi b/app/dts/behaviors.dtsi
index 202202b..36c918c 100644
--- a/app/dts/behaviors.dtsi
+++ b/app/dts/behaviors.dtsi
@@ -8,4 +8,5 @@
#include <behaviors/reset.dtsi>
#include <behaviors/sensor_rotate_key_press.dtsi>
#include <behaviors/rgb_underglow.dtsi>
-#include <behaviors/bluetooth.dtsi> \ No newline at end of file
+#include <behaviors/bluetooth.dtsi>
+#include <behaviors/ext_power.dtsi>
diff --git a/app/dts/behaviors/ext_power.dtsi b/app/dts/behaviors/ext_power.dtsi
new file mode 100644
index 0000000..92f0035
--- /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 = <1>;
+ };
+ };
+};
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 0000000..d86c6f9
--- /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: one_param.yaml
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 bbf3537..6b33910 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 0000000..5a38a09
--- /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 c56361d..86ae5c2 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/behavior.h b/app/include/drivers/behavior.h
index 45b8bea..cf259b1 100644
--- a/app/include/drivers/behavior.h
+++ b/app/include/drivers/behavior.h
@@ -10,6 +10,7 @@
#include <stddef.h>
#include <device.h>
#include <zmk/keys.h>
+#include <zmk/behavior.h>
/**
* @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/drivers/ext_power.h b/app/include/drivers/ext_power.h
new file mode 100644
index 0000000..6c1923e
--- /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 <zephyr/types.h>
+#include <stddef.h>
+#include <device.h>
+
+#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 <syscalls/ext_power.h>
diff --git a/app/include/dt-bindings/zmk/bt.h b/app/include/dt-bindings/zmk/bt.h
index 05fd65c..8ca1060 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 <peter@peterjohanson.com>
+ * Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
@@ -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/include/dt-bindings/zmk/ext_power.h b/app/include/dt-bindings/zmk/ext_power.h
new file mode 100644
index 0000000..2a3e846
--- /dev/null
+++ b/app/include/dt-bindings/zmk/ext_power.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define EXT_POWER_OFF_CMD 0
+#define EXT_POWER_ON_CMD 1
+#define EXT_POWER_TOGGLE_CMD 2
+
+#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/include/dt-bindings/zmk/keys.h b/app/include/dt-bindings/zmk/keys.h
index d3dd634..a3b2229 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 d481899..eff218b 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 4fd3e6c..2989cb6 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 c2efda8..eb72180 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/behavior.h b/app/include/zmk/behavior.h
index 6f5815f..428ae24 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/ble/profile.h b/app/include/zmk/ble/profile.h
index 9a79c6d..1df2743 100644
--- a/app/include/zmk/ble/profile.h
+++ b/app/include/zmk/ble/profile.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ * 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 66f40c7..1e3a198 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 <peter@peterjohanson.com>
+ * 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 4c00654..1e2c24e 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 f88080d..e4cbbbe 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 6192587..b8f4969 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/include/zmk/split/bluetooth/service.h b/app/include/zmk/split/bluetooth/service.h
index 954e0cd..c2be512 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 a8dfbf6..a31884d 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 <bluetooth/uuid.h>
diff --git a/app/include/zmk/usb_hid.h b/app/include/zmk/usb.h
index 7ee2629..452fd54 100644
--- a/app/include/zmk/usb_hid.h
+++ b/app/include/zmk/usb.h
@@ -12,6 +12,8 @@
#include <zmk/keys.h>
#include <zmk/hid.h>
-int zmk_usb_hid_init();
+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/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c
index 09fadba..066c437 100644
--- a/app/src/behaviors/behavior_bt.c
+++ b/app/src/behaviors/behavior_bt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Peter Johanson <peter@peterjohanson.com>
+ * Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
@@ -8,18 +8,18 @@
#include <device.h>
#include <drivers/behavior.h>
-
#include <dt-bindings/zmk/bt.h>
-
#include <bluetooth/conn.h>
-
#include <logging/log.h>
+#include <zmk/behavior.h>
+
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/ble.h>
-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_ext_power.c b/app/src/behaviors/behavior_ext_power.c
new file mode 100644
index 0000000..825f983
--- /dev/null
+++ b/app/src/behaviors/behavior_ext_power.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define DT_DRV_COMPAT zmk_behavior_ext_power
+
+#include <device.h>
+#include <devicetree.h>
+#include <drivers/behavior.h>
+#include <drivers/ext_power.h>
+
+#include <dt-bindings/zmk/ext_power.h>
+
+#include <logging/log.h>
+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) {
+ struct device *ext_power = device_get_binding("EXT_POWER");
+ if (ext_power == NULL) {
+ LOG_ERR("Unable to retrieve ext_power device: %d", binding->param1);
+ return -EIO;
+ }
+
+ switch (binding->param1) {
+ case EXT_POWER_OFF_CMD:
+ return ext_power_disable(ext_power);
+ case EXT_POWER_ON_CMD:
+ return ext_power_enable(ext_power);
+ case EXT_POWER_TOGGLE_CMD:
+ if (ext_power_get(ext_power) > 0)
+ return ext_power_disable(ext_power);
+ else
+ return ext_power_enable(ext_power);
+ default:
+ LOG_ERR("Unknown ext_power command: %d", binding->param1);
+ }
+
+ return -ENOTSUP;
+}
+
+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_APPLICATION_INIT_PRIORITY, &behavior_ext_power_driver_api);
diff --git a/app/src/behaviors/behavior_hold_tap.c b/app/src/behaviors/behavior_hold_tap.c
index 8f307a6..8b3620e 100644
--- a/app/src/behaviors/behavior_hold_tap.c
+++ b/app/src/behaviors/behavior_hold_tap.c
@@ -10,7 +10,6 @@
#include <drivers/behavior.h>
#include <logging/log.h>
#include <zmk/behavior.h>
-
#include <zmk/matrix.h>
#include <zmk/endpoints.h>
#include <zmk/event-manager.h>
@@ -18,6 +17,7 @@
#include <zmk/events/keycode-state-changed.h>
#include <zmk/events/modifiers-state-changed.h>
#include <zmk/hid.h>
+#include <zmk/behavior.h>
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 bbfbe36..923b098 100644
--- a/app/src/behaviors/behavior_key_press.c
+++ b/app/src/behaviors/behavior_key_press.c
@@ -12,6 +12,7 @@
#include <zmk/event-manager.h>
#include <zmk/events/keycode-state-changed.h>
+#include <zmk/behavior.h>
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 = {
@@ -47,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)
diff --git a/app/src/behaviors/behavior_momentary_layer.c b/app/src/behaviors/behavior_momentary_layer.c
index 80b7165..b1fb14b 100644
--- a/app/src/behaviors/behavior_momentary_layer.c
+++ b/app/src/behaviors/behavior_momentary_layer.c
@@ -11,6 +11,7 @@
#include <logging/log.h>
#include <zmk/keymap.h>
+#include <zmk/behavior.h>
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 b548e6f..96ea9d5 100644
--- a/app/src/behaviors/behavior_none.c
+++ b/app/src/behaviors/behavior_none.c
@@ -11,6 +11,8 @@
#include <drivers/behavior.h>
#include <logging/log.h>
+#include <zmk/behavior.h>
+
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 90de20b..d1233a5 100644
--- a/app/src/behaviors/behavior_reset.c
+++ b/app/src/behaviors/behavior_reset.c
@@ -11,6 +11,8 @@
#include <drivers/behavior.h>
#include <logging/log.h>
+#include <zmk/behavior.h>
+
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 621eab5..2ee6716 100644
--- a/app/src/behaviors/behavior_rgb_underglow.c
+++ b/app/src/behaviors/behavior_rgb_underglow.c
@@ -12,13 +12,15 @@
#include <dt-bindings/zmk/rgb.h>
#include <zmk/rgb_underglow.h>
+#include <zmk/keymap.h>
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 1a0bf03..71c4376 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 2819451..b3c6961 100644
--- a/app/src/behaviors/behavior_toggle_layer.c
+++ b/app/src/behaviors/behavior_toggle_layer.c
@@ -11,6 +11,7 @@
#include <logging/log.h>
#include <zmk/keymap.h>
+#include <zmk/behavior.h>
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 f7852f3..cede369 100644
--- a/app/src/behaviors/behavior_transparent.c
+++ b/app/src/behaviors/behavior_transparent.c
@@ -11,6 +11,8 @@
#include <drivers/behavior.h>
#include <logging/log.h>
+#include <zmk/behavior.h>
+
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/ble.c b/app/src/ble.c
index 49e2b3b..9090582 100644
--- a/app/src/ble.c
+++ b/app/src/ble.c
@@ -45,10 +45,29 @@ 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_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[] = {
+#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)
@@ -92,29 +111,101 @@ 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;
}
- return 0;
-};
+ bt_conn_unref(conn);
-int zmk_ble_adv_resume() {
- LOG_DBG("active_profile %d, directed? %s", active_profile,
- active_profile_is_open() ? "no" : "yes");
+ return true;
+}
- 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;
+#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_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();
+ 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;
};
+static void update_advertising_callback(struct k_work *work) { update_advertising(); }
+
+K_WORK_DEFINE(update_advertising_work, update_advertising_callback);
+
int zmk_ble_clear_bonds() {
LOG_DBG("");
@@ -124,6 +215,8 @@ int zmk_ble_clear_bonds() {
set_profile_address(active_profile, BT_ADDR_LE_ANY);
}
+ update_advertising();
+
return 0;
};
@@ -134,9 +227,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 +331,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 +350,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 +361,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 +458,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 +481,7 @@ static void zmk_ble_ready(int err) {
return;
}
- zmk_ble_adv_resume();
+ update_advertising();
}
static int zmk_ble_init(struct device *_arg) {
diff --git a/app/src/endpoints.c b/app/src/endpoints.c
index ae78587..79d294e 100644
--- a/app/src/endpoints.c
+++ b/app/src/endpoints.c
@@ -6,7 +6,7 @@
#include <zmk/endpoints.h>
#include <zmk/hid.h>
-#include <zmk/usb_hid.h>
+#include <zmk/usb.h>
#include <zmk/hog.h>
#include <logging/log.h>
diff --git a/app/src/events/ble_active_profile_changed.c b/app/src/events/ble_active_profile_changed.c
index a270a14..06988e2 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 <peter@peterjohanson.com>
+ * Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
diff --git a/app/src/ext_power_generic.c b/app/src/ext_power_generic.c
new file mode 100644
index 0000000..4817030
--- /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 <device.h>
+#include <init.h>
+#include <drivers/gpio.h>
+#include <drivers/ext_power.h>
+
+#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
+
+#include <logging/log.h>
+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/hog.c b/app/src/hog.c
index 11349ac..bcd652d 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;
};
diff --git a/app/src/keymap.c b/app/src/keymap.c
index a87ce04..74fe60d 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 0046f5c..8575e70 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/kscan_composite.c b/app/src/kscan_composite.c
index 0249140..f8e8d60 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);
diff --git a/app/src/main.c b/app/src/main.c
index dca923e..0551356 100644
--- a/app/src/main.c
+++ b/app/src/main.c
@@ -15,16 +15,25 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/matrix.h>
#include <zmk/kscan.h>
#include <zmk/display.h>
+#include <drivers/ext_power.h>
#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();
diff --git a/app/src/power.c b/app/src/power.c
new file mode 100644
index 0000000..73b3f12
--- /dev/null
+++ b/app/src/power.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <zephyr.h>
+#include <kernel.h>
+#include <power/power.h>
+
+#include <logging/log.h>
+
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+#include <zmk/usb.h>
+#include <zmk/event-manager.h>
+#include <zmk/events/position-state-changed.h>
+#include <zmk/events/sensor-event.h>
+
+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
diff --git a/app/src/split/bluetooth/central.c b/app/src/split/bluetooth/central.c
index cb1b68b..ed52ba0 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/src/usb_hid.c b/app/src/usb.c
index 530ffea..434b3d4 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);
@@ -49,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 */
+
+enum usb_dc_status_code zmk_usb_get_status() { return usb_status; }
-static int zmk_usb_hid_init(struct device *_arg) {
+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");
@@ -64,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");
@@ -74,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);
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 0000000..fdf2b15
--- /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 0000000..806896f
--- /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 0000000..3cb04c3
--- /dev/null
+++ b/app/tests/hold-tap/balanced/many-nested/native_posix.keymap
@@ -0,0 +1,41 @@
+#include <dt-bindings/zmk/keys.h>
+#include <behaviors.dtsi>
+#include <dt-bindings/zmk/kscan-mock.h>
+
+/ {
+ 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)
+ >;
+};
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 0000000..82278ad
--- /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
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 0000000..e5c22b0
--- /dev/null
+++ b/docs/docs/assets/dev-setup/vscode_devcontainer.png
Binary files differ
diff --git a/docs/docs/assets/troubleshooting/filetransfer/mac.png b/docs/docs/assets/troubleshooting/filetransfer/mac.png
new file mode 100644
index 0000000..f28ca8d
--- /dev/null
+++ b/docs/docs/assets/troubleshooting/filetransfer/mac.png
Binary files differ
diff --git a/docs/docs/behavior/bluetooth.md b/docs/docs/behavior/bluetooth.md
index f802a9a..be0fb23 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. |
@@ -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)):
diff --git a/docs/docs/behavior/power.md b/docs/docs/behavior/power.md
new file mode 100644
index 0000000..6b8237b
--- /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 <dt-bindings/zmk/ext_power.h>
+```
+
+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/docs/bond-reset.md b/docs/docs/bond-reset.md
index 1ba79ee..504fd72 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/customization.md b/docs/docs/customization.md
index 0bb1794..261c40d 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:
+* `<shield>.conf`
+* `<shield>`.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).
diff --git a/docs/docs/dev-build.md b/docs/docs/dev-build.md
index 816468e..83ed8cb 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
diff --git a/docs/docs/dev-clean-room.md b/docs/docs/dev-clean-room.md
index c11171c..2f301ec 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.
diff --git a/docs/docs/dev-guide-new-shield.md b/docs/docs/dev-guide-new-shield.md
index 6140b07..9f7b23c 100644
--- a/docs/docs/dev-guide-new-shield.md
+++ b/docs/docs/dev-guide-new-shield.md
@@ -17,9 +17,14 @@ 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.
+:::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:
@@ -44,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
@@ -62,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`.
+<Tabs
+defaultValue="unibody"
+values={[
+{label: 'Unibody Shields', value: 'unibody'},
+{label: 'Split Shields', value: 'split'},
+]}>
+
+<TabItem value="unibody">
+
The `<shield_name>.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:
@@ -97,6 +141,146 @@ this might look something like:
};
```
+</TabItem>
+
+<TabItem value="split">
+
+### .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 <dt-bindings/zmk/matrix-transform.h>
+
+/ {
+ 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 `<boardname>_left.overlay` and `<boardname>_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
+```
+
+</TabItem>
+</Tabs>
+
## (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:
@@ -302,3 +486,41 @@ 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.
+
+```
+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
+ - <MY_BOARD>
+ - <MY_SPLIT_BOARD_left>
+ - <MY_SPLIT_BOARD_right>
+ 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
diff --git a/docs/docs/dev-setup.md b/docs/docs/dev-setup.md
index 1d7d703..521d5d0 100644
--- a/docs/docs/dev-setup.md
+++ b/docs/docs/dev-setup.md
@@ -12,16 +12,17 @@ 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'},
+{label: 'VS Code & Docker', value: 'docker'},
]
}>{props.children}</Tabs>);
## 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 +35,7 @@ A unix-like environment with the following base packages installed:
<OsTabs>
<TabItem value="debian">
+
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 +76,8 @@ or download and install CMake version 3.13.1 or newer manually.
:::
</TabItem>
<TabItem value="raspberryos">
-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:
@@ -165,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
+```
</TabItem>
<TabItem value="mac">
@@ -173,10 +180,24 @@ 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
```
</TabItem>
+<TabItem value="docker">
+
+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).
+:::
+
+</TabItem>
</OsTabs>
## Setup
@@ -185,14 +206,40 @@ 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:
+
+<Tabs
+defaultValue="linux"
+values={[
+{label: 'Linux', value: 'linux'},
+{label: 'Windows', value: 'win'},
+]}>
+<TabItem value = 'linux'>
```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.
+</TabItem>
+<TabItem value = 'win'>
+
+In `cmd.exe` as **Administrator**:
+
+```sh
+pip3 install -U west
+```
+
+:::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.
+
+</TabItem>
+</Tabs>
+
+:::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.
:::
<Tabs
@@ -213,7 +260,8 @@ source ~/.bashrc
<TabItem value = 'win'>
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`.
</TabItem>
</Tabs>
@@ -279,7 +327,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.
</TabItem>
<TabItem value="mac">
@@ -308,7 +356,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
@@ -320,12 +368,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
+<OsTabs>
+<TabItem value="debian">
+
+```sh
+cd zmk
+```
+
+</TabItem>
+<TabItem value="raspberryos">
+
+```sh
+cd zmk
+```
+
+</TabItem>
+<TabItem value="fedora">
+
+```sh
+cd zmk
+```
+
+</TabItem>
+<TabItem value="mac">
+
```sh
cd zmk
```
+</TabItem>
+<TabItem value="win">
+
+```sh
+cd zmk
+```
+
+</TabItem>
+
+<TabItem value="docker">
+
+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.
+:::
+
+</TabItem>
+</OsTabs>
+
#### Initialize West
```sh
@@ -344,6 +443,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
@@ -358,12 +468,17 @@ pip3 install --user -r zephyr/scripts/requirements-base.txt
### Environment Variables
-#### For GNU ARM Embedded on Windows
+<Tabs
+defaultValue="win"
+values={[
+{label: 'Windows', value: 'win'},
+{label: 'Other OS', value: 'other'},
+]}>
+<TabItem value = 'win'>
-On Windows, you will have to set two environment variables for ZMK to build properly: `ZEPHYR_TOOLCHAIN_VARIANT` and `GNUARMEMB_TOOLCHAIN_PATH`.
+#### For GNU ARM Embedded on Windows
-<details>
-<summary> Steps to Update Environment Variables </summary>
+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 +496,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)
-</details>
+6. Close Command Prompt and reopen, or run `refreshenv` to apply the changes.
+
+</TabItem>
+
+<TabItem value = 'other'>
#### For Zephyr
@@ -396,48 +515,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:
-<OsTabs>
-<TabItem value="debian">
-
-```
-source zephyr/zephyr-env.sh
-```
-
-</TabItem>
-
-<TabItem value="raspberryos">
-
-```
-source zephyr/zephyr-env.sh
-```
-
-</TabItem>
-
-<TabItem value="fedora">
-
-```
-source zephyr/zephyr-env.sh
-```
-
-</TabItem>
-
-<TabItem value="mac">
-
```
source zephyr/zephyr-env.sh
```
-</TabItem>
-
-<TabItem value="win">
-
-```
-source zephyr/zephyr-env.cmd
-```
-
-</TabItem>
-</OsTabs>
-
##### All Shells
To load the environment variables for your shell every time,
@@ -469,3 +550,7 @@ cat ~/.zephyrrc >> ~/.zshrc
</TabItem>
</Tabs>
+
+</TabItem>
+
+</Tabs>
diff --git a/docs/docs/feature/encoders.md b/docs/docs/feature/encoders.md
index 38ff9d3..9caccc2 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.
diff --git a/docs/docs/hardware.md b/docs/docs/hardware.md
index 299d1f5..fe229df 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`)
@@ -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
diff --git a/docs/docs/intro.md b/docs/docs/intro.md
index 8c1c043..60fe0d2 100644
--- a/docs/docs/intro.md
+++ b/docs/docs/intro.md
@@ -5,39 +5,41 @@ 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. 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
+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 |
+|--------------------------------------------------------------------------------------------------------|:-----------:|:------------:|:-----------:|
+| Low Latency BLE Support | ✅ | ✅ | |
+| 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] | 🚧 | 🚧 | ✅ |
+| [RGB Underglow](feature/underglow) | ✅ | ✅ | ✅ |
+| One Shot Keys | 🚧 | ✅ | ✅ |
+| Combo Keys | 🚧 | | ✅ |
+| Macros | 🚧 | ✅ | ✅ |
+| Mouse Keys | | ✅ | ✅ |
+| Low Active Power Usage | ✅ | | |
+| [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](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.
## Code Of Conduct
diff --git a/docs/docs/troubleshooting.md b/docs/docs/troubleshooting.md
index deb89b6..36682e7 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 `<firmware>.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
@@ -59,3 +63,20 @@ After opening the `<board>.dts.pre.tmp:<line number>` 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
+
+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:
+
+**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
diff --git a/docs/docs/user-setup.md b/docs/docs/user-setup.md
index 2aade82..2785096 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'},
]}>
<TabItem value="curl">
@@ -78,6 +79,12 @@ bash -c "$(wget https://zmkfirmware.dev/setup.sh -O -)"
```
</TabItem>
+<TabItem value="PowerShell">
+
+```
+iex ((New-Object System.Net.WebClient).DownloadString('https://zmkfirmware.dev/setup.ps1'))"
+```
+</TabItem>
</Tabs>
### MCU Board Selection
diff --git a/docs/sidebars.js b/docs/sidebars.js
index ace7fa1..12b4a6e 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -6,7 +6,6 @@ module.exports = {
"faq",
"user-setup",
"customization",
- "bond-reset",
"troubleshooting"
],
Features: [
@@ -24,6 +23,7 @@ module.exports = {
"behavior/reset",
"behavior/bluetooth",
"behavior/lighting",
+ "behavior/power",
],
Development: [
"dev-clean-room",
diff --git a/docs/static/setup.ps1 b/docs/static/setup.ps1
new file mode 100644
index 0000000..5ebd376
--- /dev/null
+++ b/docs/static/setup.ps1
@@ -0,0 +1,206 @@
+# Copyright (c) 2020 The ZMK Contributors
+#
+# SPDX-License-Identifier: MIT
+
+$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 1
+ }
+ 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 1
+ }
+}
+
+try {
+ git | Out-Null
+}
+catch [System.Management.Automation.CommandNotFoundException] {
+ Write-Host "Git is not installed, and is required for this script!"
+ exit 1
+}
+
+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.email 'example@myemail.com'"
+
+$permission = (Get-Acl $pwd).Access |
+?{$_.IdentityReference -match $env:UserName `
+ -and $_.FileSystemRights -match "FullControl" `
+ -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:"
+$prompt = "Pick an MCU board"
+$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 ""
+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", "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])
+$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 1
+}
+
+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 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 GitHub Actions shortly: $actions"
+ }
+}
diff --git a/docs/static/setup.sh b/docs/static/setup.sh
index 5d203a4..e45a7ed 100644
--- a/docs/static/setup.sh
+++ b/docs/static/setup.sh
@@ -1,49 +1,69 @@
-#!/bin/sh
+#!/bin/bash
+
+# Copyright (c) 2020 The ZMK Contributors
+#
+# SPDX-License-Identifier: MIT
set -e
-repo_path="https://github.com/zmkfirmware/zmk-config-split-template.git"
-title="ZMK Config Setup:"
+check_exists() {
+ command_to_run=$1
+ error_message=$2
+
+ if ! eval "$command_to_run" &> /dev/null; then
+ printf "%s\n" "$error_message"
+ exit 1
+ fi
+}
+
+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!"
+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'"
-# TODO: Check for git being installed
-# TODO: Check for curl being installed
-# TODO: Check for user.name and user.email git configs being set
+# 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:"
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 ""
echo "MCU Board Selection:"
PS3="$prompt "
-select opt in "${options[@]}" "Quit"; do
+select opt in "${options[@]}" "Quit"; do
case "$REPLY" in
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;;
- *) echo "Invalid option. Try another one.";continue;;
+ $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;;
+ *) echo "Invalid option. Try another one."; continue;;
esac
done
-#read -p "Is this board a complete keyboard [yN]: " complete
-#echo "$complete"
-
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" "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.
-# 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
@@ -54,10 +74,15 @@ 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="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;;
+ 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;;
- $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit;;
+ # $(( ${#options[@]}+1 )) ) echo "Other!"; break;;
+ $(( ${#options[@]}+1 )) ) echo "Goodbye!"; exit 1;;
*) echo "Invalid option. Try another one.";continue;;
esac
@@ -67,41 +92,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 1
fi
git clone --single-branch $repo_path ${repo_name}
@@ -118,10 +145,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 +163,24 @@ 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)"
+ push_return_code=$?
+
+ # If push failed, assume that the origin was incorrect and give instructions on fixing.
+ 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: "
+ 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
+ fi
# 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 GitHub Actions shortly: ${github_repo%.git}/actions"
fi
fi