summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorCarey <kcarey1@APC02S226SG8WM.local>2020-10-28 07:40:54 -0500
committerCarey <kcarey1@APC02S226SG8WM.local>2020-10-28 07:40:54 -0500
commit99ad9cbdefee94007511ec2e53437951cf0e4305 (patch)
tree168c9886965ad5e5f36f4fbbad55cd5f70c5124e /app
parent6aae66782682ffcabf953d785308b83ee16fc3b6 (diff)
parentcb922fd8a2a3eddcbece040ca3727d43b171ffe3 (diff)
Merge https://github.com/zmkfirmware/zmk into refactor_kconfig
Diffstat (limited to 'app')
-rw-r--r--app/CMakeLists.txt2
-rw-r--r--app/boards/arm/bluemicro840/Kconfig.defconfig3
-rw-r--r--app/boards/arm/bluemicro840/bluemicro840_v1.dts12
-rw-r--r--app/boards/arm/nice_nano/Kconfig.defconfig3
-rw-r--r--app/boards/arm/nice_nano/nice_nano.dts12
-rw-r--r--app/boards/arm/nrfmicro/Kconfig.defconfig3
-rw-r--r--app/boards/arm/nrfmicro/nrfmicro_13.dts12
-rw-r--r--app/boards/shields/Kconfig.defconfig14
-rw-r--r--app/boards/shields/Kconfig.shield5
-rw-r--r--app/boards/shields/boardsource3x4/Kconfig.defconfig9
-rw-r--r--app/boards/shields/boardsource3x4/Kconfig.shield6
-rw-r--r--app/boards/shields/boardsource3x4/boardsource3x4.conf0
-rw-r--r--app/boards/shields/boardsource3x4/boardsource3x4.keymap49
-rw-r--r--app/boards/shields/boardsource3x4/boardsource3x4.overlay32
-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/lily58/lily58.keymap11
-rw-r--r--app/boards/shields/nibble/Kconfig.defconfig13
-rw-r--r--app/boards/shields/nibble/Kconfig.shield5
-rw-r--r--app/boards/shields/nibble/nibble.conf0
-rw-r--r--app/boards/shields/nibble/nibble.keymap37
-rw-r--r--app/boards/shields/nibble/nibble.overlay49
-rw-r--r--app/boards/shields/qaz/qaz.conf0
-rw-r--r--app/boards/shields/reviung41/Kconfig.defconfig9
-rw-r--r--app/boards/shields/reviung41/Kconfig.shield5
-rw-r--r--app/boards/shields/reviung41/boards/nice_nano.overlay28
-rw-r--r--app/boards/shields/reviung41/reviung41.conf3
-rw-r--r--app/boards/shields/reviung41/reviung41.keymap72
-rw-r--r--app/boards/shields/reviung41/reviung41.overlay52
-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/CMakeLists.txt2
-rw-r--r--app/drivers/zephyr/Kconfig6
-rw-r--r--app/drivers/zephyr/battery_voltage_divider.c215
-rw-r--r--app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml14
-rw-r--r--app/drivers/zephyr/dts/bindings/zmk,kscan-gpio-demux.yaml22
-rw-r--r--app/drivers/zephyr/kscan_gpio_demux.c254
-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/include/dt-bindings/zmk/bt.h2
-rw-r--r--app/include/dt-bindings/zmk/ext_power.h13
-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/src/behaviors/behavior_bt.c2
-rw-r--r--app/src/behaviors/behavior_ext_power.c57
-rw-r--r--app/src/behaviors/behavior_key_press.c2
-rw-r--r--app/src/ble.c146
-rw-r--r--app/src/events/ble_active_profile_changed.c2
-rw-r--r--app/src/hog.c12
-rw-r--r--app/src/kscan_mock.c2
-rw-r--r--app/src/rgb_underglow.c95
-rw-r--r--app/src/settings.c8
62 files changed, 1552 insertions, 79 deletions
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index 31d28f5..8a3971e 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -46,6 +46,7 @@ if (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_PERIPHERAL)
target_sources(app PRIVATE src/behaviors/behavior_transparent.c)
target_sources(app PRIVATE src/behaviors/behavior_none.c)
target_sources(app PRIVATE src/behaviors/behavior_sensor_rotate_key_press.c)
+ target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
target_sources(app PRIVATE src/keymap.c)
endif()
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
@@ -61,6 +62,7 @@ target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c)
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c)
target_sources(app PRIVATE src/endpoints.c)
target_sources(app PRIVATE src/hid_listener.c)
+target_sources_ifdef(CONFIG_SETTINGS app PRIVATE src/settings.c)
target_sources(app PRIVATE src/main.c)
zephyr_cc_option(-Wfatal-errors)
diff --git a/app/boards/arm/bluemicro840/Kconfig.defconfig b/app/boards/arm/bluemicro840/Kconfig.defconfig
index 566b5a4..2b55e17 100644
--- a/app/boards/arm/bluemicro840/Kconfig.defconfig
+++ b/app/boards/arm/bluemicro840/Kconfig.defconfig
@@ -27,4 +27,7 @@ config ZMK_BLE
config ZMK_USB
default y
+config ZMK_BATTERY_VOLTAGE_DIVIDER
+ default y
+
endif # BOARD_BLUEMICRO840_V1
diff --git a/app/boards/arm/bluemicro840/bluemicro840_v1.dts b/app/boards/arm/bluemicro840/bluemicro840_v1.dts
index c693662..32aa2e6 100644
--- a/app/boards/arm/bluemicro840/bluemicro840_v1.dts
+++ b/app/boards/arm/bluemicro840/bluemicro840_v1.dts
@@ -29,6 +29,18 @@
};
};
+ vbatt {
+ compatible = "zmk,battery-voltage-divider";
+ label = "VOLTAGE_DIVIDER";
+ io-channels = <&adc 7>;
+ output-ohms = <2000000>;
+ full-ohms = <(2000000 + 806000)>;
+ };
+
+};
+
+&adc {
+ status = "okay";
};
&gpio0 {
diff --git a/app/boards/arm/nice_nano/Kconfig.defconfig b/app/boards/arm/nice_nano/Kconfig.defconfig
index 0961ddd..205050a 100644
--- a/app/boards/arm/nice_nano/Kconfig.defconfig
+++ b/app/boards/arm/nice_nano/Kconfig.defconfig
@@ -25,4 +25,7 @@ config ZMK_BLE
config ZMK_USB
default y
+config ZMK_BATTERY_VOLTAGE_DIVIDER
+ default y
+
endif # BOARD_NICE_NANO
diff --git a/app/boards/arm/nice_nano/nice_nano.dts b/app/boards/arm/nice_nano/nice_nano.dts
index 0538b1d..1819541 100644
--- a/app/boards/arm/nice_nano/nice_nano.dts
+++ b/app/boards/arm/nice_nano/nice_nano.dts
@@ -34,6 +34,18 @@
label = "EXT_POWER";
control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
};
+
+ vbatt {
+ compatible = "zmk,battery-voltage-divider";
+ label = "VOLTAGE_DIVIDER";
+ io-channels = <&adc 2>;
+ output-ohms = <2000000>;
+ full-ohms = <(2000000 + 806000)>;
+ };
+};
+
+&adc {
+ status = "okay";
};
&gpiote {
diff --git a/app/boards/arm/nrfmicro/Kconfig.defconfig b/app/boards/arm/nrfmicro/Kconfig.defconfig
index 7957b4a..a3c02c2 100644
--- a/app/boards/arm/nrfmicro/Kconfig.defconfig
+++ b/app/boards/arm/nrfmicro/Kconfig.defconfig
@@ -35,6 +35,9 @@ if BOARD_NRFMICRO_13
config BOARD_NRFMICRO_CHARGER
default y
+config ZMK_BATTERY_VOLTAGE_DIVIDER
+ default y
+
endif # BOARD_NRFMICRO_13
endif # BOARD_NRFMICRO_11 || BOARD_NRFMICRO_11_FLIPPED || BOARD_NRFMICRO_13
diff --git a/app/boards/arm/nrfmicro/nrfmicro_13.dts b/app/boards/arm/nrfmicro/nrfmicro_13.dts
index ef43946..5ae11ba 100644
--- a/app/boards/arm/nrfmicro/nrfmicro_13.dts
+++ b/app/boards/arm/nrfmicro/nrfmicro_13.dts
@@ -31,6 +31,18 @@
label = "EXT_POWER";
control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
};
+
+ vbatt {
+ compatible = "zmk,battery-voltage-divider";
+ label = "VOLTAGE_DIVIDER";
+ io-channels = <&adc 2>;
+ output-ohms = <2000000>;
+ full-ohms = <(2000000 + 820000)>;
+ };
+};
+
+&adc {
+ status = "okay";
};
&gpio0 {
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/boardsource3x4/Kconfig.defconfig b/app/boards/shields/boardsource3x4/Kconfig.defconfig
new file mode 100644
index 0000000..4c55aab
--- /dev/null
+++ b/app/boards/shields/boardsource3x4/Kconfig.defconfig
@@ -0,0 +1,9 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+if SHIELD_BOARDSOURCE3X4
+
+config ZMK_KEYBOARD_NAME
+ default "Boardsource 3x4"
+
+endif \ No newline at end of file
diff --git a/app/boards/shields/boardsource3x4/Kconfig.shield b/app/boards/shields/boardsource3x4/Kconfig.shield
new file mode 100644
index 0000000..cda55d0
--- /dev/null
+++ b/app/boards/shields/boardsource3x4/Kconfig.shield
@@ -0,0 +1,6 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+config SHIELD_BOARDSOURCE3X4
+ def_bool $(shields_list_contains,boardsource3x4)
+
diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.conf b/app/boards/shields/boardsource3x4/boardsource3x4.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/boards/shields/boardsource3x4/boardsource3x4.conf
diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.keymap b/app/boards/shields/boardsource3x4/boardsource3x4.keymap
new file mode 100644
index 0000000..dfeeade
--- /dev/null
+++ b/app/boards/shields/boardsource3x4/boardsource3x4.keymap
@@ -0,0 +1,49 @@
+/*
+ * 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 = <
+ &tog 1 &cp M_PREV &cp M_PLAY &cp M_NEXT
+ &mo 2 &cp M_VOLD &kp UARW &cp M_VOLU
+ &mo 3 &kp LARW &kp DARW &kp RARW
+ >;
+
+ };
+
+ num_layer {
+ bindings = <
+ &trans &kp NUM_7 &kp NUM_8 &kp NUM_9
+ &trans &kp NUM_4 &kp NUM_5 &kp NUM_6
+ &lt 3 NUM_0 &kp NUM_1 &kp NUM_2 &kp NUM_3
+ >;
+ };
+
+ lower_layer {
+ bindings = <
+ &bt BT_CLR &none &reset &bootloader
+ &trans &bt BT_SEL 3 &bt BT_SEL 4 &none
+ &none &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2
+ >;
+ };
+
+ raise_layer {
+ bindings = <
+ &kp 0x68 &kp 0x69 &kp 0x6A &kp 0x6B
+ &kp 0x6C &kp 0x6D &kp 0x6E &kp 0x6F
+ &trans &kp 0x70 &kp 0x71 &kp 0x72
+ >;
+ };
+ };
+}; \ No newline at end of file
diff --git a/app/boards/shields/boardsource3x4/boardsource3x4.overlay b/app/boards/shields/boardsource3x4/boardsource3x4.overlay
new file mode 100644
index 0000000..ad51794
--- /dev/null
+++ b/app/boards/shields/boardsource3x4/boardsource3x4.overlay
@@ -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;
+ };
+
+ kscan0: kscan {
+ compatible = "zmk,kscan-gpio-matrix";
+ label = "KSCAN";
+ diode-direction = "col2row";
+
+ row-gpios
+ = <&pro_micro_a 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_a 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_a 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ ;
+
+ col-gpios
+ = <&pro_micro_d 10 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 16 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 14 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 15 GPIO_ACTIVE_HIGH>
+ ;
+ };
+}; \ No newline at end of file
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/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/nibble/Kconfig.defconfig b/app/boards/shields/nibble/Kconfig.defconfig
new file mode 100644
index 0000000..01d0bba
--- /dev/null
+++ b/app/boards/shields/nibble/Kconfig.defconfig
@@ -0,0 +1,13 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+if SHIELD_NIBBLE
+
+config ZMK_KEYBOARD_NAME
+ default "NIBBLE"
+
+config ZMK_USB
+ default y
+
+endif
+
diff --git a/app/boards/shields/nibble/Kconfig.shield b/app/boards/shields/nibble/Kconfig.shield
new file mode 100644
index 0000000..44364f4
--- /dev/null
+++ b/app/boards/shields/nibble/Kconfig.shield
@@ -0,0 +1,5 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+config SHIELD_NIBBLE
+ def_bool $(shields_list_contains,nibble)
diff --git a/app/boards/shields/nibble/nibble.conf b/app/boards/shields/nibble/nibble.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/boards/shields/nibble/nibble.conf
diff --git a/app/boards/shields/nibble/nibble.keymap b/app/boards/shields/nibble/nibble.keymap
new file mode 100644
index 0000000..dd37ad9
--- /dev/null
+++ b/app/boards/shields/nibble/nibble.keymap
@@ -0,0 +1,37 @@
+/*
+ * 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 FUNC 1
+
+/ {
+ keymap {
+ compatible = "zmk,keymap";
+
+ 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 HOME
+&cp M_VOLU &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 DEL
+&cp M_VOLD &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 PGUP
+&trans &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
+&trans &kp LCTL &kp LGUI &kp LALT &kp SPC &mo FUNC &kp RALT &kp RCTL &kp LARW &kp DARW &kp RARW
+ >;
+ };
+ func {
+ bindings = <
+ &kp TILD &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 &kp END
+&bt BT_CLR &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &bootloader
+&trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
+&bt BT_PRV &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans &trans
+&bt BT_NXT &trans &trans &trans &trans &trans &trans &trans &cp M_PREV &cp M_PLAY &cp M_NEXT
+ >;
+ };
+ };
+};
diff --git a/app/boards/shields/nibble/nibble.overlay b/app/boards/shields/nibble/nibble.overlay
new file mode 100644
index 0000000..7975c3c
--- /dev/null
+++ b/app/boards/shields/nibble/nibble.overlay
@@ -0,0 +1,49 @@
+/*
+ * 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-demux";
+ label = "KSCAN";
+ polling-interval-msec = <25>;
+ input-gpios
+ = <&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 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
+ ;
+ output-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>
+ ;
+ };
+
+ default_transform: keymap_transform_0 {
+ compatible = "zmk,matrix-transform";
+ columns = <16>;
+ rows = <5>;
+
+ //TODO: Add a keymap graphic here
+
+ map = <
+ RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(0,6) RC(0,7) RC(0,8) RC(0,9) RC(0,10) RC(0,11) RC(0,12) RC(0,13) RC(0,14) RC(0,15)
+RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(1,6) RC(1,7) RC(1,8) RC(1,9) RC(1,10) RC(1,11) RC(1,12) RC(1,13) RC(1,14) RC(1,15)
+RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(2,6) RC(2,7) RC(2,8) RC(2,9) RC(2,10) RC(2,11) RC(2,12) RC(2,14) RC(2,15)
+RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5) RC(3,6) RC(3,7) RC(3,8) RC(3,9) RC(3,10) RC(3,11) RC(3,12) RC(3,14) RC(3,15)
+RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,6) RC(4,9) RC(4,10) RC(4,11) RC(4,12) RC(4,14) RC(4,15)
+ >;
+ };
+};
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/reviung41/Kconfig.defconfig b/app/boards/shields/reviung41/Kconfig.defconfig
new file mode 100644
index 0000000..0625cb2
--- /dev/null
+++ b/app/boards/shields/reviung41/Kconfig.defconfig
@@ -0,0 +1,9 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+if SHIELD_REVIUNG41
+
+config ZMK_KEYBOARD_NAME
+ default "Reviung41"
+
+endif
diff --git a/app/boards/shields/reviung41/Kconfig.shield b/app/boards/shields/reviung41/Kconfig.shield
new file mode 100644
index 0000000..e51f9e6
--- /dev/null
+++ b/app/boards/shields/reviung41/Kconfig.shield
@@ -0,0 +1,5 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+config SHIELD_REVIUNG41
+ def_bool $(shields_list_contains,reviung41)
diff --git a/app/boards/shields/reviung41/boards/nice_nano.overlay b/app/boards/shields/reviung41/boards/nice_nano.overlay
new file mode 100644
index 0000000..a05d0eb
--- /dev/null
+++ b/app/boards/shields/reviung41/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 = <11>; /* arbitrary; change at will */
+ spi-one-frame = <0x70>;
+ spi-zero-frame = <0x40>;
+ };
+};
+
+/ {
+ chosen {
+ zmk,underglow = &led_strip;
+ };
+};
diff --git a/app/boards/shields/reviung41/reviung41.conf b/app/boards/shields/reviung41/reviung41.conf
new file mode 100644
index 0000000..289f070
--- /dev/null
+++ b/app/boards/shields/reviung41/reviung41.conf
@@ -0,0 +1,3 @@
+# Uncomment the following lines to enable RGB underglow
+# CONFIG_ZMK_RGB_UNDERGLOW=y
+# CONFIG_WS2812_STRIP=y
diff --git a/app/boards/shields/reviung41/reviung41.keymap b/app/boards/shields/reviung41/reviung41.keymap
new file mode 100644
index 0000000..26b4093
--- /dev/null
+++ b/app/boards/shields/reviung41/reviung41.keymap
@@ -0,0 +1,72 @@
+/*
+ * 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/rgb.h>
+
+/ {
+ keymap {
+ compatible = "zmk,keymap";
+
+ default_layer {
+// -------------------------------------------------------------------------------------
+// | TAB | Q | W | E | R | T | | Y | U | I | O | P | BKSP |
+// | CTRL | A | S | D | F | G | | H | J | K | L | ; | ' |
+// | SHFT | Z | X | C | V | B | | N | M | , | . | / | SHFT(RET) |
+// | ALT | LWR | SPC | RSE | ALT |
+ bindings = <
+ &kp TAB &kp Q &kp W &kp E &kp R &kp T &kp Y &kp U &kp I &kp O &kp P &kp BKSP
+ &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 LSFT &kp Z &kp X &kp C &kp V &kp B &kp N &kp M &kp CMMA &kp DOT &kp FSLH &mt RSFT RET
+ &kp LALT &mo 1 &kp SPC &mo 2 &kp RALT
+ >;
+ };
+
+ lower_layer {
+// ----------------------------------------------------------------------------------
+// | | ! | @ | # | $ | % | | ^ | & | * | ( | ) | DEL |
+// | | _ | + | { | } | "|" | | LFT | DWN | UP | RGT | ` | ~ |
+// | | ESC | GUI | ALT | CAPS| " | | HOME| END | PGUP| PGDN| PRSC| SHFT(RET) |
+// | | | RET | ADJ | |
+ bindings = <
+ &trans &kp BANG &kp ATSN &kp HASH &kp CURU &kp PRCT &kp CRRT &kp AMPS &kp NUM_8 &kp LPRN &kp RPRN &kp DEL
+ &trans &kp MINUS &kp KPLS &kp LCUR &kp RCUR &kp PIPE &kp LARW &kp DARW &kp UARW &kp RARW &kp GRAV &kp GRAV
+ &trans &kp ESC &kp LGUI &kp LALT &kp CLCK &kp QUOT &kp HOME &kp END &kp PGUP &kp PGDN &kp PRSC &mt RSFT RET
+ &trans &trans &kp RET &mo 3 &trans
+ >;
+ };
+
+ raise_layer {
+// -----------------------------------------------------------------------------------------
+// | | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | DEL |
+// | | - | = | [ | ] | \ | | F1 | F2 | F3 | F4 | F5 | F6 |
+// | | ESC | GUI | ALT | CAPS| " | | F7 | F8 | F9 | F10 | F11 | F12 |
+// | | ADJ | BKSP | | |
+ bindings = <
+ &trans &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 DEL
+ &trans &kp MINUS &kp EQL &kp LBKT &kp RBKT &kp BSLH &kp F1 &kp F2 &kp F3 &kp F4 &kp F5 &kp F6
+ &trans &kp ESC &kp LGUI &kp RALT &kp CLCK &kp QUOT &kp F7 &kp F8 &kp F9 &kp F10 &kp F11 &kp F12
+ &trans &mo 3 &kp BKSP &trans &trans
+ >;
+ };
+
+ adjust_layer {
+// -----------------------------------------------------------------------------------------
+// | RGB BRI+ | RGB SAT+ | RGB HUE+ | RGB ANI+ | | RGB TOG | | BT1 | BT2 | BT3 | BT4 | BT5 | BT CLR |
+// | RGB BRI- | RGB SAT- | RGB HUE- | RGB ANI+ | | | | | | | | | |
+// | | | | | | | | RESET | | | | | |
+// | | | | | |
+ bindings = <
+ &rgb_ug RGB_BRI &rgb_ug RGB_SAI &rgb_ug RGB_HUI &rgb_ug RGB_EFF &none &rgb_ug RGB_TOG &bt BT_SEL 0 &bt BT_SEL 1 &bt BT_SEL 2 &bt BT_SEL 3 &bt BT_SEL 4 &bt BT_CLR
+ &rgb_ug RGB_BRD &rgb_ug RGB_SAD &rgb_ug RGB_HUD &rgb_ug RGB_EFR &none &none &none &none &none &none &none &none
+ &none &none &none &none &none &none &reset &none &none &none &none &none
+ &trans &trans &tog 3 &trans &trans
+ >;
+ };
+ };
+};
diff --git a/app/boards/shields/reviung41/reviung41.overlay b/app/boards/shields/reviung41/reviung41.overlay
new file mode 100644
index 0000000..06270ca
--- /dev/null
+++ b/app/boards/shields/reviung41/reviung41.overlay
@@ -0,0 +1,52 @@
+/*
+ * 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 = <6>;
+ rows = <7>;
+
+ map = <
+RC(0,0) RC(0,1) RC(0,2) RC(0,3) RC(0,4) RC(0,5) RC(3,0) RC(3,1) RC(3,2) RC(3,3) RC(3,4) RC(3,5)
+RC(1,0) RC(1,1) RC(1,2) RC(1,3) RC(1,4) RC(1,5) RC(4,0) RC(4,1) RC(4,2) RC(4,3) RC(4,4) RC(4,5)
+RC(2,0) RC(2,1) RC(2,2) RC(2,3) RC(2,4) RC(2,5) RC(5,0) RC(5,1) RC(5,2) RC(5,3) RC(5,4) RC(5,5)
+ RC(6,0) RC(6,1) RC(6,2) RC(6,3) RC(6,4)
+ >;
+ };
+
+ kscan0: kscan_0 {
+ compatible = "zmk,kscan-gpio-matrix";
+ label = "KSCAN";
+ diode-direction = "col2row";
+
+ col-gpios
+ = <&pro_micro_d 4 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 5 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 6 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 7 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 8 GPIO_ACTIVE_HIGH>
+ , <&pro_micro_d 9 GPIO_ACTIVE_HIGH>
+ ;
+
+ row-gpios
+ = <&pro_micro_a 3 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_a 2 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_a 1 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_a 0 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_d 15 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_d 14 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ , <&pro_micro_d 16 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>
+ ;
+ };
+};
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/CMakeLists.txt b/app/drivers/zephyr/CMakeLists.txt
index 8778ded..e3a192d 100644
--- a/app/drivers/zephyr/CMakeLists.txt
+++ b/app/drivers/zephyr/CMakeLists.txt
@@ -5,8 +5,10 @@ if(CONFIG_ZMK_KSCAN_GPIO_DRIVER)
zephyr_library_sources(
kscan_gpio_matrix.c
kscan_gpio_direct.c
+ kscan_gpio_demux.c
)
zephyr_library_sources_ifdef(CONFIG_EC11 ec11.c)
zephyr_library_sources_ifdef(CONFIG_EC11_TRIGGER ec11_trigger.c)
+ zephyr_library_sources_ifdef(CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER battery_voltage_divider.c)
endif()
diff --git a/app/drivers/zephyr/Kconfig b/app/drivers/zephyr/Kconfig
index 0534cab..6b177fb 100644
--- a/app/drivers/zephyr/Kconfig
+++ b/app/drivers/zephyr/Kconfig
@@ -21,6 +21,12 @@ config ZMK_KSCAN_INIT_PRIORITY
help
Keyboard scan device driver initialization priority.
+config ZMK_BATTERY_VOLTAGE_DIVIDER
+ bool "ZMK battery voltage divider"
+ select ADC
+ help
+ Enable ZMK battery voltage divider driver for battery monitoring.
+
menuconfig EC11
bool "EC11 Incremental Encoder Sensor"
depends on GPIO
diff --git a/app/drivers/zephyr/battery_voltage_divider.c b/app/drivers/zephyr/battery_voltage_divider.c
new file mode 100644
index 0000000..37ac024
--- /dev/null
+++ b/app/drivers/zephyr/battery_voltage_divider.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define DT_DRV_COMPAT zmk_battery_voltage_divider
+
+#include <device.h>
+#include <drivers/gpio.h>
+#include <drivers/adc.h>
+#include <drivers/sensor.h>
+#include <logging/log.h>
+
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+struct io_channel_config {
+ const char *label;
+ uint8_t channel;
+};
+
+struct gpio_channel_config {
+ const char *label;
+ uint8_t pin;
+ uint8_t flags;
+};
+
+struct bvd_config {
+ struct io_channel_config io_channel;
+ struct gpio_channel_config power_gpios;
+ uint32_t output_ohm;
+ uint32_t full_ohm;
+};
+
+struct bvd_data {
+ struct device *adc;
+ struct device *gpio;
+ struct adc_channel_cfg acc;
+ struct adc_sequence as;
+ uint16_t adc_raw;
+ uint16_t voltage;
+ uint8_t state_of_charge;
+};
+
+static uint8_t lithium_ion_mv_to_pct(int16_t bat_mv) {
+ // Simple linear approximation of a battery based off adafruit's discharge graph:
+ // https://learn.adafruit.com/li-ion-and-lipoly-batteries/voltages
+
+ if (bat_mv >= 4200) {
+ return 100;
+ } else if (bat_mv <= 3450) {
+ return 0;
+ }
+
+ return bat_mv * 2 / 15 - 459;
+}
+
+static int bvd_sample_fetch(struct device *dev, enum sensor_channel chan) {
+ struct bvd_data *drv_data = dev->driver_data;
+ const struct bvd_config *drv_cfg = dev->config_info;
+ struct adc_sequence *as = &drv_data->as;
+
+ // Make sure selected channel is supported
+ if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE) {
+ return -ENOTSUP;
+ }
+
+ int rc = 0;
+
+ // Enable power GPIO if present
+ if (drv_data->gpio) {
+ rc = gpio_pin_set(drv_data->gpio, drv_cfg->power_gpios.pin, 1);
+
+ if (rc != 0) {
+ LOG_DBG("Failed to enable ADC power GPIO: %d", rc);
+ return rc;
+ }
+ }
+
+ // Read ADC
+ rc = adc_read(drv_data->adc, as);
+ as->calibrate = false;
+
+ if (rc == 0) {
+ int32_t val = drv_data->adc_raw;
+
+ adc_raw_to_millivolts(adc_ref_internal(drv_data->adc), drv_data->acc.gain, as->resolution,
+ &val);
+
+ uint16_t millivolts = val * (uint64_t)drv_cfg->full_ohm / drv_cfg->output_ohm;
+ LOG_DBG("ADC raw %d ~ %d mV => %d mV\n", drv_data->adc_raw, val, millivolts);
+ uint8_t percent = lithium_ion_mv_to_pct(millivolts);
+ LOG_DBG("Percent: %d", percent);
+
+ drv_data->voltage = millivolts;
+ drv_data->state_of_charge = percent;
+ } else {
+ LOG_DBG("Failed to read ADC: %d", rc);
+ }
+
+ // Disable power GPIO if present
+ if (drv_data->gpio) {
+ int rc2 = gpio_pin_set(drv_data->gpio, drv_cfg->power_gpios.pin, 0);
+
+ if (rc2 != 0) {
+ LOG_DBG("Failed to disable ADC power GPIO: %d", rc2);
+ return rc2;
+ }
+ }
+
+ return rc;
+}
+
+static int bvd_channel_get(struct device *dev, enum sensor_channel chan, struct sensor_value *val) {
+ struct bvd_data *drv_data = dev->driver_data;
+
+ switch (chan) {
+ case SENSOR_CHAN_GAUGE_VOLTAGE:
+ val->val1 = drv_data->voltage / 1000;
+ val->val2 = (drv_data->voltage % 1000) * 1000U;
+ break;
+
+ case SENSOR_CHAN_GAUGE_STATE_OF_CHARGE:
+ val->val1 = drv_data->state_of_charge;
+ val->val2 = 0;
+ break;
+
+ default:
+ return -ENOTSUP;
+ }
+
+ return 0;
+}
+
+static const struct sensor_driver_api bvd_api = {
+ .sample_fetch = bvd_sample_fetch,
+ .channel_get = bvd_channel_get,
+};
+
+static int bvd_init(struct device *dev) {
+ struct bvd_data *drv_data = dev->driver_data;
+ const struct bvd_config *drv_cfg = dev->config_info;
+
+ drv_data->adc = device_get_binding(drv_cfg->io_channel.label);
+
+ if (drv_data->adc == NULL) {
+ LOG_ERR("ADC %s failed to retrieve", drv_cfg->io_channel.label);
+ return -ENODEV;
+ }
+
+ int rc = 0;
+
+ if (drv_cfg->power_gpios.label) {
+ drv_data->gpio = device_get_binding(drv_cfg->power_gpios.label);
+ if (drv_data->gpio == NULL) {
+ LOG_ERR("Failed to get GPIO %s", drv_cfg->power_gpios.label);
+ return -ENODEV;
+ }
+ rc = gpio_pin_configure(drv_data->gpio, drv_cfg->power_gpios.pin,
+ GPIO_OUTPUT_INACTIVE | drv_cfg->power_gpios.flags);
+ if (rc != 0) {
+ LOG_ERR("Failed to control feed %s.%u: %d", drv_cfg->power_gpios.label,
+ drv_cfg->power_gpios.pin, rc);
+ return rc;
+ }
+ }
+
+ drv_data->as = (struct adc_sequence){
+ .channels = BIT(0),
+ .buffer = &drv_data->adc_raw,
+ .buffer_size = sizeof(drv_data->adc_raw),
+ .oversampling = 4,
+ .calibrate = true,
+ };
+
+#ifdef CONFIG_ADC_NRFX_SAADC
+ drv_data->acc = (struct adc_channel_cfg){
+ .gain = ADC_GAIN_1_5,
+ .reference = ADC_REF_INTERNAL,
+ .acquisition_time = ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 40),
+ .input_positive = SAADC_CH_PSELP_PSELP_AnalogInput0 + drv_cfg->io_channel.channel,
+ };
+
+ drv_data->as.resolution = 12;
+#else
+#error Unsupported ADC
+#endif
+
+ rc = adc_channel_setup(drv_data->adc, &drv_data->acc);
+ LOG_DBG("AIN%u setup returned %d", drv_cfg->io_channel.channel, rc);
+
+ return rc;
+}
+
+static struct bvd_data bvd_data;
+static const struct bvd_config bvd_cfg = {
+ .io_channel =
+ {
+ DT_INST_IO_CHANNELS_LABEL(0),
+ DT_INST_IO_CHANNELS_INPUT(0),
+ },
+#if DT_INST_NODE_HAS_PROP(0, power_gpios)
+ .power_gpios =
+ {
+ DT_INST_GPIO_LABEL(0, power_gpios),
+ DT_INST_PIN(0, power_gpios),
+ DT_INST_FLAGS(0, power_gpios),
+ },
+#endif
+ .output_ohm = DT_INST_PROP(0, output_ohms),
+ .full_ohm = DT_INST_PROP(0, full_ohms),
+};
+
+DEVICE_AND_API_INIT(bvd_dev, DT_INST_LABEL(0), &bvd_init, &bvd_data, &bvd_cfg, POST_KERNEL,
+ CONFIG_SENSOR_INIT_PRIORITY, &bvd_api);
diff --git a/app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml b/app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml
new file mode 100644
index 0000000..3f391d7
--- /dev/null
+++ b/app/drivers/zephyr/dts/bindings/zmk,battery-voltage-divider.yaml
@@ -0,0 +1,14 @@
+# Copyright (c) 2020 The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+description: Battery SoC monitoring using voltage divider
+
+compatible: "zmk,battery-voltage-divider"
+
+include: voltage-divider.yaml
+
+properties:
+ label:
+ required: true
+ type: string
+ \ No newline at end of file
diff --git a/app/drivers/zephyr/dts/bindings/zmk,kscan-gpio-demux.yaml b/app/drivers/zephyr/dts/bindings/zmk,kscan-gpio-demux.yaml
new file mode 100644
index 0000000..a2d8d24
--- /dev/null
+++ b/app/drivers/zephyr/dts/bindings/zmk,kscan-gpio-demux.yaml
@@ -0,0 +1,22 @@
+# Copyright (c) 2020, The ZMK Contributors
+# SPDX-License-Identifier: MIT
+
+description: GPIO keyboard demux controller
+
+compatible: "zmk,kscan-gpio-demux"
+
+include: kscan.yaml
+
+properties:
+ input-gpios:
+ type: phandle-array
+ required: true
+ output-gpios:
+ type: phandle-array
+ required: true
+ debounce-period:
+ type: int
+ default: 5
+ polling-interval-msec:
+ type: int
+ default: 25
diff --git a/app/drivers/zephyr/kscan_gpio_demux.c b/app/drivers/zephyr/kscan_gpio_demux.c
new file mode 100644
index 0000000..6113d7c
--- /dev/null
+++ b/app/drivers/zephyr/kscan_gpio_demux.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2020 The ZMK Contributors
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define DT_DRV_COMPAT zmk_kscan_gpio_demux
+
+#include <device.h>
+#include <drivers/kscan.h>
+#include <drivers/gpio.h>
+#include <logging/log.h>
+
+LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
+
+#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
+
+struct kscan_gpio_item_config {
+ char *label;
+ gpio_pin_t pin;
+ gpio_flags_t flags;
+};
+
+// Helper macro
+#define PWR_TWO(x) (1 << (x))
+
+// Define GPIO cfg
+#define _KSCAN_GPIO_ITEM_CFG_INIT(n, prop, idx) \
+ { \
+ .label = DT_INST_GPIO_LABEL_BY_IDX(n, prop, idx), \
+ .pin = DT_INST_GPIO_PIN_BY_IDX(n, prop, idx), \
+ .flags = DT_INST_GPIO_FLAGS_BY_IDX(n, prop, idx), \
+ },
+
+// Define row and col cfg
+#define _KSCAN_GPIO_INPUT_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, input_gpios, idx)
+#define _KSCAN_GPIO_OUTPUT_CFG_INIT(idx, n) _KSCAN_GPIO_ITEM_CFG_INIT(n, output_gpios, idx)
+
+// Check debounce config
+#define CHECK_DEBOUNCE_CFG(n, a, b) COND_CODE_0(DT_INST_PROP(n, debounce_period), a, b)
+
+// Define the row and column lengths
+#define INST_MATRIX_INPUTS(n) DT_INST_PROP_LEN(n, input_gpios)
+#define INST_DEMUX_GPIOS(n) DT_INST_PROP_LEN(n, output_gpios)
+#define INST_MATRIX_OUTPUTS(n) PWR_TWO(INST_DEMUX_GPIOS(n))
+#define POLL_INTERVAL(n) DT_INST_PROP(n, polling_interval_msec)
+
+#define GPIO_INST_INIT(n) \
+ struct kscan_gpio_irq_callback_##n { \
+ struct CHECK_DEBOUNCE_CFG(n, (k_work), (k_delayed_work)) * work; \
+ struct gpio_callback callback; \
+ struct device *dev; \
+ }; \
+ \
+ struct kscan_gpio_config_##n { \
+ struct kscan_gpio_item_config rows[INST_MATRIX_INPUTS(n)]; \
+ struct kscan_gpio_item_config cols[INST_DEMUX_GPIOS(n)]; \
+ }; \
+ \
+ struct kscan_gpio_data_##n { \
+ kscan_callback_t callback; \
+ struct k_timer poll_timer; \
+ struct CHECK_DEBOUNCE_CFG(n, (k_work), (k_delayed_work)) work; \
+ bool matrix_state[INST_MATRIX_INPUTS(n)][INST_MATRIX_OUTPUTS(n)]; \
+ struct device *rows[INST_MATRIX_INPUTS(n)]; \
+ struct device *cols[INST_MATRIX_OUTPUTS(n)]; \
+ struct device *dev; \
+ }; \
+ /* IO/GPIO SETUP */ \
+ /* gpio_input_devices are PHYSICAL IO devices */ \
+ static struct device **kscan_gpio_input_devices_##n(struct device *dev) { \
+ struct kscan_gpio_data_##n *data = dev->driver_data; \
+ return data->rows; \
+ } \
+ \
+ static const struct kscan_gpio_item_config *kscan_gpio_input_configs_##n(struct device *dev) { \
+ const struct kscan_gpio_config_##n *cfg = dev->config_info; \
+ return cfg->rows; \
+ } \
+ \
+ /* gpio_output_devices are PHYSICAL IO devices */ \
+ static struct device **kscan_gpio_output_devices_##n(struct device *dev) { \
+ struct kscan_gpio_data_##n *data = dev->driver_data; \
+ return data->cols; \
+ } \
+ \
+ static const struct kscan_gpio_item_config *kscan_gpio_output_configs_##n( \
+ struct device *dev) { \
+ const struct kscan_gpio_config_##n *cfg = dev->config_info; \
+ /* If row2col, rows = outputs & cols = inputs */ \
+ return cfg->cols; \
+ } \
+ /* POLLING SETUP */ \
+ 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); \
+ } \
+ \
+ /* Read the state of the input GPIOs */ \
+ /* This is the core matrix_scan func */ \
+ static int kscan_gpio_read_##n(struct device *dev) { \
+ bool submit_follow_up_read = false; \
+ struct kscan_gpio_data_##n *data = dev->driver_data; \
+ static bool read_state[INST_MATRIX_INPUTS(n)][INST_MATRIX_OUTPUTS(n)]; \
+ for (int o = 0; o < INST_MATRIX_OUTPUTS(n); o++) { \
+ /* Iterate over bits and set GPIOs accordingly */ \
+ for (u8_t bit = 0; bit < INST_DEMUX_GPIOS(n); bit++) { \
+ u8_t state = (o & (0b1 << bit)) >> bit; \
+ struct device *out_dev = kscan_gpio_output_devices_##n(dev)[bit]; \
+ const struct kscan_gpio_item_config *out_cfg = \
+ &kscan_gpio_output_configs_##n(dev)[bit]; \
+ gpio_pin_set(out_dev, out_cfg->pin, state); \
+ } \
+ \
+ for (int i = 0; i < INST_MATRIX_INPUTS(n); i++) { \
+ /* Get the input device (port) */ \
+ struct device *in_dev = kscan_gpio_input_devices_##n(dev)[i]; \
+ /* Get the input device config (pin) */ \
+ const struct kscan_gpio_item_config *in_cfg = \
+ &kscan_gpio_input_configs_##n(dev)[i]; \
+ read_state[i][o] = gpio_pin_get(in_dev, in_cfg->pin) > 0; \
+ } \
+ } \
+ for (int r = 0; r < INST_MATRIX_INPUTS(n); r++) { \
+ for (int c = 0; c < INST_MATRIX_OUTPUTS(n); c++) { \
+ bool pressed = read_state[r][c]; \
+ submit_follow_up_read = (submit_follow_up_read || pressed); \
+ if (pressed != data->matrix_state[r][c]) { \
+ LOG_DBG("Sending event at %d,%d state %s", r, c, (pressed ? "on" : "off")); \
+ data->matrix_state[r][c] = pressed; \
+ data->callback(dev, r, c, pressed); \
+ } \
+ } \
+ } \
+ if (submit_follow_up_read) { \
+ CHECK_DEBOUNCE_CFG(n, ({ k_work_submit(&data->work); }), ({ \
+ k_delayed_work_cancel(&data->work); \
+ k_delayed_work_submit(&data->work, K_MSEC(5)); \
+ })) \
+ } \
+ return 0; \
+ } \
+ \
+ static void kscan_gpio_work_handler_##n(struct k_work *work) { \
+ struct kscan_gpio_data_##n *data = CONTAINER_OF(work, struct kscan_gpio_data_##n, work); \
+ kscan_gpio_read_##n(data->dev); \
+ } \
+ \
+ static struct kscan_gpio_data_##n kscan_gpio_data_##n = { \
+ .rows = {[INST_MATRIX_INPUTS(n) - 1] = NULL}, .cols = {[INST_DEMUX_GPIOS(n) - 1] = NULL}}; \
+ \
+ /* KSCAN API configure function */ \
+ static int kscan_gpio_configure_##n(struct device *dev, kscan_callback_t callback) { \
+ LOG_DBG("KSCAN API configure"); \
+ struct kscan_gpio_data_##n *data = dev->driver_data; \
+ if (!callback) { \
+ return -EINVAL; \
+ } \
+ data->callback = callback; \
+ LOG_DBG("Configured GPIO %d", n); \
+ return 0; \
+ }; \
+ \
+ /* KSCAN API enable function */ \
+ static int kscan_gpio_enable_##n(struct device *dev) { \
+ LOG_DBG("KSCAN API enable"); \
+ struct kscan_gpio_data_##n *data = dev->driver_data; \
+ /* TODO: we might want a follow up to hook into the sleep state hooks in Zephyr, */ \
+ /* and disable this timer when we enter a sleep state */ \
+ k_timer_start(&data->poll_timer, K_MSEC(POLL_INTERVAL(n)), K_MSEC(POLL_INTERVAL(n))); \
+ return 0; \
+ }; \
+ \
+ /* KSCAN API disable function */ \
+ static int kscan_gpio_disable_##n(struct device *dev) { \
+ LOG_DBG("KSCAN API disable"); \
+ struct kscan_gpio_data_##n *data = dev->driver_data; \
+ k_timer_stop(&data->poll_timer); \
+ return 0; \
+ }; \
+ \
+ /* GPIO init function*/ \
+ static int kscan_gpio_init_##n(struct device *dev) { \
+ LOG_DBG("KSCAN GPIO init"); \
+ struct kscan_gpio_data_##n *data = dev->driver_data; \
+ int err; \
+ /* configure input devices*/ \
+ struct device **input_devices = kscan_gpio_input_devices_##n(dev); \
+ for (int i = 0; i < INST_MATRIX_INPUTS(n); i++) { \
+ const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs_##n(dev)[i]; \
+ input_devices[i] = device_get_binding(in_cfg->label); \
+ if (!input_devices[i]) { \
+ LOG_ERR("Unable to find input GPIO device"); \
+ return -EINVAL; \
+ } \
+ err = gpio_pin_configure(input_devices[i], in_cfg->pin, GPIO_INPUT | in_cfg->flags); \
+ if (err) { \
+ LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \
+ return err; \
+ } else { \
+ LOG_DBG("Configured pin %d on %s for input", in_cfg->pin, in_cfg->label); \
+ } \
+ if (err) { \
+ LOG_ERR("Error adding the callback to the column device"); \
+ return err; \
+ } \
+ } \
+ /* configure output devices*/ \
+ struct device **output_devices = kscan_gpio_output_devices_##n(dev); \
+ for (int o = 0; o < INST_DEMUX_GPIOS(n); o++) { \
+ const struct kscan_gpio_item_config *out_cfg = &kscan_gpio_output_configs_##n(dev)[o]; \
+ output_devices[o] = device_get_binding(out_cfg->label); \
+ if (!output_devices[o]) { \
+ LOG_ERR("Unable to find output GPIO device"); \
+ return -EINVAL; \
+ } \
+ err = gpio_pin_configure(output_devices[o], out_cfg->pin, \
+ GPIO_OUTPUT_ACTIVE | out_cfg->flags); \
+ if (err) { \
+ LOG_ERR("Unable to configure pin %d on %s for output", out_cfg->pin, \
+ out_cfg->label); \
+ return err; \
+ } else { \
+ LOG_DBG("Configured pin %d on %s for output", out_cfg->pin, out_cfg->label); \
+ } \
+ } \
+ data->dev = dev; \
+ \
+ k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL); \
+ \
+ (CHECK_DEBOUNCE_CFG(n, (k_work_init), (k_delayed_work_init)))( \
+ &data->work, kscan_gpio_work_handler_##n); \
+ return 0; \
+ } \
+ \
+ static const struct kscan_driver_api gpio_driver_api_##n = { \
+ .config = kscan_gpio_configure_##n, \
+ .enable_callback = kscan_gpio_enable_##n, \
+ .disable_callback = kscan_gpio_disable_##n, \
+ }; \
+ \
+ static const struct kscan_gpio_config_##n kscan_gpio_config_##n = { \
+ .rows = {UTIL_LISTIFY(INST_MATRIX_INPUTS(n), _KSCAN_GPIO_INPUT_CFG_INIT, n)}, \
+ .cols = {UTIL_LISTIFY(INST_DEMUX_GPIOS(n), _KSCAN_GPIO_OUTPUT_CFG_INIT, n)}, \
+ }; \
+ \
+ DEVICE_AND_API_INIT(kscan_gpio_##n, DT_INST_LABEL(n), kscan_gpio_init_##n, \
+ &kscan_gpio_data_##n, &kscan_gpio_config_##n, APPLICATION, \
+ CONFIG_APPLICATION_INIT_PRIORITY, &gpio_driver_api_##n);
+
+DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT)
+
+#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 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/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/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/src/behaviors/behavior_bt.c b/app/src/behaviors/behavior_bt.c
index 922c157..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
*/
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_key_press.c b/app/src/behaviors/behavior_key_press.c
index d691e9f..923b098 100644
--- a/app/src/behaviors/behavior_key_press.c
+++ b/app/src/behaviors/behavior_key_press.c
@@ -54,4 +54,4 @@ static const struct behavior_driver_api behavior_key_press_driver_api = {
&behavior_key_press_data_##n, &behavior_key_press_config_##n, APPLICATION, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_press_driver_api);
-DT_INST_FOREACH_STATUS_OKAY(KP_INST) \ No newline at end of file
+DT_INST_FOREACH_STATUS_OKAY(KP_INST)
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/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/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/kscan_mock.c b/app/src/kscan_mock.c
index e9c15a0..f1614f1 100644
--- a/app/src/kscan_mock.c
+++ b/app/src/kscan_mock.c
@@ -18,7 +18,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct kscan_mock_data {
kscan_callback_t callback;
- u8_t event_index;
+ u32_t event_index;
struct k_delayed_work work;
struct device *dev;
};
diff --git a/app/src/rgb_underglow.c b/app/src/rgb_underglow.c
index 13912e3..b371c94 100644
--- a/app/src/rgb_underglow.c
+++ b/app/src/rgb_underglow.c
@@ -7,6 +7,7 @@
#include <device.h>
#include <init.h>
#include <kernel.h>
+#include <settings/settings.h>
#include <math.h>
#include <stdlib.h>
@@ -14,7 +15,6 @@
#include <logging/log.h>
#include <drivers/led_strip.h>
-#include <device.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
@@ -45,12 +45,36 @@ struct rgb_underglow_state {
bool on;
};
-struct rgb_underglow_state state;
-
struct device *led_strip;
struct led_rgb pixels[STRIP_NUM_PIXELS];
+struct rgb_underglow_state state;
+
+#if IS_ENABLED(CONFIG_SETTINGS)
+static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
+ const char *next;
+ int rc;
+
+ if (settings_name_steq(name, "state", &next) && !next) {
+ if (len != sizeof(state)) {
+ return -EINVAL;
+ }
+
+ rc = read_cb(cb_arg, &state, sizeof(state));
+ if (rc >= 0) {
+ return 0;
+ }
+
+ return rc;
+ }
+
+ return -ENOENT;
+}
+
+struct settings_handler rgb_conf = {.name = "rgb/underglow", .h_set = rgb_settings_set};
+#endif
+
static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
double r, g, b;
@@ -100,6 +124,14 @@ static struct led_rgb hsb_to_rgb(struct led_hsb hsb) {
return rgb;
}
+static void zmk_rgb_underglow_off() {
+ for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
+ pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
+ }
+
+ led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
+}
+
static void zmk_rgb_underglow_effect_solid() {
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
int hue = state.hue;
@@ -182,6 +214,14 @@ static void zmk_rgb_underglow_tick(struct k_work *work) {
K_WORK_DEFINE(underglow_work, zmk_rgb_underglow_tick);
static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) {
+ if (!state.on) {
+ zmk_rgb_underglow_off();
+
+ k_timer_stop(timer);
+
+ return;
+ }
+
k_work_submit(&underglow_work);
}
@@ -197,20 +237,32 @@ static int zmk_rgb_underglow_init(struct device *_arg) {
}
state = (struct rgb_underglow_state){
- hue : 0,
- saturation : 100,
- brightness : 100,
- animation_speed : 3,
- current_effect : 0,
+ hue : CONFIG_ZMK_RGB_UNDERGLOW_HUE_START,
+ saturation : CONFIG_ZMK_RGB_UNDERGLOW_SAT_START,
+ brightness : CONFIG_ZMK_RGB_UNDERGLOW_BRT_START,
+ animation_speed : CONFIG_ZMK_RGB_UNDERGLOW_SPD_START,
+ current_effect : CONFIG_ZMK_RGB_UNDERGLOW_EFF_START,
animation_step : 0,
- on : true
+ on : IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_ON_START)
};
+#if IS_ENABLED(CONFIG_SETTINGS)
+ settings_register(&rgb_conf);
+#endif
+
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
return 0;
}
+int zmk_rgb_underglow_save_state() {
+#if IS_ENABLED(CONFIG_SETTINGS)
+ return settings_save_one("rgb/underglow/state", &state, sizeof(state));
+#else
+ return 0;
+#endif
+}
+
int zmk_rgb_underglow_cycle_effect(int direction) {
if (!led_strip)
return -ENODEV;
@@ -228,7 +280,7 @@ int zmk_rgb_underglow_cycle_effect(int direction) {
state.animation_step = 0;
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_toggle() {
@@ -241,17 +293,12 @@ int zmk_rgb_underglow_toggle() {
state.animation_step = 0;
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
} else {
-
- for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
- pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
- }
-
- led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
+ zmk_rgb_underglow_off();
k_timer_stop(&underglow_tick);
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_hue(int direction) {
@@ -259,17 +306,15 @@ int zmk_rgb_underglow_change_hue(int direction) {
return -ENODEV;
if (state.hue == 0 && direction < 0) {
- state.hue = 350;
+ state.hue = 360 - CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
return 0;
}
state.hue += direction * CONFIG_ZMK_RGB_UNDERGLOW_HUE_STEP;
- if (state.hue > 350) {
- state.hue = 0;
- }
+ state.hue = state.hue % 360;
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_sat(int direction) {
@@ -286,7 +331,7 @@ int zmk_rgb_underglow_change_sat(int direction) {
state.saturation = 100;
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_brt(int direction) {
@@ -303,7 +348,7 @@ int zmk_rgb_underglow_change_brt(int direction) {
state.brightness = 100;
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
int zmk_rgb_underglow_change_spd(int direction) {
@@ -320,7 +365,7 @@ int zmk_rgb_underglow_change_spd(int direction) {
state.animation_speed = 5;
}
- return 0;
+ return zmk_rgb_underglow_save_state();
}
SYS_INIT(zmk_rgb_underglow_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
diff --git a/app/src/settings.c b/app/src/settings.c
new file mode 100644
index 0000000..8914ccc
--- /dev/null
+++ b/app/src/settings.c
@@ -0,0 +1,8 @@
+#include <device.h>
+#include <init.h>
+#include <kernel.h>
+#include <settings/settings.h>
+
+static int zmk_settings_init(struct device *_arg) { return settings_load(); }
+
+SYS_INIT(zmk_settings_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);