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--app/CMakeLists.txt2
-rw-r--r--app/Kconfig4
-rw-r--r--app/boards/arm/nice_nano/nice_nano.dts5
-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/shields/lily58/lily58.keymap11
-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/kscan_gpio_matrix.c25
-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.h2
-rw-r--r--app/include/dt-bindings/zmk/ext_power.h13
-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/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/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/main.c9
-rw-r--r--app/src/split/bluetooth/central.c1
-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/docs/assets/dev-setup/vscode_devcontainer.pngbin0 -> 20773 bytes
-rw-r--r--docs/docs/dev-build.md13
-rw-r--r--docs/docs/dev-setup.md83
-rw-r--r--docs/docs/user-setup.md7
-rw-r--r--docs/static/setup.ps115
-rw-r--r--docs/static/setup.sh7
60 files changed, 914 insertions, 165 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/app/CMakeLists.txt b/app/CMakeLists.txt
index 3e59d75..39509ed 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -31,6 +31,7 @@ target_sources(app PRIVATE src/sensors.c)
target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c)
target_sources(app PRIVATE src/event_manager.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c)
+target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c)
target_sources(app PRIVATE src/events/position_state_changed.c)
target_sources(app PRIVATE src/events/keycode_state_changed.c)
target_sources(app PRIVATE src/events/modifiers_state_changed.c)
@@ -45,6 +46,7 @@ if (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
target_sources(app PRIVATE src/behaviors/behavior_none.c)
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
+ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
target_sources(app PRIVATE src/keymap.c)
endif()
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
diff --git a/app/Kconfig b/app/Kconfig
index edf5867..fca4912 100644
--- a/app/Kconfig
+++ b/app/Kconfig
@@ -95,6 +95,10 @@ config ZMK_IDLE_SLEEP_TIMEOUT
endif
+config ZMK_EXT_POWER
+ bool "Enable support to control external power output"
+ default y
+
config ZMK_DISPLAY
bool "ZMK display support"
default n
diff --git a/app/boards/arm/nice_nano/nice_nano.dts b/app/boards/arm/nice_nano/nice_nano.dts
index 3ffb0ea..0538b1d 100644
--- a/app/boards/arm/nice_nano/nice_nano.dts
+++ b/app/boards/arm/nice_nano/nice_nano.dts
@@ -29,6 +29,11 @@
};
};
+ ext-power {
+ compatible = "zmk,ext-power-generic";
+ label = "EXT_POWER";
+ control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+ };
};
&gpiote {
diff --git a/app/boards/arm/nrfmicro/nrfmicro_11.dts b/app/boards/arm/nrfmicro/nrfmicro_11.dts
index 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/shields/lily58/lily58.keymap b/app/boards/shields/lily58/lily58.keymap
index 997a124..d44b3fe 100644
--- a/app/boards/shields/lily58/lily58.keymap
+++ b/app/boards/shields/lily58/lily58.keymap
@@ -7,6 +7,7 @@
#include <behaviors.dtsi>
#include <dt-bindings/zmk/keys.h>
#include <dt-bindings/zmk/bt.h>
+#include <dt-bindings/zmk/ext_power.h>
/ {
keymap {
@@ -38,11 +39,11 @@
// | | | | | | | | | | | _ | + | { | } | "|" |
// | | | | | | | | | |
bindings = <
-&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans
-&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12
-&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD
-&trans &trans &trans &trans &trans &trans &trans &trans &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE
- &trans &trans &trans &trans &trans &trans &trans &trans
+&bt BT_CLR &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &trans &trans &trans &trans &trans &trans
+&kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6 &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12
+&kp GRAV &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp KMLT &kp LPRN &kp RPRN &kp TILD
+&trans &ext_power EP_ON &ext_power EP_OFF &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/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/kscan_gpio_matrix.c b/app/drivers/zephyr/kscan_gpio_matrix.c
index a0b22e4..ec4fb39 100644
--- a/app/drivers/zephyr/kscan_gpio_matrix.c
+++ b/app/drivers/zephyr/kscan_gpio_matrix.c
@@ -181,19 +181,18 @@ static int kscan_gpio_config_interrupts(struct device **devices,
struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \
kscan_gpio_read_##n(data->dev); \
} \
- COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \
- (static void kscan_gpio_irq_callback_handler_##n( \
- struct device *dev, struct gpio_callback *cb, gpio_port_pins_t pin) { \
- struct kscan_gpio_irq_callback_##n *data = \
- CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \
- kscan_gpio_disable_interrupts_##n(data->dev); \
- COND_CODE_0(DT_INST_PROP(n, debounce_period), \
- ({ k_work_submit(data->work); }), ({ \
- k_delayed_work_cancel(data->work); \
- k_delayed_work_submit( \
- data->work, K_MSEC(DT_INST_PROP(n, debounce_period))); \
- })) \
- })) \
+ static void kscan_gpio_irq_callback_handler_##n(struct device *dev, struct gpio_callback *cb, \
+ gpio_port_pins_t pin) { \
+ struct kscan_gpio_irq_callback_##n *data = \
+ CONTAINER_OF(cb, struct kscan_gpio_irq_callback_##n, callback); \
+ COND_CODE_1(CONFIG_ZMK_KSCAN_MATRIX_POLLING, (), \
+ (kscan_gpio_disable_interrupts_##n(data->dev);)) \
+ COND_CODE_0(DT_INST_PROP(n, debounce_period), ({ k_work_submit(data->work); }), ({ \
+ k_delayed_work_cancel(data->work); \
+ k_delayed_work_submit(data->work, \
+ K_MSEC(DT_INST_PROP(n, debounce_period))); \
+ })) \
+ } \
\
static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \
.rows = {[INST_MATRIX_ROWS(n) - 1] = NULL}, .cols = {[INST_MATRIX_COLS(n) - 1] = NULL}}; \
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 a403d35..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
*/
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/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/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/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/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/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/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/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/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-setup.md b/docs/docs/dev-setup.md
index 4891f5a..521d5d0 100644
--- a/docs/docs/dev-setup.md
+++ b/docs/docs/dev-setup.md
@@ -16,6 +16,7 @@ values={[
{label: 'macOS', value: 'mac'},
{label: 'Raspberry OS', value: 'raspberryos'},
{label: 'Fedora', value: 'fedora'},
+{label: 'VS Code & Docker', value: 'docker'},
]
}>{props.children}</Tabs>);
@@ -167,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">
@@ -175,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
@@ -349,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
@@ -373,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
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/static/setup.ps1 b/docs/static/setup.ps1
index abdb698..63bd5c0 100644
--- a/docs/static/setup.ps1
+++ b/docs/static/setup.ps1
@@ -57,7 +57,20 @@ catch [System.Management.Automation.CommandNotFoundException] {
}
Test-Git-Config -Option "user.name" -ErrMsg "Git username not set!`nRun: git config --global user.name 'My Name'"
-Test-Git-Config -Option "user.email" -ErrMsg "Git email not set!`nRun: git config --global user.name 'example@myemail.com'"
+Test-Git-Config -Option "user.email" -ErrMsg "Git email not set!`nRun: git config --global user.email 'example@myemail.com'"
+
+$permission = (Get-Acl $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"
diff --git a/docs/static/setup.sh b/docs/static/setup.sh
index 49ed3eb..96e8768 100644
--- a/docs/static/setup.sh
+++ b/docs/static/setup.sh
@@ -22,6 +22,13 @@ check_exists "command -v curl" "curl is not installed, and is required for this
check_exists "git config user.name" "Git username not set!\nRun: git config --global user.name 'My Name'"
check_exists "git config user.email" "Git email not set!\nRun: git config --global user.email 'example@myemail.com'"
+# Check to see if the user has write permissions in this directory to prevent a cryptic error later on
+if [ ! -w `pwd` ]; then
+ echo 'Sorry, you do not have write permissions in this directory.';
+ echo 'Please try running this script again from a directory that you do have write permissions for.';
+ exit 1
+fi
+
repo_path="https://github.com/zmkfirmware/zmk-config-split-template.git"
title="ZMK Config Setup:"