Merge branch 'main' of github.com:zmkfirmware/zmk into pillbug
This commit is contained in:
commit
f8dab7b530
169 changed files with 20967 additions and 5420 deletions
22
.github/workflows/build-user-config.yml
vendored
22
.github/workflows/build-user-config.yml
vendored
|
@ -18,6 +18,11 @@ on:
|
|||
default: "bin"
|
||||
required: false
|
||||
type: string
|
||||
artifact_name:
|
||||
description: 'Artifact output file name'
|
||||
default: 'firmware'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
matrix:
|
||||
|
@ -32,9 +37,10 @@ jobs:
|
|||
- name: Install yaml2json
|
||||
run: python3 -m pip install remarshal
|
||||
|
||||
- id: set-matrix
|
||||
name: Fetch Build Matrix
|
||||
- name: Fetch Build Matrix
|
||||
id: set-matrix
|
||||
run: |
|
||||
set -x
|
||||
matrix=$(yaml2json ${{ inputs.build_matrix_path }} | jq -c .)
|
||||
yaml2json ${{ inputs.build_matrix_path }}
|
||||
echo "::set-output name=matrix::${matrix}"
|
||||
|
@ -52,7 +58,9 @@ jobs:
|
|||
- name: Prepare variables
|
||||
id: variables
|
||||
run: |
|
||||
if [ -n "${{ matrix.shield }}" ]; then
|
||||
set -x
|
||||
if [ -n "${{ matrix.shield }}" ]
|
||||
then
|
||||
EXTRA_CMAKE_ARGS="-DSHIELD=${{ matrix.shield }}"
|
||||
ARTIFACT_NAME="${{ matrix.shield }}-${{ matrix.board }}-zmk"
|
||||
DISPLAY_NAME="${{ matrix.shield }} - ${{ matrix.board }}"
|
||||
|
@ -70,7 +78,7 @@ jobs:
|
|||
uses: actions/checkout@v2
|
||||
|
||||
- name: Cache west modules
|
||||
uses: actions/cache@v3.0.1
|
||||
uses: actions/cache@v3.0.2
|
||||
continue-on-error: true
|
||||
env:
|
||||
cache-name: cache-zephyr-${{ steps.variables.outputs.zephyr-version }}-modules
|
||||
|
@ -98,13 +106,15 @@ jobs:
|
|||
|
||||
- name: West Build (${{ steps.variables.outputs.display-name }})
|
||||
run: |
|
||||
set -x
|
||||
west build -s zmk/app -b ${{ matrix.board }} -- -DZMK_CONFIG=${GITHUB_WORKSPACE}/${{ inputs.config_path }} ${{ steps.variables.outputs.extra-cmake-args }} ${{ matrix.cmake-args }}
|
||||
|
||||
- name: ${{ steps.variables.outputs.display-name }} Kconfig file
|
||||
run: cat build/zephyr/.config | grep -v "^#" | grep -v "^$" | sort
|
||||
run: grep -v -e "^#" -e "^$" build/zephyr/.config | sort
|
||||
|
||||
- name: Rename artifacts
|
||||
run: |
|
||||
set -x
|
||||
mkdir build/artifacts
|
||||
if [ -f build/zephyr/zmk.uf2 ]
|
||||
then
|
||||
|
@ -117,5 +127,5 @@ jobs:
|
|||
- name: Archive (${{ steps.variables.outputs.display-name }})
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: firmware
|
||||
name: ${{ inputs.artifact_name }}
|
||||
path: build/artifacts
|
||||
|
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache west modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3.0.2
|
||||
env:
|
||||
cache-name: cache-zephyr-modules
|
||||
with:
|
||||
|
|
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
|
@ -38,7 +38,7 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache west modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3.0.2
|
||||
env:
|
||||
cache-name: cache-zephyr-modules
|
||||
with:
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
cmake_minimum_required(VERSION 3.13.1)
|
||||
|
||||
set(CONFIG_APPLICATION_DEFINED_SYSCALL true)
|
||||
list(APPEND BOARD_ROOT ${CMAKE_SOURCE_DIR})
|
||||
list(APPEND DTS_ROOT ${CMAKE_SOURCE_DIR})
|
||||
|
||||
# Add our custom Zephyr module for drivers w/ syscalls, etc.
|
||||
list(APPEND DTS_ROOT ${CMAKE_SOURCE_DIR}/drivers/zephyr)
|
||||
|
||||
set(ZephyrBuildConfiguration_ROOT ${CMAKE_SOURCE_DIR}/cmake)
|
||||
|
||||
list(APPEND ZEPHYR_EXTRA_MODULES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drivers
|
||||
)
|
||||
|
||||
include(cmake/zmk_config.cmake)
|
||||
|
||||
# Find Zephyr. This also loads Zephyr's build system.
|
||||
find_package(Zephyr REQUIRED HINTS ../zephyr)
|
||||
project(zmk)
|
||||
|
@ -26,26 +24,21 @@ target_sources(app PRIVATE src/stdlib.c)
|
|||
target_sources(app PRIVATE src/activity.c)
|
||||
target_sources(app PRIVATE src/kscan.c)
|
||||
target_sources(app PRIVATE src/matrix_transform.c)
|
||||
target_sources(app PRIVATE src/hid.c)
|
||||
target_sources(app PRIVATE src/sensors.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/wpm.c)
|
||||
target_sources(app PRIVATE src/event_manager.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c)
|
||||
target_sources(app PRIVATE src/events/activity_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/position_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/layer_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/keycode_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/modifiers_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/endpoint_selection_changed.c)
|
||||
target_sources(app PRIVATE src/events/sensor_event.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WPM app PRIVATE src/events/wpm_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/events/usb_conn_state_changed.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_reset.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/behaviors/behavior_ext_power.c)
|
||||
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
||||
if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE src/hid.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_key_press.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BEHAVIOR_KEY_TOGGLE app PRIVATE src/behaviors/behavior_key_toggle.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_hold_tap.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_sticky_key.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_caps_word.c)
|
||||
|
@ -63,27 +56,35 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
|||
target_sources(app PRIVATE src/combo.c)
|
||||
target_sources(app PRIVATE src/behavior_queue.c)
|
||||
target_sources(app PRIVATE src/conditional_layer.c)
|
||||
target_sources(app PRIVATE src/endpoints.c)
|
||||
target_sources(app PRIVATE src/events/endpoint_selection_changed.c)
|
||||
target_sources(app PRIVATE src/hid_listener.c)
|
||||
target_sources(app PRIVATE src/keymap.c)
|
||||
target_sources(app PRIVATE src/events/layer_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/modifiers_state_changed.c)
|
||||
target_sources(app PRIVATE src/events/keycode_state_changed.c)
|
||||
|
||||
if (CONFIG_ZMK_BLE)
|
||||
target_sources(app PRIVATE src/events/ble_active_profile_changed.c)
|
||||
target_sources(app PRIVATE src/behaviors/behavior_bt.c)
|
||||
target_sources(app PRIVATE src/ble.c)
|
||||
target_sources(app PRIVATE src/hog.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/behaviors/behavior_rgb_underglow.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/behaviors/behavior_backlight.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/behaviors/behavior_bt.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble.c)
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/battery_state_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/battery.c)
|
||||
if (CONFIG_ZMK_SPLIT_BLE AND (NOT CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))
|
||||
target_sources(app PRIVATE src/split_listener.c)
|
||||
target_sources(app PRIVATE src/split/bluetooth/service.c)
|
||||
endif()
|
||||
if (CONFIG_ZMK_SPLIT_BLE AND CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE src/split/bluetooth/central.c)
|
||||
endif()
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_SPLIT app PRIVATE src/events/split_peripheral_status_changed.c)
|
||||
add_subdirectory(src/split)
|
||||
|
||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/usb.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_USB app PRIVATE src/usb_hid.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_BACKLIGHT app PRIVATE src/backlight.c)
|
||||
target_sources(app PRIVATE src/endpoints.c)
|
||||
target_sources(app PRIVATE src/hid_listener.c)
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
|
||||
add_subdirectory(src/display/)
|
||||
|
|
121
app/Kconfig
121
app/Kconfig
|
@ -166,108 +166,7 @@ endmenu
|
|||
# HID
|
||||
endmenu
|
||||
|
||||
menu "Split Support"
|
||||
|
||||
config ZMK_SPLIT
|
||||
bool "Split keyboard support"
|
||||
|
||||
if ZMK_SPLIT
|
||||
|
||||
menuconfig ZMK_SPLIT_BLE
|
||||
bool "Split keyboard support via BLE transport"
|
||||
depends on ZMK_BLE
|
||||
default y
|
||||
select BT_USER_PHY_UPDATE
|
||||
select BT_AUTO_PHY_UPDATE
|
||||
|
||||
if ZMK_SPLIT_BLE
|
||||
|
||||
menuconfig ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
bool "Central"
|
||||
select BT_CENTRAL
|
||||
select BT_GATT_CLIENT
|
||||
select BT_GATT_AUTO_DISCOVER_CCC
|
||||
|
||||
if ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
|
||||
config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE
|
||||
int "Max number of key position state events to queue when received from peripherals"
|
||||
default 5
|
||||
|
||||
config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE
|
||||
int "BLE split central write thread stack size"
|
||||
default 512
|
||||
|
||||
config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE
|
||||
int "Max number of behavior run events to queue to send to the peripheral(s)"
|
||||
default 5
|
||||
|
||||
endif
|
||||
|
||||
if !ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE
|
||||
int "BLE split peripheral notify thread stack size"
|
||||
default 650
|
||||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY
|
||||
int "BLE split peripheral notify thread priority"
|
||||
default 5
|
||||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE
|
||||
int "Max number of key position state events to queue to send to the central"
|
||||
default 10
|
||||
|
||||
config ZMK_USB
|
||||
default n
|
||||
|
||||
config BT_MAX_PAIRED
|
||||
default 1
|
||||
|
||||
config BT_MAX_CONN
|
||||
default 1
|
||||
|
||||
config BT_PERIPHERAL_PREF_MAX_INT
|
||||
default 6
|
||||
|
||||
#!ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
endif
|
||||
|
||||
#ZMK_SPLIT_BLE
|
||||
endif
|
||||
|
||||
#ZMK_SPLIT
|
||||
endif
|
||||
|
||||
if ZMK_BLE
|
||||
|
||||
if ZMK_SPLIT_BLE && ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
|
||||
config BT_MAX_CONN
|
||||
default 6
|
||||
|
||||
config BT_MAX_PAIRED
|
||||
default 6
|
||||
|
||||
#ZMK_SPLIT_BLE && ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
endif
|
||||
|
||||
if !ZMK_SPLIT_BLE
|
||||
|
||||
config BT_MAX_CONN
|
||||
default 5
|
||||
|
||||
config BT_MAX_PAIRED
|
||||
default 5
|
||||
|
||||
#!ZMK_SPLIT_BLE
|
||||
endif
|
||||
|
||||
#ZMK_BLE
|
||||
endif
|
||||
|
||||
#Split Support
|
||||
endmenu
|
||||
rsource "src/split/Kconfig"
|
||||
|
||||
#Basic Keyboard Setup
|
||||
endmenu
|
||||
|
@ -344,6 +243,13 @@ config ZMK_RGB_UNDERGLOW_ON_START
|
|||
bool "RGB underglow starts on by default"
|
||||
default y
|
||||
|
||||
config ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE
|
||||
bool "Turn off RGB underglow when keyboard goes into idle state"
|
||||
|
||||
config ZMK_RGB_UNDERGLOW_AUTO_OFF_USB
|
||||
bool "Turn off RGB underglow when USB is disconnected"
|
||||
depends on USB_DEVICE_STACK
|
||||
|
||||
#ZMK_RGB_UNDERGLOW
|
||||
endif
|
||||
|
||||
|
@ -431,6 +337,12 @@ config ZMK_BEHAVIORS_QUEUE_SIZE
|
|||
int "Maximum number of behaviors to allow queueing from a macro or other complex behavior"
|
||||
default 64
|
||||
|
||||
DT_COMPAT_ZMK_BEHAVIOR_KEY_TOGGLE := zmk,behavior-key-toggle
|
||||
|
||||
config ZMK_BEHAVIOR_KEY_TOGGLE
|
||||
bool
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_BEHAVIOR_KEY_TOGGLE))
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Advanced"
|
||||
|
@ -518,6 +430,11 @@ config ZMK_SETTINGS_SAVE_DEBOUNCE
|
|||
#SETTINGS
|
||||
endif
|
||||
|
||||
config ZMK_BATTERY_REPORT_INTERVAL
|
||||
depends on ZMK_BLE
|
||||
int "Battery level report interval in seconds"
|
||||
default 60
|
||||
|
||||
#Advanced
|
||||
endmenu
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_A_DUX_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "A. Dux"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -29,23 +29,23 @@
|
|||
compatible = "zmk,kscan-gpio-direct";
|
||||
label = "KSCAN";
|
||||
input-gpios =
|
||||
<&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_a 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_a 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_a 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_a 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
<&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 0 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>,
|
||||
<&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
;
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_BFO9000_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "BFO-9000"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_CLOG_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Clog"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -3,7 +3,7 @@ if SHIELD_CORNE_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Corne"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -12,7 +12,7 @@ if SHIELD_CORNE_LEFT || SHIELD_CORNE_RIGHT
|
|||
|
||||
config ZMK_SPLIT
|
||||
default y
|
||||
|
||||
|
||||
if ZMK_DISPLAY
|
||||
|
||||
config I2C
|
||||
|
@ -28,12 +28,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_CRADIO_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Cradio"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -11,23 +11,23 @@ Some revisions of the aforementioned PCBs have slightly different pin arrangemen
|
|||
/* The position of Q and B keys have been swapped */
|
||||
&kscan0 {
|
||||
input-gpios
|
||||
= <&pro_micro_d 6 (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_d 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro_d 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro_d 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro_d 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro_d 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
= <&pro_micro 6 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 18 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 19 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 20 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 21 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 15 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 14 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 16 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 10 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 1 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 2 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 3 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 4 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 7 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 8 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
, <&pro_micro 9 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>
|
||||
;
|
||||
};
|
||||
```
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_ELEPHANT42_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Elephant42"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -31,12 +31,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_ERGODASH_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Ergodash"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -7,7 +7,7 @@ if SHIELD_FOURIER_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Fourier"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_HELIX_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Helix"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_IRIS_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Iris"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -4,7 +4,7 @@ if SHIELD_JIAN_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Jian"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_JIRAN_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Jiran"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -4,7 +4,7 @@ if SHIELD_JORNE_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Jorne"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -29,12 +29,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -21,12 +21,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ if SHIELD_KYRIA_LEFT || SHIELD_KYRIA_REV2_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Kyria"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -29,12 +29,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 64
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_LEELOO_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Leeloo"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -31,11 +31,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
|
|
@ -32,8 +32,8 @@ Build command for the default keymap of Leeloo:
|
|||
|
||||
Build command for your custom keymap of Leeloo:
|
||||
|
||||
west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right -DZMK_CONFIG="C:\dev\zmk\[yourNmae]\leeloo\config"
|
||||
west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left -DZMK_CONFIG="C:\dev\zmk\[yourName]\leeloo\config"
|
||||
west build -d build/right -p -b nice_nano_v2 -- -DSHIELD=leeloo_right -DZMK_CONFIG="C:/dev/zmk/[yourNmae]/leeloo/config"
|
||||
west build -d build/left -p -b nice_nano_v2 -- -DSHIELD=leeloo_left -DZMK_CONFIG="C:/dev/zmk/[yourName]/leeloo/config"
|
||||
|
||||
# Support
|
||||
If you have any questions with regards to Leeloo, please [Contact Us](https://clicketysplit.ca/pages/contact-us).
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
/ {
|
||||
chosen {
|
||||
zephyr,display = &oled;
|
||||
zmk,kscan = &kscan0;
|
||||
zmk,matrix_transform = &default_transform;
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ if SHIELD_LILY58_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Lily58"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -29,12 +29,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_LOTUS58_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Lotus58"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -31,12 +31,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_MICRODOX_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Microdox"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -31,12 +31,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -21,12 +21,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -25,12 +25,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ if SHIELD_QUEFRENCY_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Quefrency"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -5,7 +5,7 @@ if SHIELD_REDOX_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Redox"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -6,7 +6,7 @@ if SHIELD_SOFLE_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Sofle"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -31,12 +31,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ if SHIELD_SPLITREUS62_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Splitreus62"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
|
|
@ -22,12 +22,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 32
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
31
app/boards/shields/two_percent_milk/boards/nice_nano.overlay
Normal file
31
app/boards/shields/two_percent_milk/boards/nice_nano.overlay
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include <dt-bindings/led/led.h>
|
||||
|
||||
&spi1 {
|
||||
compatible = "nordic,nrf-spim";
|
||||
status = "okay";
|
||||
mosi-pin = <9>;
|
||||
// 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 = <2>;
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zmk,underglow = &led_strip;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
#include <dt-bindings/led/led.h>
|
||||
|
||||
&spi1 {
|
||||
compatible = "nordic,nrf-spim";
|
||||
status = "okay";
|
||||
mosi-pin = <9>;
|
||||
// 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 = <2>;
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zmk,underglow = &led_strip;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,32 @@
|
|||
#include <dt-bindings/led/led.h>
|
||||
|
||||
&spi1 {
|
||||
compatible = "nordic,nrf-spim";
|
||||
status = "okay";
|
||||
mosi-pin = <43>;
|
||||
// Unused pins, needed for SPI definition, but not used by the ws2812 driver itself.
|
||||
sck-pin = <12>; // 0.12 is not broken out on the nRFMicro
|
||||
miso-pin = <22>; // 0.22 is not broken out on the nRFMicro
|
||||
|
||||
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 = <2>;
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zmk,underglow = &led_strip;
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
#include <dt-bindings/led/led.h>
|
||||
|
||||
&spi1 {
|
||||
compatible = "nordic,nrf-spim";
|
||||
status = "okay";
|
||||
mosi-pin = <38>;
|
||||
// Unused pins, needed for SPI definition, but not used by the ws2812 driver itself.
|
||||
sck-pin = <12>; // 0.12 is not broken out on the nRFMicro
|
||||
miso-pin = <22>; // 0.22 is not broken out on the nRFMicro
|
||||
|
||||
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 = <2>;
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zmk,underglow = &led_strip;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
#include <dt-bindings/led/led.h>
|
||||
|
||||
&spi1 {
|
||||
compatible = "nordic,nrf-spim";
|
||||
status = "okay";
|
||||
mosi-pin = <43>;
|
||||
// Unused pins, needed for SPI definition, but not used by the ws2812 driver itself.
|
||||
sck-pin = <12>; // 0.12 is not broken out on the nRFMicro
|
||||
miso-pin = <22>; // 0.22 is not broken out on the nRFMicro
|
||||
|
||||
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 = <2>;
|
||||
spi-one-frame = <0x70>;
|
||||
spi-zero-frame = <0x40>;
|
||||
color-mapping = <LED_COLOR_ID_GREEN LED_COLOR_ID_RED LED_COLOR_ID_BLUE>;
|
||||
};
|
||||
};
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
zmk,underglow = &led_strip;
|
||||
};
|
||||
};
|
|
@ -1,2 +1,9 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# Uncomment the following lines to enable RGB Underglow
|
||||
# CONFIG_ZMK_RGB_UNDERGLOW=y
|
||||
# CONFIG_WS2812_STRIP=y
|
||||
|
||||
# Uncomment the following line to turn on logging, and set ZMK logging to debug output
|
||||
# CONFIG_ZMK_USB_LOGGING=y
|
|
@ -4,19 +4,19 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/bt.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <dt-bindings/zmk/bt.h>
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&kp X
|
||||
&kp Z
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
default_layer {
|
||||
bindings = <
|
||||
&kp X
|
||||
&kp Z
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -6,7 +6,7 @@ if SHIELD_ZODIARK_LEFT
|
|||
config ZMK_KEYBOARD_NAME
|
||||
default "Zodiark"
|
||||
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y
|
||||
|
||||
endif
|
||||
|
@ -31,12 +31,6 @@ endif # ZMK_DISPLAY
|
|||
|
||||
if LVGL
|
||||
|
||||
config LVGL_HOR_RES_MAX
|
||||
default 128
|
||||
|
||||
config LVGL_VER_RES_MAX
|
||||
default 64
|
||||
|
||||
config LVGL_VDB_SIZE
|
||||
default 64
|
||||
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
list(APPEND BOARD_ROOT ${APPLICATION_SOURCE_DIR})
|
||||
list(APPEND DTS_ROOT ${APPLICATION_SOURCE_DIR})
|
||||
|
||||
get_property(cached_user_config_value CACHE ZMK_CONFIG PROPERTY VALUE)
|
||||
|
||||
set(user_config_cli_argument ${cached_user_config_value}) # Either new or old
|
||||
|
@ -57,9 +60,29 @@ if (ZMK_CONFIG)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(DEFINED SHIELD)
|
||||
string(REPLACE " " ";" SHIELD_AS_LIST "${SHIELD}")
|
||||
endif()
|
||||
|
||||
foreach(root ${BOARD_ROOT})
|
||||
set(shield_dir ${root}/boards/shields)
|
||||
# Match the Kconfig.shield files in the shield directories to make sure we are
|
||||
# finding shields, e.g. x_nucleo_iks01a1/Kconfig.shield
|
||||
file(GLOB_RECURSE shields_refs_list ${shield_dir}/*/Kconfig.shield)
|
||||
unset(SHIELD_LIST)
|
||||
foreach(shields_refs ${shields_refs_list})
|
||||
get_filename_component(shield_path ${shields_refs} DIRECTORY)
|
||||
file(GLOB shield_overlays RELATIVE ${shield_path} ${shield_path}/*.overlay)
|
||||
foreach(overlay ${shield_overlays})
|
||||
get_filename_component(shield ${overlay} NAME_WE)
|
||||
list(APPEND SHIELD_LIST ${shield})
|
||||
set(SHIELD_DIR_${shield} ${shield_path})
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
if (EXISTS "${root}/boards/${BOARD}.overlay")
|
||||
list(APPEND ZMK_DTC_FILES "${root}/boards/${BOARD}.overlay")
|
||||
list(APPEND shield_dts_files "${root}/boards/${BOARD}.overlay")
|
||||
endif()
|
||||
if (NOT DEFINED BOARD_DIR_NAME)
|
||||
find_path(BOARD_DIR
|
||||
|
@ -74,34 +97,58 @@ foreach(root ${BOARD_ROOT})
|
|||
endif()
|
||||
|
||||
if(DEFINED SHIELD)
|
||||
find_path(shields_refs_list
|
||||
NAMES ${SHIELD}.overlay
|
||||
PATHS ${root}/boards/shields/*
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
foreach(shield_path ${shields_refs_list})
|
||||
get_filename_component(SHIELD_DIR ${shield_path} NAME)
|
||||
list(APPEND KEYMAP_DIRS ${shield_path})
|
||||
foreach(s ${SHIELD_AS_LIST})
|
||||
if(NOT ${s} IN_LIST SHIELD_LIST)
|
||||
message(WARNING "Didn't find ${s}")
|
||||
continue()
|
||||
endif()
|
||||
message(STATUS "Adding ${SHIELD_DIR_${s}}")
|
||||
list(APPEND KEYMAP_DIRS ${SHIELD_DIR_${s}})
|
||||
get_filename_component(shield_dir_name ${SHIELD_DIR_${s}} NAME)
|
||||
list(APPEND SHIELD_DIR ${shield_dir_name})
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Give a shield like `kyria_rev2_left` we want to use `kyria_rev2` and `kyria` as candidate names for
|
||||
# overlay/conf/keymap files.
|
||||
if(DEFINED SHIELD)
|
||||
foreach(s ${SHIELD_AS_LIST})
|
||||
if (DEFINED $SHIELD_DIR_${s})
|
||||
get_filename_component(shield_dir_name ${SHIELD_DIR_${s}} NAME)
|
||||
endif()
|
||||
string(REPLACE "_" ";" S_PIECES ${s})
|
||||
list(LENGTH S_PIECES S_PIECES_LEN)
|
||||
while(NOT S_PIECES STREQUAL "")
|
||||
list(POP_BACK S_PIECES)
|
||||
list(JOIN S_PIECES "_" s_substr)
|
||||
if ("${s_substr}" STREQUAL "" OR "${s_substr}" STREQUAL "${shield_dir_name}")
|
||||
break()
|
||||
endif()
|
||||
list(APPEND shield_candidate_names ${s_substr})
|
||||
endwhile()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (ZMK_CONFIG)
|
||||
if (EXISTS ${ZMK_CONFIG})
|
||||
message(STATUS "ZMK Config directory: ${ZMK_CONFIG}")
|
||||
list(APPEND DTS_ROOT ${ZMK_CONFIG})
|
||||
list(PREPEND KEYMAP_DIRS "${ZMK_CONFIG}")
|
||||
|
||||
if (SHIELD)
|
||||
message(STATUS "Board: ${BOARD}, ${BOARD_DIR}, ${SHIELD}, ${SHIELD_DIR}")
|
||||
list(APPEND overlay_candidates "${ZMK_CONFIG}/${SHIELD_DIR}.overlay")
|
||||
list(APPEND overlay_candidates "${ZMK_CONFIG}/${SHIELD_DIR}_${BOARD}.overlay")
|
||||
list(APPEND overlay_candidates "${ZMK_CONFIG}/${SHIELD}_${BOARD}.overlay")
|
||||
list(APPEND overlay_candidates "${ZMK_CONFIG}/${SHIELD}.overlay")
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${SHIELD_DIR}.conf")
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${SHIELD_DIR}_${BOARD}.conf")
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${SHIELD}_${BOARD}.conf")
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${SHIELD}.conf")
|
||||
if (DEFINED SHIELD)
|
||||
foreach (s ${shield_candidate_names} ${SHIELD_AS_LIST})
|
||||
if (DEFINED ${SHIELD_DIR_${s}})
|
||||
get_filename_component(shield_dir_name ${SHIELD_DIR_${s}} NAME)
|
||||
endif()
|
||||
list(APPEND overlay_candidates "${ZMK_CONFIG}/${s}_${BOARD}.overlay")
|
||||
list(APPEND overlay_candidates "${ZMK_CONFIG}/${s}.overlay")
|
||||
if (NOT "${shield_dir_name}" STREQUAL "${s}")
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${shield_dir_name}_${BOARD}.conf")
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${shield_dir_name}.conf")
|
||||
endif()
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${s}_${BOARD}.conf")
|
||||
list(APPEND config_candidates "${ZMK_CONFIG}/${s}.conf")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# TODO: Board revisions?
|
||||
|
@ -115,7 +162,7 @@ if (ZMK_CONFIG)
|
|||
foreach(overlay ${overlay_candidates})
|
||||
if (EXISTS "${overlay}")
|
||||
message(STATUS "ZMK Config devicetree overlay: ${overlay}")
|
||||
list(APPEND ZMK_DTC_FILES "${overlay}")
|
||||
list(APPEND shield_dts_files "${overlay}")
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
@ -123,8 +170,7 @@ if (ZMK_CONFIG)
|
|||
foreach(conf ${config_candidates})
|
||||
if (EXISTS "${conf}")
|
||||
message(STATUS "ZMK Config Kconfig: ${conf}")
|
||||
set(CONF_FILE "${conf}")
|
||||
break()
|
||||
list(APPEND shield_conf_files "${conf}")
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
|
@ -135,22 +181,20 @@ endif()
|
|||
|
||||
if(NOT KEYMAP_FILE)
|
||||
foreach(keymap_dir ${KEYMAP_DIRS})
|
||||
foreach(keymap_prefix ${SHIELD} ${SHIELD_DIR} ${BOARD} ${BOARD_DIR_NAME})
|
||||
foreach(keymap_prefix ${shield_candidate_names} ${SHIELD_AS_LIST} ${SHIELD_DIR} ${BOARD} ${BOARD_DIR_NAME})
|
||||
if (EXISTS ${keymap_dir}/${keymap_prefix}.keymap)
|
||||
set(KEYMAP_FILE "${keymap_dir}/${keymap_prefix}.keymap" CACHE STRING "Selected keymap file")
|
||||
message(STATUS "Using keymap file: ${KEYMAP_FILE}")
|
||||
set(DTC_OVERLAY_FILE ${KEYMAP_FILE})
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
else()
|
||||
message(STATUS "Using keymap file: ${KEYMAP_FILE}")
|
||||
set(DTC_OVERLAY_FILE ${KEYMAP_FILE})
|
||||
endif()
|
||||
|
||||
if (NOT KEYMAP_FILE)
|
||||
message(FATAL_ERROR "Failed to locate keymap file!")
|
||||
endif()
|
||||
|
||||
list(APPEND ZMK_DTC_FILES ${KEYMAP_FILE})
|
||||
|
||||
if (ZMK_DTC_FILES)
|
||||
string(REPLACE ";" " " DTC_OVERLAY_FILE "${ZMK_DTC_FILES}")
|
||||
message(WARNING "Failed to locate keymap file!")
|
||||
endif()
|
|
@ -11,6 +11,8 @@ shield:
|
|||
include:
|
||||
- board: bdn9_rev2
|
||||
- board: nice60
|
||||
- board: seeeduino_xiao_ble
|
||||
shield: hummingbird
|
||||
- board: nrf52840_m2
|
||||
shield: m60
|
||||
- board: planck_rev6
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (c) 2020 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
add_subdirectory(gpio)
|
||||
add_subdirectory_ifdef(CONFIG_ZMK_DRIVERS_GPIO gpio)
|
||||
add_subdirectory(kscan)
|
||||
add_subdirectory(sensor)
|
||||
add_subdirectory(display)
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
zephyr_library_named(zmk__drivers__gpio)
|
||||
zephyr_library_include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_595 gpio_595.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_GPIO_MCP23017 gpio_mcp23017.c)
|
||||
zephyr_library_sources_ifndef(CONFIG_GPIO_MCP23017 ${ZEPHYR_BASE}/misc/empty_file.c)
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
menuconfig ZMK_DRIVERS_GPIO
|
||||
bool "GPIO"
|
||||
|
||||
rsource "Kconfig.mcp23017"
|
||||
rsource "Kconfig.595"
|
25
app/drivers/gpio/Kconfig.595
Normal file
25
app/drivers/gpio/Kconfig.595
Normal file
|
@ -0,0 +1,25 @@
|
|||
# 595 GPIO configuration options
|
||||
|
||||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
DT_COMPAT_ZMK_GPIO_595 := zmk,gpio-595
|
||||
|
||||
menuconfig GPIO_595
|
||||
bool "595 Shift Register SPI driver"
|
||||
default $(dt_compat_enabled,$(DT_COMPAT_ZMK_GPIO_595))
|
||||
depends on SPI
|
||||
select HAS_DTS_GPIO
|
||||
select ZMK_DRIVERS_GPIO
|
||||
help
|
||||
Enable driver for 595 shift register chip using SPI.
|
||||
|
||||
if GPIO_595
|
||||
|
||||
config GPIO_595_INIT_PRIORITY
|
||||
int "Init priority"
|
||||
default 75
|
||||
help
|
||||
Device driver initialization priority.
|
||||
|
||||
endif #GPIO_595
|
|
@ -7,6 +7,7 @@ menuconfig GPIO_MCP23017
|
|||
bool "MCP23017 I2C-based GPIO chip"
|
||||
depends on I2C
|
||||
select HAS_DTS_GPIO
|
||||
select ZMK_DRIVERS_GPIO
|
||||
help
|
||||
Enable driver for MCP23017 I2C-based GPIO chip.
|
||||
|
||||
|
|
215
app/drivers/gpio/gpio_595.c
Normal file
215
app/drivers/gpio/gpio_595.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_gpio_595
|
||||
|
||||
/**
|
||||
* @file Driver for 595 SPI-based GPIO driver.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <kernel.h>
|
||||
#include <device.h>
|
||||
#include <init.h>
|
||||
#include <sys/byteorder.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/spi.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(gpio_595);
|
||||
|
||||
/** Configuration data */
|
||||
struct reg_595_config {
|
||||
/* gpio_driver_data needs to be first */
|
||||
struct gpio_driver_config common;
|
||||
|
||||
struct spi_dt_spec bus;
|
||||
|
||||
uint8_t ngpios;
|
||||
};
|
||||
|
||||
/** Runtime driver data */
|
||||
struct reg_595_drv_data {
|
||||
/* gpio_driver_data needs to be first */
|
||||
struct gpio_driver_config data;
|
||||
|
||||
struct k_sem lock;
|
||||
|
||||
uint32_t gpio_cache;
|
||||
};
|
||||
|
||||
static int reg_595_write_registers(const struct device *dev, uint32_t value) {
|
||||
const struct reg_595_config *config = dev->config;
|
||||
struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data;
|
||||
int ret = 0;
|
||||
|
||||
uint8_t nwrite = config->ngpios / 8;
|
||||
uint32_t reg_data = sys_cpu_to_be32(value);
|
||||
|
||||
/* Allow a sequence of 1-4 registers in sequence, lowest byte is for the first in the chain */
|
||||
const struct spi_buf tx_buf[1] = {{
|
||||
.buf = ((uint8_t *)®_data) + (4 - nwrite),
|
||||
.len = nwrite,
|
||||
}};
|
||||
|
||||
const struct spi_buf_set tx = {
|
||||
.buffers = tx_buf,
|
||||
.count = ARRAY_SIZE(tx_buf),
|
||||
};
|
||||
|
||||
ret = spi_write_dt(&config->bus, &tx);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("spi_write FAIL %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
drv_data->gpio_cache = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup the pin direction (input or output)
|
||||
*
|
||||
* @param dev Device struct of the 595
|
||||
* @param pin The pin number
|
||||
* @param flags Flags of pin or port
|
||||
*
|
||||
* @return 0 if successful, failed otherwise
|
||||
*/
|
||||
static int setup_pin_dir(const struct device *dev, uint32_t pin, int flags) {
|
||||
if ((flags & GPIO_OUTPUT) == 0U) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int reg_595_pin_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags) {
|
||||
int ret;
|
||||
|
||||
/* Can't do SPI bus operations from an ISR */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
if ((flags & GPIO_OPEN_DRAIN) != 0U) {
|
||||
return -ENOTSUP;
|
||||
};
|
||||
|
||||
ret = setup_pin_dir(dev, pin, flags);
|
||||
if (ret) {
|
||||
LOG_ERR("595: error setting pin direction (%d)", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int reg_595_port_get_raw(const struct device *dev, uint32_t *value) { return -ENOTSUP; }
|
||||
|
||||
static int reg_595_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value) {
|
||||
struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data;
|
||||
uint32_t buf;
|
||||
int ret;
|
||||
|
||||
/* Can't do SPI bus operations from an ISR */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
k_sem_take(&drv_data->lock, K_FOREVER);
|
||||
|
||||
buf = drv_data->gpio_cache;
|
||||
buf = (buf & ~mask) | (mask & value);
|
||||
|
||||
ret = reg_595_write_registers(dev, buf);
|
||||
|
||||
k_sem_give(&drv_data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int reg_595_port_set_bits_raw(const struct device *dev, uint32_t mask) {
|
||||
return reg_595_port_set_masked_raw(dev, mask, mask);
|
||||
}
|
||||
|
||||
static int reg_595_port_clear_bits_raw(const struct device *dev, uint32_t mask) {
|
||||
return reg_595_port_set_masked_raw(dev, mask, 0);
|
||||
}
|
||||
|
||||
static int reg_595_port_toggle_bits(const struct device *dev, uint32_t mask) {
|
||||
struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data;
|
||||
uint32_t buf;
|
||||
int ret;
|
||||
|
||||
/* Can't do SPI bus operations from an ISR */
|
||||
if (k_is_in_isr()) {
|
||||
return -EWOULDBLOCK;
|
||||
}
|
||||
|
||||
k_sem_take(&drv_data->lock, K_FOREVER);
|
||||
|
||||
buf = drv_data->gpio_cache;
|
||||
buf ^= mask;
|
||||
|
||||
ret = reg_595_write_registers(dev, buf);
|
||||
|
||||
k_sem_give(&drv_data->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct gpio_driver_api api_table = {
|
||||
.pin_configure = reg_595_pin_config,
|
||||
.port_get_raw = reg_595_port_get_raw,
|
||||
.port_set_masked_raw = reg_595_port_set_masked_raw,
|
||||
.port_set_bits_raw = reg_595_port_set_bits_raw,
|
||||
.port_clear_bits_raw = reg_595_port_clear_bits_raw,
|
||||
.port_toggle_bits = reg_595_port_toggle_bits,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialization function of 595
|
||||
*
|
||||
* @param dev Device struct
|
||||
* @return 0 if successful, failed otherwise.
|
||||
*/
|
||||
static int reg_595_init(const struct device *dev) {
|
||||
const struct reg_595_config *const config = dev->config;
|
||||
struct reg_595_drv_data *const drv_data = (struct reg_595_drv_data *const)dev->data;
|
||||
|
||||
if (!device_is_ready(config->bus.bus)) {
|
||||
LOG_ERR("Unable to get SPI bus device");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
k_sem_init(&drv_data->lock, 1, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GPIO_PORT_PIN_MASK_FROM_NGPIOS(ngpios) ((gpio_port_pins_t)(((uint64_t)1 << (ngpios)) - 1U))
|
||||
|
||||
#define GPIO_PORT_PIN_MASK_FROM_DT_INST(inst) \
|
||||
GPIO_PORT_PIN_MASK_FROM_NGPIOS(DT_INST_PROP(inst, ngpios))
|
||||
|
||||
#define REG_595_INIT(n) \
|
||||
static struct reg_595_config reg_595_##n##_config = { \
|
||||
.common = \
|
||||
{ \
|
||||
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
|
||||
}, \
|
||||
.bus = \
|
||||
SPI_DT_SPEC_INST_GET(n, SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | SPI_WORD_SET(8), 0), \
|
||||
.ngpios = DT_INST_PROP(n, ngpios), \
|
||||
}; \
|
||||
\
|
||||
static struct reg_595_drv_data reg_595_##n##_drvdata = {}; \
|
||||
\
|
||||
/* This has to init after SPI master */ \
|
||||
DEVICE_DT_INST_DEFINE(n, reg_595_init, NULL, ®_595_##n##_drvdata, ®_595_##n##_config, \
|
||||
POST_KERNEL, CONFIG_GPIO_595_INIT_PRIORITY, &api_table);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(REG_595_INIT)
|
|
@ -4,83 +4,297 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_kscan_gpio_direct
|
||||
#include "debounce.h"
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/kscan.h>
|
||||
#include <devicetree.h>
|
||||
#include <drivers/gpio.h>
|
||||
#include <drivers/kscan.h>
|
||||
#include <kernel.h>
|
||||
#include <logging/log.h>
|
||||
#include <sys/util.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
struct kscan_gpio_item_config {
|
||||
char *label;
|
||||
gpio_pin_t pin;
|
||||
gpio_flags_t flags;
|
||||
};
|
||||
#define DT_DRV_COMPAT zmk_kscan_gpio_direct
|
||||
|
||||
union work_reference {
|
||||
struct k_work_delayable delayed;
|
||||
struct k_work direct;
|
||||
};
|
||||
#if CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS >= 0
|
||||
#define INST_DEBOUNCE_PRESS_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_PRESS_MS
|
||||
#else
|
||||
#define INST_DEBOUNCE_PRESS_MS(n) \
|
||||
DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_press_ms))
|
||||
#endif
|
||||
|
||||
struct kscan_gpio_config {
|
||||
uint8_t num_of_inputs;
|
||||
uint8_t debounce_period;
|
||||
struct kscan_gpio_item_config inputs[];
|
||||
};
|
||||
#if CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS >= 0
|
||||
#define INST_DEBOUNCE_RELEASE_MS(n) CONFIG_ZMK_KSCAN_DEBOUNCE_RELEASE_MS
|
||||
#else
|
||||
#define INST_DEBOUNCE_RELEASE_MS(n) \
|
||||
DT_INST_PROP_OR(n, debounce_period, DT_INST_PROP(n, debounce_release_ms))
|
||||
#endif
|
||||
|
||||
struct kscan_gpio_data {
|
||||
#if defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING)
|
||||
struct k_timer poll_timer;
|
||||
#endif /* defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) */
|
||||
kscan_callback_t callback;
|
||||
union work_reference work;
|
||||
#define USE_POLLING IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING)
|
||||
#define USE_INTERRUPTS (!USE_POLLING)
|
||||
|
||||
#define COND_INTERRUPTS(code) COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, (), code)
|
||||
#define COND_POLL_OR_INTERRUPTS(pollcode, intcode) \
|
||||
COND_CODE_1(CONFIG_ZMK_KSCAN_DIRECT_POLLING, pollcode, intcode)
|
||||
|
||||
#define INST_INPUTS_LEN(n) DT_INST_PROP_LEN(n, input_gpios)
|
||||
#define KSCAN_DIRECT_INPUT_CFG_INIT(idx, inst_idx) \
|
||||
GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst_idx), input_gpios, idx),
|
||||
|
||||
struct kscan_direct_irq_callback {
|
||||
const struct device *dev;
|
||||
uint32_t pin_state;
|
||||
const struct device *inputs[];
|
||||
};
|
||||
|
||||
static const struct device **kscan_gpio_input_devices(const struct device *dev) {
|
||||
struct kscan_gpio_data *data = dev->data;
|
||||
return data->inputs;
|
||||
}
|
||||
|
||||
static const struct kscan_gpio_item_config *kscan_gpio_input_configs(const struct device *dev) {
|
||||
const struct kscan_gpio_config *cfg = dev->config;
|
||||
return cfg->inputs;
|
||||
}
|
||||
|
||||
static void kscan_gpio_direct_queue_read(union work_reference *work, uint8_t debounce_period) {
|
||||
if (debounce_period > 0) {
|
||||
k_work_reschedule(&work->delayed, K_MSEC(debounce_period));
|
||||
} else {
|
||||
k_work_submit(&work->direct);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING)
|
||||
|
||||
struct kscan_gpio_irq_callback {
|
||||
const struct device *dev;
|
||||
union work_reference *work;
|
||||
uint8_t debounce_period;
|
||||
struct gpio_callback callback;
|
||||
};
|
||||
|
||||
static int kscan_gpio_config_interrupts(const struct device *dev, gpio_flags_t flags) {
|
||||
const struct kscan_gpio_config *cfg = dev->config;
|
||||
const struct device **devices = kscan_gpio_input_devices(dev);
|
||||
const struct kscan_gpio_item_config *configs = kscan_gpio_input_configs(dev);
|
||||
struct kscan_direct_data {
|
||||
const struct device *dev;
|
||||
kscan_callback_t callback;
|
||||
struct k_work_delayable work;
|
||||
#if USE_INTERRUPTS
|
||||
/** Array of length config->inputs.len */
|
||||
struct kscan_direct_irq_callback *irqs;
|
||||
#endif
|
||||
/** Timestamp of the current or scheduled scan. */
|
||||
int64_t scan_time;
|
||||
/** Current state of the inputs as an array of length config->inputs.len */
|
||||
struct debounce_state *pin_state;
|
||||
};
|
||||
|
||||
for (int i = 0; i < cfg->num_of_inputs; i++) {
|
||||
const struct device *dev = devices[i];
|
||||
const struct kscan_gpio_item_config *cfg = &configs[i];
|
||||
struct kscan_gpio_list {
|
||||
const struct gpio_dt_spec *gpios;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
int err = gpio_pin_interrupt_configure(dev, cfg->pin, flags);
|
||||
/** Define a kscan_gpio_list from a compile-time GPIO array. */
|
||||
#define KSCAN_GPIO_LIST(gpio_array) \
|
||||
((struct kscan_gpio_list){.gpios = gpio_array, .len = ARRAY_SIZE(gpio_array)})
|
||||
|
||||
struct kscan_direct_config {
|
||||
struct kscan_gpio_list inputs;
|
||||
struct debounce_config debounce_config;
|
||||
int32_t debounce_scan_period_ms;
|
||||
int32_t poll_period_ms;
|
||||
bool toggle_mode;
|
||||
};
|
||||
|
||||
#if USE_INTERRUPTS
|
||||
static int kscan_direct_interrupt_configure(const struct device *dev, const gpio_flags_t flags) {
|
||||
const struct kscan_direct_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
|
||||
int err = gpio_pin_interrupt_configure_dt(gpio, flags);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure interrupt for pin %u on %s", gpio->pin, gpio->port->name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_INTERRUPTS
|
||||
static int kscan_direct_interrupt_enable(const struct device *dev) {
|
||||
return kscan_direct_interrupt_configure(dev, GPIO_INT_LEVEL_ACTIVE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_INTERRUPTS
|
||||
static int kscan_direct_interrupt_disable(const struct device *dev) {
|
||||
return kscan_direct_interrupt_configure(dev, GPIO_INT_DISABLE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_INTERRUPTS
|
||||
static void kscan_direct_irq_callback_handler(const struct device *port, struct gpio_callback *cb,
|
||||
const gpio_port_pins_t pin) {
|
||||
struct kscan_direct_irq_callback *irq_data =
|
||||
CONTAINER_OF(cb, struct kscan_direct_irq_callback, callback);
|
||||
struct kscan_direct_data *data = irq_data->dev->data;
|
||||
|
||||
// Disable our interrupts temporarily to avoid re-entry while we scan.
|
||||
kscan_direct_interrupt_disable(data->dev);
|
||||
|
||||
data->scan_time = k_uptime_get();
|
||||
|
||||
k_work_reschedule(&data->work, K_NO_WAIT);
|
||||
}
|
||||
#endif
|
||||
|
||||
static gpio_flags_t kscan_gpio_get_extra_flags(const struct gpio_dt_spec *gpio, bool active) {
|
||||
if (!active) {
|
||||
return ((BIT(0) & gpio->dt_flags) ? GPIO_PULL_UP : GPIO_PULL_DOWN);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kscan_inputs_set_flags(const struct kscan_gpio_list *inputs,
|
||||
const struct gpio_dt_spec *active_gpio) {
|
||||
gpio_flags_t extra_flags;
|
||||
for (int i = 0; i < inputs->len; i++) {
|
||||
extra_flags = GPIO_INPUT | kscan_gpio_get_extra_flags(&inputs->gpios[i],
|
||||
&inputs->gpios[i] == active_gpio);
|
||||
LOG_DBG("Extra flags equal to: %d", extra_flags);
|
||||
|
||||
int err = gpio_pin_configure_dt(&inputs->gpios[i], extra_flags);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure flags on pin %d on %s", inputs->gpios[i].pin,
|
||||
inputs->gpios[i].port->name);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kscan_direct_read_continue(const struct device *dev) {
|
||||
const struct kscan_direct_config *config = dev->config;
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
|
||||
data->scan_time += config->debounce_scan_period_ms;
|
||||
|
||||
k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time));
|
||||
}
|
||||
|
||||
static void kscan_direct_read_end(const struct device *dev) {
|
||||
#if USE_INTERRUPTS
|
||||
// Return to waiting for an interrupt.
|
||||
kscan_direct_interrupt_enable(dev);
|
||||
#else
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
const struct kscan_direct_config *config = dev->config;
|
||||
|
||||
data->scan_time += config->poll_period_ms;
|
||||
|
||||
// Return to polling slowly.
|
||||
k_work_reschedule(&data->work, K_TIMEOUT_ABS_MS(data->scan_time));
|
||||
#endif
|
||||
}
|
||||
|
||||
static int kscan_direct_read(const struct device *dev) {
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
const struct kscan_direct_config *config = dev->config;
|
||||
|
||||
// Read the inputs.
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
|
||||
const bool active = gpio_pin_get_dt(gpio);
|
||||
|
||||
debounce_update(&data->pin_state[i], active, config->debounce_scan_period_ms,
|
||||
&config->debounce_config);
|
||||
}
|
||||
|
||||
// Process the new state.
|
||||
bool continue_scan = false;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
struct debounce_state *state = &data->pin_state[i];
|
||||
|
||||
if (debounce_get_changed(state)) {
|
||||
const bool pressed = debounce_is_pressed(state);
|
||||
|
||||
LOG_DBG("Sending event at 0,%i state %s", i, pressed ? "on" : "off");
|
||||
data->callback(dev, 0, i, pressed);
|
||||
if (config->toggle_mode && pressed) {
|
||||
kscan_inputs_set_flags(&config->inputs, &config->inputs.gpios[i]);
|
||||
}
|
||||
}
|
||||
|
||||
continue_scan = continue_scan || debounce_is_active(state);
|
||||
}
|
||||
|
||||
if (continue_scan) {
|
||||
// At least one key is pressed or the debouncer has not yet decided if
|
||||
// it is pressed. Poll quickly until everything is released.
|
||||
kscan_direct_read_continue(dev);
|
||||
} else {
|
||||
// All keys are released. Return to normal.
|
||||
kscan_direct_read_end(dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kscan_direct_work_handler(struct k_work *work) {
|
||||
struct k_work_delayable *dwork = CONTAINER_OF(work, struct k_work_delayable, work);
|
||||
struct kscan_direct_data *data = CONTAINER_OF(dwork, struct kscan_direct_data, work);
|
||||
kscan_direct_read(data->dev);
|
||||
}
|
||||
|
||||
static int kscan_direct_configure(const struct device *dev, kscan_callback_t callback) {
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
|
||||
if (!callback) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->callback = callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kscan_direct_enable(const struct device *dev) {
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
|
||||
data->scan_time = k_uptime_get();
|
||||
|
||||
// Read will automatically start interrupts/polling once done.
|
||||
return kscan_direct_read(dev);
|
||||
}
|
||||
|
||||
static int kscan_direct_disable(const struct device *dev) {
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
|
||||
k_work_cancel_delayable(&data->work);
|
||||
|
||||
#if USE_INTERRUPTS
|
||||
return kscan_direct_interrupt_disable(dev);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int kscan_direct_init_input_inst(const struct device *dev, const struct gpio_dt_spec *gpio,
|
||||
const int index, bool toggle_mode) {
|
||||
if (!device_is_ready(gpio->port)) {
|
||||
LOG_ERR("GPIO is not ready: %s", gpio->port->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
int err = gpio_pin_configure_dt(
|
||||
gpio, GPIO_INPUT | (toggle_mode ? kscan_gpio_get_extra_flags(gpio, false) : 0));
|
||||
if (err) {
|
||||
LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name);
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Configured pin %u on %s for input", gpio->pin, gpio->port->name);
|
||||
|
||||
#if USE_INTERRUPTS
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
struct kscan_direct_irq_callback *irq = &data->irqs[index];
|
||||
|
||||
irq->dev = dev;
|
||||
gpio_init_callback(&irq->callback, kscan_direct_irq_callback_handler, BIT(gpio->pin));
|
||||
err = gpio_add_callback(gpio->port, &irq->callback);
|
||||
if (err) {
|
||||
LOG_ERR("Error adding the callback to the input device: %i", err);
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kscan_direct_init_inputs(const struct device *dev) {
|
||||
const struct kscan_direct_config *config = dev->config;
|
||||
|
||||
for (int i = 0; i < config->inputs.len; i++) {
|
||||
const struct gpio_dt_spec *gpio = &config->inputs.gpios[i];
|
||||
int err = kscan_direct_init_input_inst(dev, gpio, i, config->toggle_mode);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to enable direct GPIO interrupt");
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -88,155 +302,55 @@ static int kscan_gpio_config_interrupts(const struct device *dev, gpio_flags_t f
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int kscan_gpio_direct_enable(const struct device *dev) {
|
||||
return kscan_gpio_config_interrupts(dev, GPIO_INT_LEVEL_ACTIVE);
|
||||
}
|
||||
static int kscan_gpio_direct_disable(const struct device *dev) {
|
||||
return kscan_gpio_config_interrupts(dev, GPIO_INT_DISABLE);
|
||||
}
|
||||
static int kscan_direct_init(const struct device *dev) {
|
||||
struct kscan_direct_data *data = dev->data;
|
||||
|
||||
static void kscan_gpio_irq_callback_handler(const struct device *dev, struct gpio_callback *cb,
|
||||
gpio_port_pins_t pin) {
|
||||
struct kscan_gpio_irq_callback *data =
|
||||
CONTAINER_OF(cb, struct kscan_gpio_irq_callback, callback);
|
||||
data->dev = dev;
|
||||
|
||||
kscan_gpio_direct_disable(data->dev);
|
||||
kscan_gpio_direct_queue_read(data->work, data->debounce_period);
|
||||
}
|
||||
kscan_direct_init_inputs(dev);
|
||||
|
||||
#else /* !defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) */
|
||||
|
||||
static void kscan_gpio_timer_handler(struct k_timer *timer) {
|
||||
struct kscan_gpio_data *data = CONTAINER_OF(timer, struct kscan_gpio_data, poll_timer);
|
||||
|
||||
kscan_gpio_direct_queue_read(&data->work, 0);
|
||||
}
|
||||
|
||||
static int kscan_gpio_direct_enable(const struct device *dev) {
|
||||
struct kscan_gpio_data *data = dev->data;
|
||||
k_timer_start(&data->poll_timer, K_MSEC(10), K_MSEC(10));
|
||||
return 0;
|
||||
}
|
||||
static int kscan_gpio_direct_disable(const struct device *dev) {
|
||||
struct kscan_gpio_data *data = dev->data;
|
||||
k_timer_stop(&data->poll_timer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING) */
|
||||
|
||||
static int kscan_gpio_direct_configure(const struct device *dev, kscan_callback_t callback) {
|
||||
struct kscan_gpio_data *data = dev->data;
|
||||
if (!callback) {
|
||||
return -EINVAL;
|
||||
}
|
||||
data->callback = callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kscan_gpio_read(const struct device *dev) {
|
||||
struct kscan_gpio_data *data = dev->data;
|
||||
const struct kscan_gpio_config *cfg = dev->config;
|
||||
uint32_t read_state = data->pin_state;
|
||||
bool submit_follow_up_read = false;
|
||||
for (int i = 0; i < cfg->num_of_inputs; i++) {
|
||||
const struct device *in_dev = kscan_gpio_input_devices(dev)[i];
|
||||
const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs(dev)[i];
|
||||
WRITE_BIT(read_state, i, gpio_pin_get(in_dev, in_cfg->pin) > 0);
|
||||
}
|
||||
for (int i = 0; i < cfg->num_of_inputs; i++) {
|
||||
bool prev_pressed = BIT(i) & data->pin_state;
|
||||
bool pressed = (BIT(i) & read_state) != 0;
|
||||
submit_follow_up_read = (submit_follow_up_read || pressed);
|
||||
if (pressed != prev_pressed) {
|
||||
LOG_DBG("Sending event at %d,%d state %s", 0, i, (pressed ? "on" : "off"));
|
||||
WRITE_BIT(data->pin_state, i, pressed);
|
||||
data->callback(dev, 0, i, pressed);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_ZMK_KSCAN_DIRECT_POLLING)
|
||||
if (submit_follow_up_read) {
|
||||
kscan_gpio_direct_queue_read(&data->work, cfg->debounce_period);
|
||||
} else {
|
||||
kscan_gpio_direct_enable(dev);
|
||||
}
|
||||
#endif
|
||||
k_work_init_delayable(&data->work, kscan_direct_work_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kscan_gpio_work_handler(struct k_work *work) {
|
||||
struct kscan_gpio_data *data = CONTAINER_OF(work, struct kscan_gpio_data, work);
|
||||
kscan_gpio_read(data->dev);
|
||||
}
|
||||
|
||||
static const struct kscan_driver_api gpio_driver_api = {
|
||||
.config = kscan_gpio_direct_configure,
|
||||
.enable_callback = kscan_gpio_direct_enable,
|
||||
.disable_callback = kscan_gpio_direct_disable,
|
||||
static const struct kscan_driver_api kscan_direct_api = {
|
||||
.config = kscan_direct_configure,
|
||||
.enable_callback = kscan_direct_enable,
|
||||
.disable_callback = kscan_direct_disable,
|
||||
};
|
||||
|
||||
#define KSCAN_DIRECT_INPUT_ITEM(i, n) \
|
||||
{ \
|
||||
.label = DT_INST_GPIO_LABEL_BY_IDX(n, input_gpios, i), \
|
||||
.pin = DT_INST_GPIO_PIN_BY_IDX(n, input_gpios, i), \
|
||||
.flags = DT_INST_GPIO_FLAGS_BY_IDX(n, input_gpios, i), \
|
||||
},
|
||||
#define KSCAN_DIRECT_INIT(n) \
|
||||
BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(n) <= DEBOUNCE_COUNTER_MAX, \
|
||||
"ZMK_KSCAN_DEBOUNCE_PRESS_MS or debounce-press-ms is too large"); \
|
||||
BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \
|
||||
"ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \
|
||||
\
|
||||
static const struct gpio_dt_spec kscan_direct_inputs_##n[] = { \
|
||||
UTIL_LISTIFY(INST_INPUTS_LEN(n), KSCAN_DIRECT_INPUT_CFG_INIT, n)}; \
|
||||
\
|
||||
static struct debounce_state kscan_direct_state_##n[INST_INPUTS_LEN(n)]; \
|
||||
\
|
||||
COND_INTERRUPTS( \
|
||||
(static struct kscan_direct_irq_callback kscan_direct_irqs_##n[INST_INPUTS_LEN(n)];)) \
|
||||
\
|
||||
static struct kscan_direct_data kscan_direct_data_##n = { \
|
||||
.pin_state = kscan_direct_state_##n, COND_INTERRUPTS((.irqs = kscan_direct_irqs_##n, ))}; \
|
||||
\
|
||||
static struct kscan_direct_config kscan_direct_config_##n = { \
|
||||
.inputs = KSCAN_GPIO_LIST(kscan_direct_inputs_##n), \
|
||||
.debounce_config = \
|
||||
{ \
|
||||
.debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n), \
|
||||
.debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(n), \
|
||||
}, \
|
||||
.debounce_scan_period_ms = DT_INST_PROP(n, debounce_scan_period_ms), \
|
||||
.poll_period_ms = DT_INST_PROP(n, poll_period_ms), \
|
||||
.toggle_mode = DT_INST_PROP(n, toggle_mode), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(n, &kscan_direct_init, NULL, &kscan_direct_data_##n, \
|
||||
&kscan_direct_config_##n, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \
|
||||
&kscan_direct_api);
|
||||
|
||||
#define INST_INPUT_LEN(n) DT_INST_PROP_LEN(n, input_gpios)
|
||||
|
||||
#define GPIO_INST_INIT(n) \
|
||||
COND_CODE_0(IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING), \
|
||||
(static struct kscan_gpio_irq_callback irq_callbacks_##n[INST_INPUT_LEN(n)];), ()) \
|
||||
static struct kscan_gpio_data kscan_gpio_data_##n = { \
|
||||
.inputs = {[INST_INPUT_LEN(n) - 1] = NULL}}; \
|
||||
static int kscan_gpio_init_##n(const struct device *dev) { \
|
||||
struct kscan_gpio_data *data = dev->data; \
|
||||
const struct kscan_gpio_config *cfg = dev->config; \
|
||||
int err; \
|
||||
const struct device **input_devices = kscan_gpio_input_devices(dev); \
|
||||
for (int i = 0; i < cfg->num_of_inputs; i++) { \
|
||||
const struct kscan_gpio_item_config *in_cfg = &kscan_gpio_input_configs(dev)[i]; \
|
||||
input_devices[i] = device_get_binding(in_cfg->label); \
|
||||
if (!input_devices[i]) { \
|
||||
LOG_ERR("Unable to find input GPIO device"); \
|
||||
return -EINVAL; \
|
||||
} \
|
||||
err = gpio_pin_configure(input_devices[i], in_cfg->pin, GPIO_INPUT | in_cfg->flags); \
|
||||
if (err) { \
|
||||
LOG_ERR("Unable to configure pin %d on %s for input", in_cfg->pin, in_cfg->label); \
|
||||
return err; \
|
||||
} \
|
||||
COND_CODE_0( \
|
||||
IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING), \
|
||||
(irq_callbacks_##n[i].work = &data->work; irq_callbacks_##n[i].dev = dev; \
|
||||
irq_callbacks_##n[i].debounce_period = cfg->debounce_period; \
|
||||
gpio_init_callback(&irq_callbacks_##n[i].callback, \
|
||||
kscan_gpio_irq_callback_handler, BIT(in_cfg->pin)); \
|
||||
err = gpio_add_callback(input_devices[i], &irq_callbacks_##n[i].callback); \
|
||||
if (err) { \
|
||||
LOG_ERR("Error adding the callback to the column device"); \
|
||||
return err; \
|
||||
}), \
|
||||
()) \
|
||||
} \
|
||||
data->dev = dev; \
|
||||
COND_CODE_1(IS_ENABLED(CONFIG_ZMK_KSCAN_DIRECT_POLLING), \
|
||||
(k_timer_init(&data->poll_timer, kscan_gpio_timer_handler, NULL);), ()) \
|
||||
if (cfg->debounce_period > 0) { \
|
||||
k_work_init_delayable(&data->work.delayed, kscan_gpio_work_handler); \
|
||||
} else { \
|
||||
k_work_init(&data->work.direct, kscan_gpio_work_handler); \
|
||||
} \
|
||||
return 0; \
|
||||
} \
|
||||
static const struct kscan_gpio_config kscan_gpio_config_##n = { \
|
||||
.inputs = {UTIL_LISTIFY(INST_INPUT_LEN(n), KSCAN_DIRECT_INPUT_ITEM, n)}, \
|
||||
.num_of_inputs = INST_INPUT_LEN(n), \
|
||||
.debounce_period = DT_INST_PROP(n, debounce_period)}; \
|
||||
DEVICE_DT_INST_DEFINE(n, kscan_gpio_init_##n, NULL, &kscan_gpio_data_##n, \
|
||||
&kscan_gpio_config_##n, POST_KERNEL, CONFIG_ZMK_KSCAN_INIT_PRIORITY, \
|
||||
&gpio_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(GPIO_INST_INIT)
|
||||
DT_INST_FOREACH_STATUS_OKAY(KSCAN_DIRECT_INIT);
|
||||
|
|
|
@ -418,46 +418,46 @@ static const struct kscan_driver_api kscan_matrix_api = {
|
|||
.disable_callback = kscan_matrix_disable,
|
||||
};
|
||||
|
||||
#define KSCAN_MATRIX_INIT(index) \
|
||||
BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(index) <= DEBOUNCE_COUNTER_MAX, \
|
||||
#define KSCAN_MATRIX_INIT(n) \
|
||||
BUILD_ASSERT(INST_DEBOUNCE_PRESS_MS(n) <= DEBOUNCE_COUNTER_MAX, \
|
||||
"ZMK_KSCAN_DEBOUNCE_PRESS_MS or debounce-press-ms is too large"); \
|
||||
BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(index) <= DEBOUNCE_COUNTER_MAX, \
|
||||
BUILD_ASSERT(INST_DEBOUNCE_RELEASE_MS(n) <= DEBOUNCE_COUNTER_MAX, \
|
||||
"ZMK_KSCAN_DEBOUNCE_RELEASE_MS or debounce-release-ms is too large"); \
|
||||
\
|
||||
static const struct gpio_dt_spec kscan_matrix_rows_##index[] = { \
|
||||
UTIL_LISTIFY(INST_ROWS_LEN(index), KSCAN_GPIO_ROW_CFG_INIT, index)}; \
|
||||
static const struct gpio_dt_spec kscan_matrix_rows_##n[] = { \
|
||||
UTIL_LISTIFY(INST_ROWS_LEN(n), KSCAN_GPIO_ROW_CFG_INIT, n)}; \
|
||||
\
|
||||
static const struct gpio_dt_spec kscan_matrix_cols_##index[] = { \
|
||||
UTIL_LISTIFY(INST_COLS_LEN(index), KSCAN_GPIO_COL_CFG_INIT, index)}; \
|
||||
static const struct gpio_dt_spec kscan_matrix_cols_##n[] = { \
|
||||
UTIL_LISTIFY(INST_COLS_LEN(n), KSCAN_GPIO_COL_CFG_INIT, n)}; \
|
||||
\
|
||||
static struct debounce_state kscan_matrix_state_##index[INST_MATRIX_LEN(index)]; \
|
||||
static struct debounce_state kscan_matrix_state_##n[INST_MATRIX_LEN(n)]; \
|
||||
\
|
||||
COND_INTERRUPTS((static struct kscan_matrix_irq_callback \
|
||||
kscan_matrix_irqs_##index[INST_INPUTS_LEN(index)];)) \
|
||||
COND_INTERRUPTS( \
|
||||
(static struct kscan_matrix_irq_callback kscan_matrix_irqs_##n[INST_INPUTS_LEN(n)];)) \
|
||||
\
|
||||
static struct kscan_matrix_data kscan_matrix_data_##index = { \
|
||||
.matrix_state = kscan_matrix_state_##index, \
|
||||
COND_INTERRUPTS((.irqs = kscan_matrix_irqs_##index, ))}; \
|
||||
static struct kscan_matrix_data kscan_matrix_data_##n = { \
|
||||
.matrix_state = kscan_matrix_state_##n, \
|
||||
COND_INTERRUPTS((.irqs = kscan_matrix_irqs_##n, ))}; \
|
||||
\
|
||||
static struct kscan_matrix_config kscan_matrix_config_##index = { \
|
||||
.rows = KSCAN_GPIO_LIST(kscan_matrix_rows_##index), \
|
||||
.cols = KSCAN_GPIO_LIST(kscan_matrix_cols_##index), \
|
||||
.inputs = KSCAN_GPIO_LIST( \
|
||||
COND_DIODE_DIR(index, (kscan_matrix_cols_##index), (kscan_matrix_rows_##index))), \
|
||||
.outputs = KSCAN_GPIO_LIST( \
|
||||
COND_DIODE_DIR(index, (kscan_matrix_rows_##index), (kscan_matrix_cols_##index))), \
|
||||
static struct kscan_matrix_config kscan_matrix_config_##n = { \
|
||||
.rows = KSCAN_GPIO_LIST(kscan_matrix_rows_##n), \
|
||||
.cols = KSCAN_GPIO_LIST(kscan_matrix_cols_##n), \
|
||||
.inputs = \
|
||||
KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_cols_##n), (kscan_matrix_rows_##n))), \
|
||||
.outputs = \
|
||||
KSCAN_GPIO_LIST(COND_DIODE_DIR(n, (kscan_matrix_rows_##n), (kscan_matrix_cols_##n))), \
|
||||
.debounce_config = \
|
||||
{ \
|
||||
.debounce_press_ms = INST_DEBOUNCE_PRESS_MS(index), \
|
||||
.debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(index), \
|
||||
.debounce_press_ms = INST_DEBOUNCE_PRESS_MS(n), \
|
||||
.debounce_release_ms = INST_DEBOUNCE_RELEASE_MS(n), \
|
||||
}, \
|
||||
.debounce_scan_period_ms = DT_INST_PROP(index, debounce_scan_period_ms), \
|
||||
.poll_period_ms = DT_INST_PROP(index, poll_period_ms), \
|
||||
.diode_direction = INST_DIODE_DIR(index), \
|
||||
.debounce_scan_period_ms = DT_INST_PROP(n, debounce_scan_period_ms), \
|
||||
.poll_period_ms = DT_INST_PROP(n, poll_period_ms), \
|
||||
.diode_direction = INST_DIODE_DIR(n), \
|
||||
}; \
|
||||
\
|
||||
DEVICE_DT_INST_DEFINE(index, &kscan_matrix_init, NULL, &kscan_matrix_data_##index, \
|
||||
&kscan_matrix_config_##index, APPLICATION, \
|
||||
CONFIG_APPLICATION_INIT_PRIORITY, &kscan_matrix_api);
|
||||
DEVICE_DT_INST_DEFINE(n, &kscan_matrix_init, NULL, &kscan_matrix_data_##n, \
|
||||
&kscan_matrix_config_##n, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, \
|
||||
&kscan_matrix_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KSCAN_MATRIX_INIT);
|
||||
|
|
33
app/drivers/zephyr/dts/bindings/gpio/zmk,gpio-595.yaml
Normal file
33
app/drivers/zephyr/dts/bindings/gpio/zmk,gpio-595.yaml
Normal file
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# Copyright (c) 2022 The ZMK Contributors
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
|
||||
description: >
|
||||
This is a representation of the 595 Shift Register.
|
||||
|
||||
compatible: "zmk,gpio-595"
|
||||
|
||||
include: [gpio-controller.yaml, spi-device.yaml]
|
||||
|
||||
properties:
|
||||
label:
|
||||
required: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
ngpios:
|
||||
type: int
|
||||
required: true
|
||||
enum:
|
||||
- 8
|
||||
- 16
|
||||
- 24
|
||||
- 32
|
||||
description: Number of gpios supported
|
||||
|
||||
gpio-cells:
|
||||
- pin
|
||||
- flags
|
|
@ -12,5 +12,26 @@ properties:
|
|||
type: phandle-array
|
||||
required: true
|
||||
debounce-period:
|
||||
type: int
|
||||
required: false
|
||||
deprecated: true
|
||||
description: Deprecated. Use debounce-press-ms and debounce-release-ms instead.
|
||||
debounce-press-ms:
|
||||
type: int
|
||||
default: 5
|
||||
description: Debounce time for key press in milliseconds. Use 0 for eager debouncing.
|
||||
debounce-release-ms:
|
||||
type: int
|
||||
default: 5
|
||||
description: Debounce time for key release in milliseconds.
|
||||
debounce-scan-period-ms:
|
||||
type: int
|
||||
default: 1
|
||||
description: Time between reads in milliseconds when any key is pressed.
|
||||
poll-period-ms:
|
||||
type: int
|
||||
default: 10
|
||||
description: Time between reads in milliseconds when no key is pressed and ZMK_KSCAN_DIRECT_POLLING is enabled.
|
||||
toggle-mode:
|
||||
type: boolean
|
||||
description: Enable toggle-switch mode.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <behaviors/key_press.dtsi>
|
||||
#include <behaviors/key_toggle.dtsi>
|
||||
#include <behaviors/transparent.dtsi>
|
||||
#include <behaviors/none.dtsi>
|
||||
#include <behaviors/mod_tap.dtsi>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
compatible = "zmk,behavior-caps-word";
|
||||
label = "CAPS_WORD";
|
||||
#binding-cells = <0>;
|
||||
continue-list = <UNDERSCORE>;
|
||||
continue-list = <UNDERSCORE BACKSPACE DELETE>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
15
app/dts/behaviors/key_toggle.dtsi
Normal file
15
app/dts/behaviors/key_toggle.dtsi
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
/omit-if-no-ref/ kt: behavior_key_toggle {
|
||||
compatible = "zmk,behavior-key-toggle";
|
||||
label = "KEY_TOGGLE";
|
||||
#binding-cells = <1>;
|
||||
};
|
||||
};
|
||||
};
|
8
app/dts/bindings/behaviors/zmk,behavior-key-toggle.yaml
Normal file
8
app/dts/bindings/behaviors/zmk,behavior-key-toggle.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Key toggle behavior
|
||||
|
||||
compatible: "zmk,behavior-key-toggle"
|
||||
|
||||
include: one_param.yaml
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright (c) 2020 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Keyboard Reset Behavior
|
||||
description: Mod Morph Behavior
|
||||
|
||||
compatible: "zmk,behavior-mod-morph"
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
#define ZMK_HID_USAGE(page, id) ((page << 16) | id)
|
||||
#define ZMK_HID_USAGE_ID(usage) (usage & 0xFFFF)
|
||||
#define ZMK_HID_USAGE_PAGE(usage) (usage >> 16)
|
||||
#define ZMK_HID_USAGE_PAGE(usage) ((usage >> 16) & 0xFF)
|
||||
|
||||
/* WARNING: DEPRECATED from dt-bindings/zmk/keys.h */
|
||||
#define USAGE_KEYPAD (0x07) // WARNING: DEPRECATED (DO NOT USE)
|
||||
|
|
|
@ -930,7 +930,7 @@
|
|||
|
||||
/* Consumer Closed Caption */
|
||||
#define C_CAPTIONS (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_CLOSED_CAPTION))
|
||||
#define C_SUBTITILES (C_CAPTIONS)
|
||||
#define C_SUBTITLES (C_CAPTIONS)
|
||||
|
||||
/* Consumer Snapshot */
|
||||
#define C_SNAPSHOT (ZMK_HID_USAGE(HID_USAGE_CONSUMER, HID_USAGE_CONSUMER_SNAPSHOT))
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#define ZMK_BLE_IS_CENTRAL \
|
||||
(IS_ENABLED(CONFIG_ZMK_SPLIT) && IS_ENABLED(CONFIG_ZMK_BLE) && \
|
||||
IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))
|
||||
IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL))
|
||||
|
||||
#if ZMK_BLE_IS_CENTRAL
|
||||
#define ZMK_BLE_PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
|
||||
|
@ -33,6 +33,6 @@ char *zmk_ble_active_profile_name();
|
|||
|
||||
int zmk_ble_unpair_all();
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr);
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
||||
|
|
19
app/include/zmk/display/widgets/peripheral_status.h
Normal file
19
app/include/zmk/display/widgets/peripheral_status.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <lvgl.h>
|
||||
#include <kernel.h>
|
||||
|
||||
struct zmk_widget_peripheral_status {
|
||||
sys_snode_t node;
|
||||
lv_obj_t *obj;
|
||||
};
|
||||
|
||||
int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget,
|
||||
lv_obj_t *parent);
|
||||
lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget);
|
|
@ -23,7 +23,7 @@ ZMK_EVENT_DECLARE(zmk_keycode_state_changed);
|
|||
|
||||
static inline struct zmk_keycode_state_changed_event *
|
||||
zmk_keycode_state_changed_from_encoded(uint32_t encoded, bool pressed, int64_t timestamp) {
|
||||
uint16_t page = ZMK_HID_USAGE_PAGE(encoded) & 0xFF;
|
||||
uint16_t page = ZMK_HID_USAGE_PAGE(encoded);
|
||||
uint16_t id = ZMK_HID_USAGE_ID(encoded);
|
||||
uint8_t implicit_modifiers = 0x00;
|
||||
uint8_t explicit_modifiers = 0x00;
|
||||
|
|
16
app/include/zmk/events/split_peripheral_status_changed.h
Normal file
16
app/include/zmk/events/split_peripheral_status_changed.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <zmk/event_manager.h>
|
||||
|
||||
struct zmk_split_peripheral_status_changed {
|
||||
bool connected;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_split_peripheral_status_changed);
|
|
@ -129,17 +129,26 @@ struct zmk_hid_consumer_report {
|
|||
zmk_mod_flags_t zmk_hid_get_explicit_mods();
|
||||
int zmk_hid_register_mod(zmk_mod_t modifier);
|
||||
int zmk_hid_unregister_mod(zmk_mod_t modifier);
|
||||
bool zmk_hid_mod_is_pressed(zmk_mod_t modifier);
|
||||
|
||||
int zmk_hid_register_mods(zmk_mod_flags_t explicit_modifiers);
|
||||
int zmk_hid_unregister_mods(zmk_mod_flags_t explicit_modifiers);
|
||||
int zmk_hid_implicit_modifiers_press(zmk_mod_flags_t implicit_modifiers);
|
||||
int zmk_hid_implicit_modifiers_release();
|
||||
|
||||
int zmk_hid_keyboard_press(zmk_key_t key);
|
||||
int zmk_hid_keyboard_release(zmk_key_t key);
|
||||
void zmk_hid_keyboard_clear();
|
||||
bool zmk_hid_keyboard_is_pressed(zmk_key_t key);
|
||||
|
||||
int zmk_hid_consumer_press(zmk_key_t key);
|
||||
int zmk_hid_consumer_release(zmk_key_t key);
|
||||
void zmk_hid_consumer_clear();
|
||||
bool zmk_hid_consumer_is_pressed(zmk_key_t key);
|
||||
|
||||
int zmk_hid_press(uint32_t usage);
|
||||
int zmk_hid_release(uint32_t usage);
|
||||
bool zmk_hid_is_pressed(uint32_t usage);
|
||||
|
||||
struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report();
|
||||
struct zmk_hid_consumer_report *zmk_hid_get_consumer_report();
|
||||
|
|
9
app/include/zmk/split/bluetooth/peripheral.h
Normal file
9
app/include/zmk/split/bluetooth/peripheral.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
bool zmk_split_bt_peripheral_is_connected(void);
|
|
@ -68,9 +68,9 @@ void activity_work_handler(struct k_work *work) {
|
|||
int32_t inactive_time = current - activity_last_uptime;
|
||||
#if IS_ENABLED(CONFIG_ZMK_SLEEP)
|
||||
if (inactive_time > MAX_SLEEP_MS && !is_usb_power_present()) {
|
||||
// Put devices in low power mode before sleeping
|
||||
// Put devices in suspend power mode before sleeping
|
||||
set_state(ZMK_ACTIVITY_SLEEP);
|
||||
pm_power_state_set((struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
pm_power_state_force(0U, (struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0});
|
||||
} else
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SLEEP) */
|
||||
if (inactive_time > MAX_IDLE_MS) {
|
||||
|
|
|
@ -91,7 +91,9 @@ static int zmk_backlight_init(const struct device *_arg) {
|
|||
LOG_ERR("Failed to load backlight settings: %d", rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB)
|
||||
state.on = zmk_usb_is_powered();
|
||||
#endif
|
||||
return zmk_backlight_update();
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ static int zmk_battery_init(const struct device *_arg) {
|
|||
return rc;
|
||||
}
|
||||
|
||||
k_timer_start(&battery_timer, K_MINUTES(1), K_MINUTES(1));
|
||||
k_timer_start(&battery_timer, K_MINUTES(1), K_SECONDS(CONFIG_ZMK_BATTERY_REPORT_INTERVAL));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <zmk/events/position_state_changed.h>
|
||||
#include <zmk/events/keycode_state_changed.h>
|
||||
#include <zmk/events/modifiers_state_changed.h>
|
||||
#include <zmk/keys.h>
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
|
@ -92,7 +93,9 @@ static bool caps_word_is_caps_includelist(const struct behavior_caps_word_config
|
|||
continuation->id, continuation->implicit_modifiers);
|
||||
|
||||
if (continuation->page == usage_page && continuation->id == usage_id &&
|
||||
continuation->implicit_modifiers == implicit_modifiers) {
|
||||
(continuation->implicit_modifiers &
|
||||
(implicit_modifiers | zmk_hid_get_explicit_mods())) ==
|
||||
continuation->implicit_modifiers) {
|
||||
LOG_DBG("Continuing capsword, found included usage: 0x%02X - 0x%02X", usage_page,
|
||||
usage_id);
|
||||
return true;
|
||||
|
@ -143,6 +146,7 @@ static int caps_word_keycode_state_changed_listener(const zmk_event_t *eh) {
|
|||
caps_word_enhance_usage(config, ev);
|
||||
|
||||
if (!caps_word_is_alpha(ev->keycode) && !caps_word_is_numeric(ev->keycode) &&
|
||||
!is_mod(ev->usage_page, ev->keycode) &&
|
||||
!caps_word_is_caps_includelist(config, ev->usage_page, ev->keycode,
|
||||
ev->implicit_modifiers)) {
|
||||
LOG_DBG("Deactivating caps_word for 0x%02X - 0x%02X", ev->usage_page, ev->keycode);
|
||||
|
@ -162,7 +166,7 @@ static int behavior_caps_word_init(const struct device *dev) {
|
|||
#define CAPS_WORD_LABEL(i, _n) DT_INST_LABEL(i)
|
||||
|
||||
#define PARSE_BREAK(i) \
|
||||
{.page = (ZMK_HID_USAGE_PAGE(i) & 0xFF), \
|
||||
{.page = ZMK_HID_USAGE_PAGE(i), \
|
||||
.id = ZMK_HID_USAGE_ID(i), \
|
||||
.implicit_modifiers = SELECT_MODS(i)},
|
||||
|
||||
|
|
44
app/src/behaviors/behavior_key_toggle.c
Normal file
44
app/src/behaviors/behavior_key_toggle.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT zmk_behavior_key_toggle
|
||||
|
||||
#include <device.h>
|
||||
#include <drivers/behavior.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#include <zmk/hid.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/keycode_state_changed.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
static int behavior_key_toggle_init(const struct device *dev) { return 0; }
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
LOG_DBG("position %d keycode 0x%02X", event.position, binding->param1);
|
||||
bool pressed = zmk_hid_is_pressed(binding->param1);
|
||||
return ZMK_EVENT_RAISE(
|
||||
zmk_keycode_state_changed_from_encoded(binding->param1, !pressed, event.timestamp));
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_key_toggle_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed,
|
||||
.binding_released = on_keymap_binding_released,
|
||||
};
|
||||
|
||||
#define KT_INST(n) \
|
||||
DEVICE_DT_INST_DEFINE(n, behavior_key_toggle_init, NULL, NULL, NULL, APPLICATION, \
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_key_toggle_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(KT_INST)
|
|
@ -199,7 +199,7 @@ static int sticky_key_keycode_state_changed_listener(const zmk_event_t *eh) {
|
|||
|
||||
if (strcmp(sticky_key->config->behavior.behavior_dev, "KEY_PRESS") == 0 &&
|
||||
ZMK_HID_USAGE_ID(sticky_key->param1) == ev->keycode &&
|
||||
(ZMK_HID_USAGE_PAGE(sticky_key->param1) & 0xFF) == ev->usage_page &&
|
||||
ZMK_HID_USAGE_PAGE(sticky_key->param1) == ev->usage_page &&
|
||||
SELECT_MODS(sticky_key->param1) == ev->implicit_modifiers) {
|
||||
// don't catch key down events generated by the sticky key behavior itself
|
||||
continue;
|
||||
|
|
|
@ -36,14 +36,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/ble_active_profile_changed.h>
|
||||
|
||||
#define IS_HOST_PERIPHERAL \
|
||||
(!IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))
|
||||
#define IS_SPLIT_PERIPHERAL \
|
||||
(IS_ENABLED(CONFIG_ZMK_SPLIT) && !IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL))
|
||||
|
||||
#define DO_PASSKEY_ENTRY (IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) && !IS_SPLIT_PERIPHERAL)
|
||||
|
||||
#if DO_PASSKEY_ENTRY
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||
#include <zmk/events/keycode_state_changed.h>
|
||||
|
||||
#define PASSKEY_DIGITS 6
|
||||
|
@ -52,9 +45,9 @@ static struct bt_conn *auth_passkey_entry_conn;
|
|||
static uint8_t passkey_entries[PASSKEY_DIGITS] = {};
|
||||
static uint8_t passkey_digit = 0;
|
||||
|
||||
#endif
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
#define PROFILE_COUNT (CONFIG_BT_MAX_PAIRED - 1)
|
||||
#else
|
||||
#define PROFILE_COUNT CONFIG_BT_MAX_PAIRED
|
||||
|
@ -81,27 +74,19 @@ static uint8_t active_profile;
|
|||
BUILD_ASSERT(DEVICE_NAME_LEN <= 16, "ERROR: BLE device name is too long. Max length: 16");
|
||||
|
||||
static const struct bt_data zmk_ble_ad[] = {
|
||||
#if IS_HOST_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_HOST_PERIPHERAL
|
||||
0x12, 0x18, /* HID Service */
|
||||
#endif
|
||||
0x0f, 0x18 /* Battery Service */
|
||||
BT_DATA_BYTES(BT_DATA_UUID16_SOME, 0x12, 0x18, /* HID Service */
|
||||
0x0f, 0x18 /* Battery Service */
|
||||
),
|
||||
#if IS_SPLIT_PERIPHERAL
|
||||
BT_DATA_BYTES(BT_DATA_UUID128_ALL, ZMK_SPLIT_BT_SERVICE_UUID)
|
||||
#endif
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
|
||||
static bt_addr_le_t peripheral_addr;
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
||||
|
||||
static void raise_profile_changed_event() {
|
||||
ZMK_EVENT_RAISE(new_zmk_ble_active_profile_changed((struct zmk_ble_active_profile_changed){
|
||||
|
@ -293,14 +278,14 @@ bt_addr_le_t *zmk_ble_active_profile_addr() { return &profiles[active_profile].p
|
|||
|
||||
char *zmk_ble_active_profile_name() { return profiles[active_profile].name; }
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
|
||||
void zmk_ble_set_peripheral_addr(bt_addr_le_t *addr) {
|
||||
memcpy(&peripheral_addr, addr, sizeof(bt_addr_le_t));
|
||||
settings_save_one("ble/peripheral_address", addr, sizeof(bt_addr_le_t));
|
||||
}
|
||||
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL) */
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL) */
|
||||
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
|
||||
|
@ -351,7 +336,7 @@ static int ble_profiles_handle_set(const char *name, size_t len, settings_read_c
|
|||
return err;
|
||||
}
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
else if (settings_name_steq(name, "peripheral_address", &next) && !next) {
|
||||
if (len != sizeof(bt_addr_le_t)) {
|
||||
return -EINVAL;
|
||||
|
@ -473,7 +458,7 @@ static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey) {
|
|||
}
|
||||
*/
|
||||
|
||||
#if DO_PASSKEY_ENTRY
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||
|
||||
static void auth_passkey_entry(struct bt_conn *conn) {
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
@ -492,7 +477,7 @@ static void auth_cancel(struct bt_conn *conn) {
|
|||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
#if DO_PASSKEY_ENTRY
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||
if (auth_passkey_entry_conn) {
|
||||
bt_conn_unref(auth_passkey_entry_conn);
|
||||
auth_passkey_entry_conn = NULL;
|
||||
|
@ -504,7 +489,6 @@ static void auth_cancel(struct bt_conn *conn) {
|
|||
LOG_DBG("Pairing cancelled: %s", log_strdup(addr));
|
||||
}
|
||||
|
||||
#if IS_HOST_PERIPHERAL
|
||||
static enum bt_security_err auth_pairing_accept(struct bt_conn *conn,
|
||||
const struct bt_conn_pairing_feat *const feat) {
|
||||
struct bt_conn_info info;
|
||||
|
@ -518,7 +502,6 @@ static enum bt_security_err auth_pairing_accept(struct bt_conn *conn,
|
|||
|
||||
return BT_SECURITY_ERR_SUCCESS;
|
||||
};
|
||||
#endif /* IS_HOST_PERIPHERAL */
|
||||
|
||||
static void auth_pairing_complete(struct bt_conn *conn, bool bonded) {
|
||||
struct bt_conn_info info;
|
||||
|
@ -533,26 +516,22 @@ static void auth_pairing_complete(struct bt_conn *conn, bool bonded) {
|
|||
return;
|
||||
}
|
||||
|
||||
#if IS_HOST_PERIPHERAL
|
||||
if (!zmk_ble_active_profile_is_open()) {
|
||||
LOG_ERR("Pairing completed but current profile is not open: %s", log_strdup(addr));
|
||||
bt_unpair(BT_ID_DEFAULT, dst);
|
||||
return;
|
||||
}
|
||||
#endif /* IS_HOST_PERIPHERAL */
|
||||
|
||||
set_profile_address(active_profile, dst);
|
||||
update_advertising();
|
||||
};
|
||||
|
||||
static struct bt_conn_auth_cb zmk_ble_auth_cb_display = {
|
||||
#if IS_HOST_PERIPHERAL
|
||||
.pairing_accept = auth_pairing_accept,
|
||||
#endif /* IS_HOST_PERIPHERAL */
|
||||
.pairing_complete = auth_pairing_complete,
|
||||
// .passkey_display = auth_passkey_display,
|
||||
|
||||
#if DO_PASSKEY_ENTRY
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||
.passkey_entry = auth_passkey_entry,
|
||||
#endif
|
||||
.cancel = auth_cancel,
|
||||
|
@ -595,9 +574,7 @@ static int zmk_ble_init(const struct device *_arg) {
|
|||
#if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START)
|
||||
LOG_WRN("Clearing all existing BLE bond information from the keyboard");
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
bt_unpair(i, NULL);
|
||||
}
|
||||
bt_unpair(BT_ID_DEFAULT, NULL);
|
||||
|
||||
for (int i = 0; i < ZMK_BLE_PROFILE_COUNT; i++) {
|
||||
char setting_name[15];
|
||||
|
@ -618,21 +595,7 @@ static int zmk_ble_init(const struct device *_arg) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int zmk_ble_unpair_all() {
|
||||
int resp = 0;
|
||||
for (int i = BT_ID_DEFAULT; i < CONFIG_BT_ID_MAX; i++) {
|
||||
|
||||
int err = bt_unpair(BT_ID_DEFAULT, NULL);
|
||||
if (err) {
|
||||
resp = err;
|
||||
LOG_ERR("Failed to unpair devices (err %d)", err);
|
||||
}
|
||||
}
|
||||
|
||||
return resp;
|
||||
};
|
||||
|
||||
#if DO_PASSKEY_ENTRY
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY)
|
||||
|
||||
static bool zmk_ble_numeric_usage_to_value(const zmk_key_t key, const zmk_key_t one,
|
||||
const zmk_key_t zero, uint32_t *value) {
|
||||
|
@ -705,6 +668,6 @@ static int zmk_ble_listener(const zmk_event_t *eh) {
|
|||
|
||||
ZMK_LISTENER(zmk_ble, zmk_ble_listener);
|
||||
ZMK_SUBSCRIPTION(zmk_ble, zmk_keycode_state_changed);
|
||||
#endif /* DO_PASSKEY_ENTRY */
|
||||
#endif /* IS_ENABLED(CONFIG_ZMK_BLE_PASSKEY_ENTRY) */
|
||||
|
||||
SYS_INIT(zmk_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define DT_DRV_COMPAT zmk_conditional_layers
|
||||
|
||||
#include <stdint.h>
|
||||
#include <kernel.h>
|
||||
|
||||
#include <devicetree.h>
|
||||
#include <logging/log.h>
|
||||
|
@ -19,6 +20,8 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
|
||||
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
|
||||
|
||||
static K_SEM_DEFINE(conditional_layer_sem, 1, 1);
|
||||
|
||||
// Conditional layer configuration that activates the specified then-layer when all if-layers are
|
||||
// active. With two if-layers, this is referred to as "tri-layer", and is commonly used to activate
|
||||
// a third "adjust" layer if and only if the "lower" and "raise" layers are both active.
|
||||
|
@ -66,22 +69,53 @@ static void conditional_layer_deactivate(int8_t layer) {
|
|||
}
|
||||
}
|
||||
|
||||
// On layer state changes, examines each conditional layer config to determine if then-layer in the
|
||||
// config should activate based on the currently active set of if-layers.
|
||||
static int layer_state_changed_listener(const zmk_event_t *ev) {
|
||||
for (int i = 0; i < NUM_CONDITIONAL_LAYER_CFGS; i++) {
|
||||
const struct conditional_layer_cfg *cfg = CONDITIONAL_LAYER_CFGS + i;
|
||||
zmk_keymap_layers_state_t mask = cfg->if_layers_state_mask;
|
||||
static bool conditional_layer_updates_needed;
|
||||
|
||||
// Activate then-layer if and only if all if-layers are already active. Note that we
|
||||
// reevaluate the current layer state for each config since activation of one layer can also
|
||||
// trigger activation of another.
|
||||
if ((zmk_keymap_layer_state() & mask) == mask) {
|
||||
conditional_layer_activate(cfg->then_layer);
|
||||
} else {
|
||||
conditional_layer_deactivate(cfg->then_layer);
|
||||
conditional_layer_updates_needed = true;
|
||||
|
||||
// Semaphore ensures we don't re-enter the loop in the middle of doing update, and
|
||||
// ensures that "waterfalling layer updates" are all processed to trigger subsequent
|
||||
// nested conditional layers properly.
|
||||
if (k_sem_take(&conditional_layer_sem, K_NO_WAIT) < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (conditional_layer_updates_needed) {
|
||||
int8_t max_then_layer = -1;
|
||||
uint32_t then_layers = 0;
|
||||
uint32_t then_layer_state = 0;
|
||||
|
||||
conditional_layer_updates_needed = false;
|
||||
|
||||
// On layer state changes, examines each conditional layer config to determine if then-layer
|
||||
// in the config should activate based on the currently active set of if-layers.
|
||||
for (int i = 0; i < NUM_CONDITIONAL_LAYER_CFGS; i++) {
|
||||
const struct conditional_layer_cfg *cfg = CONDITIONAL_LAYER_CFGS + i;
|
||||
zmk_keymap_layers_state_t mask = cfg->if_layers_state_mask;
|
||||
then_layers |= BIT(cfg->then_layer);
|
||||
max_then_layer = MAX(max_then_layer, cfg->then_layer);
|
||||
|
||||
// Activate then-layer if and only if all if-layers are already active. Note that we
|
||||
// reevaluate the current layer state for each config since activation of one layer can
|
||||
// also trigger activation of another.
|
||||
if ((zmk_keymap_layer_state() & mask) == mask) {
|
||||
then_layer_state |= BIT(cfg->then_layer);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t layer = 0; layer <= max_then_layer; layer++) {
|
||||
if ((BIT(layer) & then_layers) != 0U) {
|
||||
if ((BIT(layer) & then_layer_state) != 0U) {
|
||||
conditional_layer_activate(layer);
|
||||
} else {
|
||||
conditional_layer_deactivate(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
k_sem_give(&conditional_layer_sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <zmk/display/widgets/output_status.h>
|
||||
#include <zmk/display/widgets/peripheral_status.h>
|
||||
#include <zmk/display/widgets/battery_status.h>
|
||||
#include <zmk/display/widgets/layer_status.h>
|
||||
#include <zmk/display/widgets/wpm_status.h>
|
||||
|
@ -21,6 +22,10 @@ static struct zmk_widget_battery_status battery_status_widget;
|
|||
static struct zmk_widget_output_status output_status_widget;
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS)
|
||||
static struct zmk_widget_peripheral_status peripheral_status_widget;
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_WIDGET_LAYER_STATUS)
|
||||
static struct zmk_widget_layer_status layer_status_widget;
|
||||
#endif
|
||||
|
@ -46,6 +51,12 @@ lv_obj_t *zmk_display_status_screen() {
|
|||
0);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS)
|
||||
zmk_widget_peripheral_status_init(&peripheral_status_widget, screen);
|
||||
lv_obj_align(zmk_widget_peripheral_status_obj(&peripheral_status_widget), NULL,
|
||||
LV_ALIGN_IN_TOP_LEFT, 0, 0);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_WIDGET_LAYER_STATUS)
|
||||
zmk_widget_layer_status_init(&layer_status_widget, screen);
|
||||
lv_obj_set_style_local_text_font(zmk_widget_layer_status_obj(&layer_status_widget),
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
|
||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_BATTERY_STATUS app PRIVATE battery_status.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_OUTPUT_STATUS app PRIVATE output_status.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_PERIPHERAL_STATUS app PRIVATE peripheral_status.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_LAYER_STATUS app PRIVATE layer_status.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_WIDGET_WPM_STATUS app PRIVATE wpm_status.c)
|
||||
|
|
|
@ -6,7 +6,7 @@ menu "ZMK Display Widgets"
|
|||
config ZMK_WIDGET_LAYER_STATUS
|
||||
bool "Widget for highest, active layer using small icons"
|
||||
default y
|
||||
depends on !ZMK_SPLIT || ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
depends on !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL
|
||||
select LVGL_USE_LABEL
|
||||
|
||||
config ZMK_WIDGET_BATTERY_STATUS
|
||||
|
@ -17,13 +17,19 @@ config ZMK_WIDGET_BATTERY_STATUS
|
|||
|
||||
config ZMK_WIDGET_OUTPUT_STATUS
|
||||
bool "Widget for keyboard output status icons"
|
||||
depends on BT
|
||||
default y if BT
|
||||
depends on BT && (!ZMK_SPLIT_BLE || ZMK_SPLIT_ROLE_CENTRAL)
|
||||
default y if BT && (!ZMK_SPLIT_BLE || ZMK_SPLIT_ROLE_CENTRAL)
|
||||
select LVGL_USE_LABEL
|
||||
|
||||
config ZMK_WIDGET_PERIPHERAL_STATUS
|
||||
bool "Widget for split peripheral status icons"
|
||||
depends on BT && ZMK_SPLIT_BLE && !ZMK_SPLIT_ROLE_CENTRAL
|
||||
default y if BT && ZMK_SPLIT_BLE && !ZMK_SPLIT_ROLE_CENTRAL
|
||||
select LVGL_USE_LABEL
|
||||
|
||||
config ZMK_WIDGET_WPM_STATUS
|
||||
bool "Widget for displaying typed words per minute"
|
||||
depends on !ZMK_SPLIT || ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
depends on !ZMK_SPLIT || ZMK_SPLIT_ROLE_CENTRAL
|
||||
select LVGL_USE_LABEL
|
||||
select ZMK_WPM
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ ZMK_SUBSCRIPTION(widget_battery_status, zmk_usb_conn_state_changed);
|
|||
int zmk_widget_battery_status_init(struct zmk_widget_battery_status *widget, lv_obj_t *parent) {
|
||||
widget->obj = lv_label_create(parent, NULL);
|
||||
|
||||
lv_obj_set_size(widget->obj, 40, 15);
|
||||
lv_obj_set_size(widget->obj, 43, 15);
|
||||
|
||||
sys_slist_append(&widgets, &widget->node);
|
||||
|
||||
|
|
60
app/src/display/widgets/peripheral_status.c
Normal file
60
app/src/display/widgets/peripheral_status.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <bluetooth/services/bas.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/display.h>
|
||||
#include <zmk/display/widgets/peripheral_status.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/split/bluetooth/peripheral.h>
|
||||
#include <zmk/events/split_peripheral_status_changed.h>
|
||||
|
||||
static sys_slist_t widgets = SYS_SLIST_STATIC_INIT(&widgets);
|
||||
|
||||
struct peripheral_status_state {
|
||||
bool connected;
|
||||
};
|
||||
|
||||
static struct peripheral_status_state get_state(const zmk_event_t *_eh) {
|
||||
return (struct peripheral_status_state){.connected = zmk_split_bt_peripheral_is_connected()};
|
||||
}
|
||||
|
||||
static void set_status_symbol(lv_obj_t *label, struct peripheral_status_state state) {
|
||||
const char *text =
|
||||
state.connected ? (LV_SYMBOL_WIFI " " LV_SYMBOL_OK) : (LV_SYMBOL_WIFI " " LV_SYMBOL_CLOSE);
|
||||
|
||||
LOG_DBG("connected? %s", state.connected ? "true" : "false");
|
||||
lv_label_set_text(label, text);
|
||||
}
|
||||
|
||||
static void output_status_update_cb(struct peripheral_status_state state) {
|
||||
struct zmk_widget_peripheral_status *widget;
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&widgets, widget, node) { set_status_symbol(widget->obj, state); }
|
||||
}
|
||||
|
||||
ZMK_DISPLAY_WIDGET_LISTENER(widget_peripheral_status, struct peripheral_status_state,
|
||||
output_status_update_cb, get_state)
|
||||
ZMK_SUBSCRIPTION(widget_peripheral_status, zmk_split_peripheral_status_changed);
|
||||
|
||||
int zmk_widget_peripheral_status_init(struct zmk_widget_peripheral_status *widget,
|
||||
lv_obj_t *parent) {
|
||||
widget->obj = lv_label_create(parent, NULL);
|
||||
|
||||
lv_obj_set_size(widget->obj, 40, 15);
|
||||
|
||||
sys_slist_append(&widgets, &widget->node);
|
||||
|
||||
widget_peripheral_status_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
lv_obj_t *zmk_widget_peripheral_status_obj(struct zmk_widget_peripheral_status *widget) {
|
||||
return widget->obj;
|
||||
}
|
10
app/src/events/split_peripheral_status_changed.c
Normal file
10
app/src/events/split_peripheral_status_changed.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <kernel.h>
|
||||
#include <zmk/events/split_peripheral_status_changed.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_split_peripheral_status_changed);
|
|
@ -176,10 +176,10 @@ static int ext_power_generic_init(const struct device *dev) {
|
|||
#ifdef CONFIG_PM_DEVICE
|
||||
static int ext_power_generic_pm_action(const struct device *dev, enum pm_device_action action) {
|
||||
switch (action) {
|
||||
case PM_DEVICE_ACTION_TURN_ON:
|
||||
case PM_DEVICE_ACTION_RESUME:
|
||||
ext_power_generic_enable(dev);
|
||||
return 0;
|
||||
case PM_DEVICE_ACTION_TURN_OFF:
|
||||
case PM_DEVICE_ACTION_SUSPEND:
|
||||
ext_power_generic_disable(dev);
|
||||
return 0;
|
||||
default:
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "zmk/keys.h"
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
|
@ -55,6 +56,11 @@ int zmk_hid_unregister_mod(zmk_mod_t modifier) {
|
|||
return current == GET_MODIFIERS ? 0 : 1;
|
||||
}
|
||||
|
||||
bool zmk_hid_mod_is_pressed(zmk_mod_t modifier) {
|
||||
zmk_mod_flags_t mod_flag = 1 << modifier;
|
||||
return (zmk_hid_get_explicit_mods() & mod_flag) == mod_flag;
|
||||
}
|
||||
|
||||
int zmk_hid_register_mods(zmk_mod_flags_t modifiers) {
|
||||
int ret = 0;
|
||||
for (zmk_mod_t i = 0; i < 8; i++) {
|
||||
|
@ -96,6 +102,13 @@ static inline int deselect_keyboard_usage(zmk_key_t usage) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline bool check_keyboard_usage(zmk_key_t usage) {
|
||||
if (usage > ZMK_HID_KEYBOARD_NKRO_MAX_USAGE) {
|
||||
return false;
|
||||
}
|
||||
return keyboard_report.body.keys[usage / 8] & (1 << (usage % 8));
|
||||
}
|
||||
|
||||
#elif IS_ENABLED(CONFIG_ZMK_HID_REPORT_TYPE_HKRO)
|
||||
|
||||
#define TOGGLE_KEYBOARD(match, val) \
|
||||
|
@ -119,6 +132,15 @@ static inline int deselect_keyboard_usage(zmk_key_t usage) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int check_keyboard_usage(zmk_key_t usage) {
|
||||
for (int idx = 0; idx < CONFIG_ZMK_HID_KEYBOARD_REPORT_SIZE; idx++) {
|
||||
if (keyboard_report.body.keys[idx] == usage) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "A proper HID report type must be selected"
|
||||
#endif
|
||||
|
@ -164,6 +186,13 @@ int zmk_hid_keyboard_release(zmk_key_t code) {
|
|||
return 0;
|
||||
};
|
||||
|
||||
bool zmk_hid_keyboard_is_pressed(zmk_key_t code) {
|
||||
if (code >= HID_USAGE_KEY_KEYBOARD_LEFTCONTROL && code <= HID_USAGE_KEY_KEYBOARD_RIGHT_GUI) {
|
||||
return zmk_hid_mod_is_pressed(code - HID_USAGE_KEY_KEYBOARD_LEFTCONTROL);
|
||||
}
|
||||
return check_keyboard_usage(code);
|
||||
}
|
||||
|
||||
void zmk_hid_keyboard_clear() { memset(&keyboard_report.body, 0, sizeof(keyboard_report.body)); }
|
||||
|
||||
int zmk_hid_consumer_press(zmk_key_t code) {
|
||||
|
@ -178,6 +207,45 @@ int zmk_hid_consumer_release(zmk_key_t code) {
|
|||
|
||||
void zmk_hid_consumer_clear() { memset(&consumer_report.body, 0, sizeof(consumer_report.body)); }
|
||||
|
||||
bool zmk_hid_consumer_is_pressed(zmk_key_t key) {
|
||||
for (int idx = 0; idx < CONFIG_ZMK_HID_CONSUMER_REPORT_SIZE; idx++) {
|
||||
if (consumer_report.body.keys[idx] == key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int zmk_hid_press(uint32_t usage) {
|
||||
switch (ZMK_HID_USAGE_PAGE(usage)) {
|
||||
case HID_USAGE_KEY:
|
||||
return zmk_hid_keyboard_press(ZMK_HID_USAGE_ID(usage));
|
||||
case HID_USAGE_CONSUMER:
|
||||
return zmk_hid_consumer_press(ZMK_HID_USAGE_ID(usage));
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int zmk_hid_release(uint32_t usage) {
|
||||
switch (ZMK_HID_USAGE_PAGE(usage)) {
|
||||
case HID_USAGE_KEY:
|
||||
return zmk_hid_keyboard_release(ZMK_HID_USAGE_ID(usage));
|
||||
case HID_USAGE_CONSUMER:
|
||||
return zmk_hid_consumer_release(ZMK_HID_USAGE_ID(usage));
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bool zmk_hid_is_pressed(uint32_t usage) {
|
||||
switch (ZMK_HID_USAGE_PAGE(usage)) {
|
||||
case HID_USAGE_KEY:
|
||||
return zmk_hid_keyboard_is_pressed(ZMK_HID_USAGE_ID(usage));
|
||||
case HID_USAGE_CONSUMER:
|
||||
return zmk_hid_consumer_is_pressed(ZMK_HID_USAGE_ID(usage));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct zmk_hid_keyboard_report *zmk_hid_get_keyboard_report() {
|
||||
return &keyboard_report;
|
||||
}
|
||||
|
|
|
@ -21,21 +21,10 @@ static int hid_listener_keycode_pressed(const struct zmk_keycode_state_changed *
|
|||
|
||||
LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X",
|
||||
ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers);
|
||||
switch (ev->usage_page) {
|
||||
case HID_USAGE_KEY:
|
||||
err = zmk_hid_keyboard_press(ev->keycode);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to press keycode");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case HID_USAGE_CONSUMER:
|
||||
err = zmk_hid_consumer_press(ev->keycode);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to press keycode");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
err = zmk_hid_press(ZMK_HID_USAGE(ev->usage_page, ev->keycode));
|
||||
if (err < 0) {
|
||||
LOG_DBG("Unable to press keycode");
|
||||
return err;
|
||||
}
|
||||
explicit_mods_changed = zmk_hid_register_mods(ev->explicit_modifiers);
|
||||
implicit_mods_changed = zmk_hid_implicit_modifiers_press(ev->implicit_modifiers);
|
||||
|
@ -56,20 +45,10 @@ static int hid_listener_keycode_released(const struct zmk_keycode_state_changed
|
|||
|
||||
LOG_DBG("usage_page 0x%02X keycode 0x%02X implicit_mods 0x%02X explicit_mods 0x%02X",
|
||||
ev->usage_page, ev->keycode, ev->implicit_modifiers, ev->explicit_modifiers);
|
||||
switch (ev->usage_page) {
|
||||
case HID_USAGE_KEY:
|
||||
err = zmk_hid_keyboard_release(ev->keycode);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to release keycode");
|
||||
return err;
|
||||
}
|
||||
break;
|
||||
case HID_USAGE_CONSUMER:
|
||||
err = zmk_hid_consumer_release(ev->keycode);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Unable to release keycode");
|
||||
return err;
|
||||
}
|
||||
err = zmk_hid_release(ZMK_HID_USAGE(ev->usage_page, ev->keycode));
|
||||
if (err < 0) {
|
||||
LOG_DBG("Unable to release keycode");
|
||||
return err;
|
||||
}
|
||||
|
||||
explicit_mods_changed = zmk_hid_unregister_mods(ev->explicit_modifiers);
|
||||
|
@ -104,4 +83,4 @@ int hid_listener(const zmk_event_t *eh) {
|
|||
}
|
||||
|
||||
ZMK_LISTENER(hid_listener, hid_listener);
|
||||
ZMK_SUBSCRIPTION(hid_listener, zmk_keycode_state_changed);
|
||||
ZMK_SUBSCRIPTION(hid_listener, zmk_keycode_state_changed);
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
|
||||
#include <zmk/rgb_underglow.h>
|
||||
|
||||
#include <zmk/activity.h>
|
||||
#include <zmk/usb.h>
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/activity_state_changed.h>
|
||||
#include <zmk/events/usb_conn_state_changed.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#define STRIP_LABEL DT_LABEL(DT_CHOSEN(zmk_underglow))
|
||||
|
@ -265,7 +271,13 @@ static int zmk_rgb_underglow_init(const struct device *_arg) {
|
|||
settings_load_subtree("rgb/underglow");
|
||||
#endif
|
||||
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB)
|
||||
state.on = zmk_usb_is_powered();
|
||||
#endif
|
||||
|
||||
if (state.on) {
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -444,4 +456,53 @@ int zmk_rgb_underglow_change_spd(int direction) {
|
|||
return zmk_rgb_underglow_save_state();
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE) || \
|
||||
IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB)
|
||||
static int rgb_underglow_auto_state(bool *prev_state, bool new_state) {
|
||||
if (state.on == new_state) {
|
||||
return 0;
|
||||
}
|
||||
if (new_state) {
|
||||
state.on = *prev_state;
|
||||
*prev_state = false;
|
||||
return zmk_rgb_underglow_on();
|
||||
} else {
|
||||
state.on = false;
|
||||
*prev_state = true;
|
||||
return zmk_rgb_underglow_off();
|
||||
}
|
||||
}
|
||||
|
||||
static int rgb_underglow_event_listener(const zmk_event_t *eh) {
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE)
|
||||
if (as_zmk_activity_state_changed(eh)) {
|
||||
static bool prev_state = false;
|
||||
return rgb_underglow_auto_state(&prev_state,
|
||||
zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB)
|
||||
if (as_zmk_usb_conn_state_changed(eh)) {
|
||||
static bool prev_state = false;
|
||||
return rgb_underglow_auto_state(&prev_state, zmk_usb_is_powered());
|
||||
}
|
||||
#endif
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(rgb_underglow, rgb_underglow_event_listener);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE) ||
|
||||
// IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB)
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE)
|
||||
ZMK_SUBSCRIPTION(rgb_underglow, zmk_activity_state_changed);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB)
|
||||
ZMK_SUBSCRIPTION(rgb_underglow, zmk_usb_conn_state_changed);
|
||||
#endif
|
||||
|
||||
SYS_INIT(zmk_rgb_underglow_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
|
||||
|
|
6
app/src/split/CMakeLists.txt
Normal file
6
app/src/split/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if (CONFIG_ZMK_SPLIT_BLE)
|
||||
add_subdirectory(bluetooth)
|
||||
endif()
|
26
app/src/split/Kconfig
Normal file
26
app/src/split/Kconfig
Normal file
|
@ -0,0 +1,26 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
menuconfig ZMK_SPLIT
|
||||
bool "Split keyboard support"
|
||||
|
||||
if ZMK_SPLIT
|
||||
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
bool "Split central device"
|
||||
|
||||
choice ZMK_SPLIT_TRANSPORT
|
||||
prompt "Split transport"
|
||||
|
||||
config ZMK_SPLIT_BLE
|
||||
bool "BLE"
|
||||
depends on ZMK_BLE
|
||||
select BT_USER_PHY_UPDATE
|
||||
select BT_AUTO_PHY_UPDATE
|
||||
|
||||
endchoice
|
||||
|
||||
#ZMK_SPLIT
|
||||
endif
|
||||
|
||||
rsource "bluetooth/Kconfig"
|
11
app/src/split/bluetooth/CMakeLists.txt
Normal file
11
app/src/split/bluetooth/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if (NOT CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE split_listener.c)
|
||||
target_sources(app PRIVATE service.c)
|
||||
target_sources(app PRIVATE peripheral.c)
|
||||
endif()
|
||||
if (CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE central.c)
|
||||
endif()
|
95
app/src/split/bluetooth/Kconfig
Normal file
95
app/src/split/bluetooth/Kconfig
Normal file
|
@ -0,0 +1,95 @@
|
|||
# Copyright (c) 2022 The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
if ZMK_SPLIT && ZMK_SPLIT_BLE
|
||||
|
||||
menu "BLE Transport"
|
||||
|
||||
# Added for backwards compatibility. New shields/board should set `ZMK_SPLIT_ROLE_CENTRAL` only.
|
||||
config ZMK_SPLIT_BLE_ROLE_CENTRAL
|
||||
bool
|
||||
select ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
config ZMK_SPLIT_ROLE_CENTRAL
|
||||
select BT_CENTRAL
|
||||
select BT_GATT_CLIENT
|
||||
select BT_GATT_AUTO_DISCOVER_CCC
|
||||
|
||||
if ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
config ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE
|
||||
int "Max number of key position state events to queue when received from peripherals"
|
||||
default 5
|
||||
|
||||
config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_STACK_SIZE
|
||||
int "BLE split central write thread stack size"
|
||||
default 512
|
||||
|
||||
config ZMK_BLE_SPLIT_CENTRAL_SPLIT_RUN_QUEUE_SIZE
|
||||
int "Max number of behavior run events to queue to send to the peripheral(s)"
|
||||
default 5
|
||||
|
||||
endif # ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
if !ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE
|
||||
int "BLE split peripheral notify thread stack size"
|
||||
default 650
|
||||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_PRIORITY
|
||||
int "BLE split peripheral notify thread priority"
|
||||
default 5
|
||||
|
||||
config ZMK_SPLIT_BLE_PERIPHERAL_POSITION_QUEUE_SIZE
|
||||
int "Max number of key position state events to queue to send to the central"
|
||||
default 10
|
||||
|
||||
config ZMK_USB
|
||||
default n
|
||||
|
||||
config BT_MAX_PAIRED
|
||||
default 1
|
||||
|
||||
config BT_MAX_CONN
|
||||
default 1
|
||||
|
||||
config BT_PERIPHERAL_PREF_MAX_INT
|
||||
default 6
|
||||
|
||||
#!ZMK_SPLIT_ROLE_CENTRAL
|
||||
endif
|
||||
|
||||
endmenu
|
||||
|
||||
#ZMK_SPLIT_BLE
|
||||
endif
|
||||
|
||||
|
||||
if ZMK_BLE
|
||||
|
||||
if ZMK_SPLIT_BLE && ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
config BT_MAX_CONN
|
||||
default 6
|
||||
|
||||
config BT_MAX_PAIRED
|
||||
default 6
|
||||
|
||||
#ZMK_SPLIT_BLE && ZMK_SPLIT_ROLE_CENTRAL
|
||||
endif
|
||||
|
||||
if !ZMK_SPLIT_BLE
|
||||
|
||||
config BT_MAX_CONN
|
||||
default 5
|
||||
|
||||
config BT_MAX_PAIRED
|
||||
default 5
|
||||
|
||||
#!ZMK_SPLIT_BLE
|
||||
endif
|
||||
|
||||
#ZMK_BLE
|
||||
endif
|
||||
|
|
@ -54,6 +54,16 @@ static const struct bt_uuid_128 split_service_uuid = BT_UUID_INIT_128(ZMK_SPLIT_
|
|||
K_MSGQ_DEFINE(peripheral_event_msgq, sizeof(struct zmk_position_state_changed),
|
||||
CONFIG_ZMK_SPLIT_BLE_CENTRAL_POSITION_QUEUE_SIZE, 4);
|
||||
|
||||
void peripheral_event_work_callback(struct k_work *work) {
|
||||
struct zmk_position_state_changed ev;
|
||||
while (k_msgq_get(&peripheral_event_msgq, &ev, K_NO_WAIT) == 0) {
|
||||
LOG_DBG("Trigger key position state change for %d", ev.position);
|
||||
ZMK_EVENT_RAISE(new_zmk_position_state_changed(ev));
|
||||
}
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(peripheral_event_work, peripheral_event_work_callback);
|
||||
|
||||
int peripheral_slot_index_for_conn(struct bt_conn *conn) {
|
||||
for (int i = 0; i < ZMK_BLE_SPLIT_PERIPHERAL_COUNT; i++) {
|
||||
if (peripherals[i].conn == conn) {
|
||||
|
@ -92,6 +102,22 @@ int release_peripheral_slot(int index) {
|
|||
}
|
||||
slot->state = PERIPHERAL_SLOT_STATE_OPEN;
|
||||
|
||||
// Raise events releasing any active positions from this peripheral
|
||||
for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (slot->position_state[i] & BIT(j)) {
|
||||
uint32_t position = (i * 8) + j;
|
||||
struct zmk_position_state_changed ev = {.source = index,
|
||||
.position = position,
|
||||
.state = false,
|
||||
.timestamp = k_uptime_get()};
|
||||
|
||||
k_msgq_put(&peripheral_event_msgq, &ev, K_NO_WAIT);
|
||||
k_work_submit(&peripheral_event_work);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < POSITION_STATE_DATA_LEN; i++) {
|
||||
slot->position_state[i] = 0U;
|
||||
slot->changed_positions[i] = 0U;
|
||||
|
@ -136,16 +162,6 @@ int confirm_peripheral_slot_conn(struct bt_conn *conn) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void peripheral_event_work_callback(struct k_work *work) {
|
||||
struct zmk_position_state_changed ev;
|
||||
while (k_msgq_get(&peripheral_event_msgq, &ev, K_NO_WAIT) == 0) {
|
||||
LOG_DBG("Trigger key position state change for %d", ev.position);
|
||||
ZMK_EVENT_RAISE(new_zmk_position_state_changed(ev));
|
||||
}
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(peripheral_event_work, peripheral_event_work_callback);
|
||||
|
||||
static uint8_t split_central_notify_func(struct bt_conn *conn,
|
||||
struct bt_gatt_subscribe_params *params, const void *data,
|
||||
uint16_t length) {
|
||||
|
|
128
app/src/split/bluetooth/peripheral.c
Normal file
128
app/src/split/bluetooth/peripheral.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <device.h>
|
||||
#include <init.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <settings/settings.h>
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/conn.h>
|
||||
#include <bluetooth/hci.h>
|
||||
#include <bluetooth/uuid.h>
|
||||
#include <bluetooth/gatt.h>
|
||||
#include <bluetooth/hci_err.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
|
||||
#include <settings/settings.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include <logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/split_peripheral_status_changed.h>
|
||||
#include <zmk/ble.h>
|
||||
#include <zmk/split/bluetooth/uuid.h>
|
||||
|
||||
static const struct bt_data zmk_ble_ad[] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||
BT_DATA_BYTES(BT_DATA_UUID16_SOME, 0x0f, 0x18 /* Battery Service */
|
||||
),
|
||||
BT_DATA_BYTES(BT_DATA_UUID128_ALL, ZMK_SPLIT_BT_SERVICE_UUID)};
|
||||
|
||||
static bool is_connected = false;
|
||||
|
||||
static int start_advertising() {
|
||||
return bt_le_adv_start(BT_LE_ADV_CONN, zmk_ble_ad, ARRAY_SIZE(zmk_ble_ad), NULL, 0);
|
||||
};
|
||||
|
||||
static void connected(struct bt_conn *conn, uint8_t err) {
|
||||
is_connected = (err == 0);
|
||||
|
||||
ZMK_EVENT_RAISE(new_zmk_split_peripheral_status_changed(
|
||||
(struct zmk_split_peripheral_status_changed){.connected = is_connected}));
|
||||
}
|
||||
|
||||
static void disconnected(struct bt_conn *conn, uint8_t reason) {
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
LOG_DBG("Disconnected from %s (reason 0x%02x)", log_strdup(addr), reason);
|
||||
|
||||
is_connected = false;
|
||||
|
||||
ZMK_EVENT_RAISE(new_zmk_split_peripheral_status_changed(
|
||||
(struct zmk_split_peripheral_status_changed){.connected = is_connected}));
|
||||
}
|
||||
|
||||
static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err) {
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
if (!err) {
|
||||
LOG_DBG("Security changed: %s level %u", log_strdup(addr), level);
|
||||
} else {
|
||||
LOG_ERR("Security failed: %s level %u err %d", log_strdup(addr), level, err);
|
||||
}
|
||||
}
|
||||
|
||||
static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency,
|
||||
uint16_t timeout) {
|
||||
char addr[BT_ADDR_LE_STR_LEN];
|
||||
|
||||
bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
|
||||
|
||||
LOG_DBG("%s: interval %d latency %d timeout %d", log_strdup(addr), interval, latency, timeout);
|
||||
}
|
||||
|
||||
static struct bt_conn_cb conn_callbacks = {
|
||||
.connected = connected,
|
||||
.disconnected = disconnected,
|
||||
.security_changed = security_changed,
|
||||
.le_param_updated = le_param_updated,
|
||||
};
|
||||
|
||||
bool zmk_split_bt_peripheral_is_connected() { return is_connected; }
|
||||
|
||||
static int zmk_peripheral_ble_init(const struct device *_arg) {
|
||||
int err = bt_enable(NULL);
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("BLUETOOTH FAILED (%d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
settings_subsys_init();
|
||||
|
||||
settings_load_subtree("ble");
|
||||
settings_load_subtree("bt");
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE_CLEAR_BONDS_ON_START)
|
||||
LOG_WRN("Clearing all existing BLE bond information from the keyboard");
|
||||
|
||||
bt_unpair(BT_ID_DEFAULT, NULL);
|
||||
#endif
|
||||
|
||||
bt_conn_cb_register(&conn_callbacks);
|
||||
|
||||
start_advertising();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(zmk_peripheral_ble_init, APPLICATION, CONFIG_ZMK_BLE_INIT_PRIORITY);
|
|
@ -31,16 +31,16 @@ enum usb_dc_status_code zmk_usb_get_status() { return usb_status; }
|
|||
enum zmk_usb_conn_state zmk_usb_get_conn_state() {
|
||||
LOG_DBG("state: %d", usb_status);
|
||||
switch (usb_status) {
|
||||
case USB_DC_SUSPEND:
|
||||
case USB_DC_CONFIGURED:
|
||||
return ZMK_USB_CONN_HID;
|
||||
|
||||
case USB_DC_DISCONNECTED:
|
||||
case USB_DC_UNKNOWN:
|
||||
return ZMK_USB_CONN_NONE;
|
||||
|
||||
case USB_DC_ERROR:
|
||||
case USB_DC_RESET:
|
||||
return ZMK_USB_CONN_POWERED;
|
||||
|
||||
default:
|
||||
return ZMK_USB_CONN_HID;
|
||||
return ZMK_USB_CONN_POWERED;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
s/.*hid_listener_keycode_//p
|
||||
s/.*hid_implicit_modifiers_//p
|
||||
s/.*caps_word_enhance_usage/enhance_usage/p
|
||||
s/.*caps_word_is_caps_includelist/caps_includelist/p
|
|
@ -0,0 +1,20 @@
|
|||
enhance_usage: Enhancing usage 0x04 with modifiers: 0x02
|
||||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00
|
||||
press: Modifiers set to 0x02
|
||||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
release: Modifiers set to 0x00
|
||||
pressed: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00
|
||||
press: Modifiers set to 0x02
|
||||
caps_includelist: Comparing with 0x07 - 0x2D (with implicit mods: 0x02)
|
||||
caps_includelist: Continuing capsword, found included usage: 0x07 - 0x2D
|
||||
pressed: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00
|
||||
press: Modifiers set to 0x02
|
||||
released: usage_page 0x07 keycode 0x2D implicit_mods 0x00 explicit_mods 0x00
|
||||
release: Modifiers set to 0x02
|
||||
released: usage_page 0x07 keycode 0xE1 implicit_mods 0x00 explicit_mods 0x00
|
||||
release: Modifiers set to 0x00
|
||||
enhance_usage: Enhancing usage 0x04 with modifiers: 0x02
|
||||
pressed: usage_page 0x07 keycode 0x04 implicit_mods 0x02 explicit_mods 0x00
|
||||
press: Modifiers set to 0x02
|
||||
released: usage_page 0x07 keycode 0x04 implicit_mods 0x00 explicit_mods 0x00
|
||||
release: Modifiers set to 0x00
|
|
@ -0,0 +1,33 @@
|
|||
#include <dt-bindings/zmk/keys.h>
|
||||
#include <behaviors.dtsi>
|
||||
#include <dt-bindings/zmk/kscan_mock.h>
|
||||
#include "../behavior_keymap.dtsi"
|
||||
|
||||
/ {
|
||||
keymap {
|
||||
compatible = "zmk,keymap";
|
||||
label = "Default keymap";
|
||||
|
||||
default_layer {
|
||||
bindings = <
|
||||
&caps_word &kp A
|
||||
&kp LSHFT &kp MINUS
|
||||
>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&kscan {
|
||||
events = <
|
||||
ZMK_MOCK_PRESS(0,0,10)
|
||||
ZMK_MOCK_RELEASE(0,0,10)
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
ZMK_MOCK_PRESS(1,0,10)
|
||||
ZMK_MOCK_PRESS(1,1,10)
|
||||
ZMK_MOCK_RELEASE(1,1,10)
|
||||
ZMK_MOCK_RELEASE(1,0,10)
|
||||
ZMK_MOCK_PRESS(0,1,10)
|
||||
ZMK_MOCK_RELEASE(0,1,10)
|
||||
>;
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
s/.*hid_listener_keycode/kp/p
|
||||
s/.*mo_keymap_binding/mo/p
|
||||
s/.*conditional_layer/cl/p
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue