Compare commits
25 commits
main
...
rgb-modula
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f3c4d3929 | |||
| d94d1597c1 | |||
| 89a8f1e664 | |||
| 9ab9c4619f | |||
| aa79502d5a | |||
| a904f76092 | |||
|
|
28a1c4697e | ||
|
|
01f8f363f8 | ||
|
|
62dc6d8ec5 | ||
|
|
0f43eeb033 | ||
|
|
f178f86a54 | ||
|
|
aa151f7473 | ||
|
|
8999793d2f | ||
|
|
f20c011fc6 | ||
|
|
a1d67a4e92 | ||
|
|
bd5e07f842 | ||
|
|
886cd1025d | ||
|
|
9308ba806a | ||
|
|
da994be0ba | ||
|
|
0ca086a845 | ||
|
|
6f9a411793 | ||
|
|
01d0749411 | ||
|
|
e1fc10651c | ||
|
|
954253c6f5 | ||
|
|
319f03fd01 |
37 changed files with 1058 additions and 107 deletions
|
|
@ -11,6 +11,9 @@ project(zmk)
|
|||
|
||||
zephyr_linker_sources(SECTIONS include/linker/zmk-behaviors.ld)
|
||||
zephyr_linker_sources(RODATA include/linker/zmk-events.ld)
|
||||
if(CONFIG_ZMK_RGB_UNDERGLOW)
|
||||
zephyr_linker_sources(SECTIONS include/linker/zmk-rgb-effects.ld)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS)
|
||||
zephyr_linker_sources(DATA_SECTIONS include/linker/zmk-behavior-local-id-map.ld)
|
||||
|
|
@ -71,16 +74,12 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|||
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_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)
|
||||
target_sources_ifdef(CONFIG_ZMK_HID_INDICATORS app PRIVATE src/hid_indicators.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)
|
||||
|
|
@ -95,7 +94,15 @@ target_sources_ifdef(CONFIG_ZMK_BATTERY_REPORTING app PRIVATE src/battery.c)
|
|||
|
||||
target_sources_ifdef(CONFIG_ZMK_HID_INDICATORS app PRIVATE src/events/hid_indicators_changed.c)
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/events/ble_active_profile_changed.c)
|
||||
|
||||
target_sources_ifdef(CONFIG_ZMK_SPLIT app PRIVATE src/events/split_peripheral_status_changed.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_SPLIT app PRIVATE src/events/split_peripheral_layer_changed.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/endpoint_changed.c)
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_ZMK_SPLIT src/split)
|
||||
|
||||
target_sources_ifdef(CONFIG_USB_DEVICE_STACK app PRIVATE src/usb.c)
|
||||
|
|
|
|||
14
app/Kconfig
14
app/Kconfig
|
|
@ -322,8 +322,8 @@ config ZMK_RGB_UNDERGLOW_SPD_START
|
|||
range 1 5
|
||||
|
||||
config ZMK_RGB_UNDERGLOW_EFF_START
|
||||
int "RGB underglow start effect int value related to the effect enum list"
|
||||
range 0 3
|
||||
int "RGB underglow start effect index (clamped to available effects at runtime)"
|
||||
range 0 15
|
||||
|
||||
config ZMK_RGB_UNDERGLOW_ON_START
|
||||
bool "RGB underglow starts on by default"
|
||||
|
|
@ -435,6 +435,16 @@ config ZMK_GPIO_KEY_WAKEUP_TRIGGER
|
|||
depends on DT_HAS_ZMK_GPIO_KEY_WAKEUP_TRIGGER_ENABLED && ZMK_PM_SOFT_OFF
|
||||
|
||||
# Power Management
|
||||
if ZMK_EXT_POWER
|
||||
|
||||
config ZMK_EXT_POWER_START
|
||||
bool "Enable external power output by default"
|
||||
default y
|
||||
|
||||
#ZMK_EXT_POWER
|
||||
endif
|
||||
|
||||
#Power Management
|
||||
endmenu
|
||||
|
||||
menu "Combo options"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,14 @@
|
|||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
underglow-layer {
|
||||
compatible = "zmk,underglow-layer";
|
||||
pixel-lookup = <52>, <53>, <54>, <69>, <70>, <71>, <15>, <27>, <39>, <51>, <4>, <14>, <26>, <38>,
|
||||
<50>, <68>, <3>, <13>, <25>, <37>, <49>, <67>, <2>, <12>, <24>, <36>, <48>, <66>,
|
||||
<1>, <11>, <23>, <35>, <47>, <65>, <0>, <10>, <22>, <34>, <46>, <64>;
|
||||
};
|
||||
|
||||
|
||||
back_led_backlight: pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
pwm_led_0 {
|
||||
|
|
|
|||
|
|
@ -16,16 +16,32 @@ CONFIG_USB_DEVICE_VID=0x16c0
|
|||
CONFIG_USB_DEVICE_MANUFACTURER="MoErgo"
|
||||
CONFIG_USB_DEVICE_SN="moergo.com:GLV80-0123456789ABCDEF"
|
||||
|
||||
CONFIG_BT_DEVICE_NAME="Glove80"
|
||||
|
||||
CONFIG_BT_DIS_PNP_PID=0x27db
|
||||
CONFIG_BT_DIS_PNP_VID=0x16c0
|
||||
CONFIG_BT_DIS_MANUF="MoErgo"
|
||||
CONFIG_BT_DIS_MODEL="Glove80"
|
||||
|
||||
### Bluetooth configuration workarounds
|
||||
|
||||
# Use higher radio transmit power
|
||||
CONFIG_BT_CTLR_TX_PWR_PLUS_8=y
|
||||
|
||||
# Work-around for Windows bug with battery notifications
|
||||
CONFIG_BT_GATT_ENFORCE_SUBSCRIPTION=n
|
||||
|
||||
# Allow unauthenticated re-pairing for already paired hosts. This would permit
|
||||
# an attacker that can spoof the host's peer address to "steal" the keyboard
|
||||
# pairing by overwriting it, but without access to the previous keys it can't
|
||||
# establish a MITM, and the sudden loss of the keyboard would be very obvious to
|
||||
# the previously-connected host.
|
||||
CONFIG_BT_SMP_ALLOW_UNAUTH_OVERWRITE=y
|
||||
CONFIG_ZMK_BLE_PASSKEY_ENTRY=n
|
||||
|
||||
# Fetch peripheral battery level for status display reporting
|
||||
CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING=y
|
||||
|
||||
# Enable MPU
|
||||
CONFIG_ARM_MPU=y
|
||||
|
||||
|
|
@ -51,6 +67,9 @@ CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=y
|
|||
# Enable RGB underglow
|
||||
CONFIG_ZMK_RGB_UNDERGLOW=y
|
||||
|
||||
# disable EXT_POWER until underglow gets turned on
|
||||
CONFIG_ZMK_EXT_POWER_START=n
|
||||
|
||||
CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER=y
|
||||
CONFIG_ZMK_RGB_UNDERGLOW_ON_START=n
|
||||
CONFIG_ZMK_RGB_UNDERGLOW_BRT_STEP=4
|
||||
|
|
@ -79,6 +98,13 @@ CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB=y
|
|||
# space.
|
||||
CONFIG_ZMK_HID_CONSUMER_REPORT_USAGES_BASIC=y
|
||||
|
||||
# Enable USB boot protocol support
|
||||
CONFIG_ZMK_USB_BOOT=y
|
||||
CONFIG_ZMK_HID_INDICATORS=y
|
||||
|
||||
# Send HID indicator to peripherals
|
||||
CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS=y
|
||||
|
||||
# Turn on debugging to disable optimization. Debug messages can result in larger
|
||||
# stacks, so enable stack protection and particularly a larger BLE peripheral stack.
|
||||
# CONFIG_DEBUG=y
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@
|
|||
zmk,battery = &vbatt;
|
||||
};
|
||||
|
||||
underglow-layer {
|
||||
compatible = "zmk,underglow-layer";
|
||||
pixel-lookup = <57>, <56>, <55>, <74>, <73>, <72>, <16>, <28>, <40>, <58>, <5>, <17>, <29>, <41>,
|
||||
<59>, <75>, <6>, <18>, <30>, <42>, <60>, <76>, <7>, <19>, <31>, <43>, <61>, <77>,
|
||||
<8>, <20>, <32>, <44>, <62>, <78>, <9>, <21>, <33>, <45>, <63>, <79>;
|
||||
};
|
||||
|
||||
|
||||
back_led_backlight: pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
pwm_led_0 {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ CONFIG_ZMK_RGB_UNDERGLOW_HUE_START=285
|
|||
CONFIG_ZMK_RGB_UNDERGLOW_SAT_START=75
|
||||
CONFIG_ZMK_RGB_UNDERGLOW_BRT_START=16
|
||||
|
||||
# Enable HID indicators on peripheral
|
||||
CONFIG_ZMK_HID_INDICATORS=y
|
||||
CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS=y
|
||||
|
||||
# The power LED is implemented as a backlight
|
||||
# For now, the power LED is acting as a "USB connected" indicator
|
||||
CONFIG_ZMK_BACKLIGHT=y
|
||||
|
|
|
|||
|
|
@ -28,3 +28,6 @@
|
|||
#include <behaviors/soft_off.dtsi>
|
||||
#include <behaviors/studio_unlock.dtsi>
|
||||
#include <behaviors/mouse_keys.dtsi>
|
||||
#include <behaviors/ug_color.dtsi>
|
||||
#include <behaviors/ug_indicators.dtsi>
|
||||
#include <behaviors/ug_battery.dtsi>
|
||||
|
|
|
|||
34
app/dts/behaviors/ug_battery.dtsi
Normal file
34
app/dts/behaviors/ug_battery.dtsi
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
ug_b2: ugbat20 {
|
||||
compatible = "zmk,behavior-underglow-battery";
|
||||
threshold = <20>;
|
||||
#binding-cells = <2>;
|
||||
display-name = "Underglow Battery level 20%";
|
||||
};
|
||||
ug_b4: ugbat40 {
|
||||
compatible = "zmk,behavior-underglow-battery";
|
||||
threshold = <40>;
|
||||
#binding-cells = <2>;
|
||||
display-name = "Underglow Battery level 40%";
|
||||
};
|
||||
ug_b6: ugbat60 {
|
||||
compatible = "zmk,behavior-underglow-battery";
|
||||
threshold = <60>;
|
||||
#binding-cells = <2>;
|
||||
display-name = "Underglow Battery level 60%";
|
||||
};
|
||||
ug_b8: ugbat80 {
|
||||
compatible = "zmk,behavior-underglow-battery";
|
||||
threshold = <80>;
|
||||
#binding-cells = <2>;
|
||||
display-name = "Underglow Battery level 80%";
|
||||
};
|
||||
};
|
||||
};
|
||||
15
app/dts/behaviors/ug_color.dtsi
Normal file
15
app/dts/behaviors/ug_color.dtsi
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
ug: ugcolor {
|
||||
compatible = "zmk,behavior-underglow-color";
|
||||
#binding-cells = <1>;
|
||||
display-name = "Underglow Color";
|
||||
};
|
||||
};
|
||||
};
|
||||
33
app/dts/behaviors/ug_indicators.dtsi
Normal file
33
app/dts/behaviors/ug_indicators.dtsi
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <dt-bindings/zmk/hid_indicators.h>
|
||||
|
||||
/ {
|
||||
behaviors {
|
||||
ug_nl: ugnumlk {
|
||||
compatible = "zmk,behavior-underglow-indicators";
|
||||
indicator = <NUM_LOCK>;
|
||||
#binding-cells = <2>;
|
||||
display-name = "Underglow NumLock indicator";
|
||||
};
|
||||
|
||||
ug_cl: ugcapslk {
|
||||
compatible = "zmk,behavior-underglow-indicators";
|
||||
indicator = <CAPS_LOCK>;
|
||||
#binding-cells = <2>;
|
||||
display-name = "Underglow CapsLock indicator";
|
||||
};
|
||||
|
||||
ug_sl: ugscrllk {
|
||||
compatible = "zmk,behavior-underglow-indicators";
|
||||
indicator = <SCROLL_LOCK>;
|
||||
#binding-cells = <2>;
|
||||
display-name = "Underglow ScrollLock indicator";
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
35
app/dts/bindings/zmk,underglow-indicators.yaml
Normal file
35
app/dts/bindings/zmk,underglow-indicators.yaml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright (c) 2020, The ZMK Contributors
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
description: Underglow indicators
|
||||
|
||||
compatible: "zmk,underglow-indicators"
|
||||
|
||||
properties:
|
||||
bat-lhs:
|
||||
type: array
|
||||
required: true
|
||||
bat-rhs:
|
||||
type: array
|
||||
required: true
|
||||
capslock:
|
||||
type: int
|
||||
required: true
|
||||
numlock:
|
||||
type: int
|
||||
required: true
|
||||
scrolllock:
|
||||
type: int
|
||||
required: true
|
||||
layer-state:
|
||||
type: array
|
||||
required: true
|
||||
ble-state:
|
||||
type: array
|
||||
required: true
|
||||
usb-state:
|
||||
type: int
|
||||
required: true
|
||||
output-fallback:
|
||||
type: int
|
||||
required: true
|
||||
9
app/include/dt-bindings/zmk/hid_indicators.h
Normal file
9
app/include/dt-bindings/zmk/hid_indicators.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2020 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define NUM_LOCK 0
|
||||
#define CAPS_LOCK 1
|
||||
#define SCROLL_LOCK 2
|
||||
|
|
@ -19,6 +19,7 @@
|
|||
#define RGB_EFR_CMD 12
|
||||
#define RGB_EFS_CMD 13
|
||||
#define RGB_COLOR_HSB_CMD 14
|
||||
#define RGB_STATUS_CMD 15
|
||||
|
||||
#define RGB_TOG RGB_TOG_CMD 0
|
||||
#define RGB_ON RGB_ON_CMD 0
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
#define RGB_SPD RGB_SPD_CMD 0
|
||||
#define RGB_EFF RGB_EFF_CMD 0
|
||||
#define RGB_EFR RGB_EFR_CMD 0
|
||||
#define RGB_STATUS RGB_STATUS_CMD 0
|
||||
#define RGB_COLOR_HSB_VAL(h, s, v) (((h) << 16) + ((s) << 8) + (v))
|
||||
#define RGB_COLOR_HSB(h, s, v) RGB_COLOR_HSB_CMD##(RGB_COLOR_HSB_VAL(h, s, v))
|
||||
#define RGB_COLOR_HSV RGB_COLOR_HSB
|
||||
18
app/include/dt-bindings/zmk/rgb_colors.h
Normal file
18
app/include/dt-bindings/zmk/rgb_colors.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright (c) 2021 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#define GREEN 0x00ff00
|
||||
#define RED 0xff0000
|
||||
#define BLUE 0x0000ff
|
||||
#define TEAL 0x008080
|
||||
#define ORANGE 0xffa500
|
||||
#define YELLOW 0xffff00
|
||||
#define GOLD 0xffd700
|
||||
#define PURPLE 0x800080
|
||||
#define PINK 0xffc0cb
|
||||
#define WHITE 0xffffff
|
||||
#define ___ 0x000000
|
||||
#define BLACK 0x000000
|
||||
9
app/include/linker/zmk-rgb-effects.ld
Normal file
9
app/include/linker/zmk-rgb-effects.ld
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/linker/linker-defs.h>
|
||||
|
||||
ITERABLE_SECTION_ROM(zmk_rgb_effect, 4)
|
||||
|
|
@ -39,6 +39,7 @@ bool zmk_ble_profile_is_open(uint8_t index);
|
|||
bool zmk_ble_active_profile_is_open(void);
|
||||
bool zmk_ble_active_profile_is_connected(void);
|
||||
char *zmk_ble_active_profile_name(void);
|
||||
int8_t zmk_ble_profile_status(uint8_t index);
|
||||
|
||||
int zmk_ble_unpair_all(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ int zmk_endpoints_toggle_transport(void);
|
|||
*/
|
||||
struct zmk_endpoint_instance zmk_endpoints_selected(void);
|
||||
|
||||
bool zmk_endpoints_preferred_transport_is_active();
|
||||
|
||||
int zmk_endpoints_send_report(uint16_t usage_page);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_POINTING)
|
||||
|
|
|
|||
16
app/include/zmk/events/split_peripheral_layer_changed.h
Normal file
16
app/include/zmk/events/split_peripheral_layer_changed.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/event_manager.h>
|
||||
|
||||
struct zmk_split_peripheral_layer_changed {
|
||||
uint32_t layers;
|
||||
};
|
||||
|
||||
ZMK_EVENT_DECLARE(zmk_split_peripheral_layer_changed);
|
||||
47
app/include/zmk/rgb_effect.h
Normal file
47
app/include/zmk/rgb_effect.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2024 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <zephyr/drivers/led_strip.h>
|
||||
#include <zmk/rgb_underglow.h>
|
||||
|
||||
struct zmk_rgb_effect_ctx {
|
||||
struct led_rgb *pixels;
|
||||
uint16_t num_pixels;
|
||||
struct zmk_led_hsb base_color;
|
||||
uint16_t *animation_step;
|
||||
uint8_t animation_speed;
|
||||
};
|
||||
|
||||
typedef void (*zmk_rgb_effect_render_fn)(struct zmk_rgb_effect_ctx *ctx);
|
||||
typedef void (*zmk_rgb_effect_event_fn)(void);
|
||||
|
||||
#define ZMK_RGB_EFFECT_STATIC BIT(0)
|
||||
|
||||
struct zmk_rgb_effect {
|
||||
const char *name;
|
||||
zmk_rgb_effect_render_fn render;
|
||||
zmk_rgb_effect_event_fn on_select;
|
||||
zmk_rgb_effect_event_fn on_deselect;
|
||||
uint8_t flags;
|
||||
};
|
||||
|
||||
#define ZMK_RGB_EFFECT_DEFINE(_sym, _name_str, _render, _flags, _on_select, _on_deselect) \
|
||||
STRUCT_SECTION_ITERABLE(zmk_rgb_effect, _sym) = { \
|
||||
.name = _name_str, \
|
||||
.render = _render, \
|
||||
.flags = _flags, \
|
||||
.on_select = _on_select, \
|
||||
.on_deselect = _on_deselect, \
|
||||
}
|
||||
|
||||
void zmk_rgb_request_refresh(void);
|
||||
int zmk_rgb_effect_get_count(void);
|
||||
|
||||
struct led_rgb zmk_rgb_hsb_to_rgb(struct zmk_led_hsb hsb);
|
||||
struct zmk_led_hsb zmk_rgb_hsb_scale_min_max(struct zmk_led_hsb hsb);
|
||||
struct zmk_led_hsb zmk_rgb_hsb_scale_zero_max(struct zmk_led_hsb hsb);
|
||||
|
|
@ -16,6 +16,8 @@ int zmk_rgb_underglow_toggle(void);
|
|||
int zmk_rgb_underglow_get_state(bool *state);
|
||||
int zmk_rgb_underglow_on(void);
|
||||
int zmk_rgb_underglow_off(void);
|
||||
int zmk_rgb_underglow_transient_on(void);
|
||||
int zmk_rgb_underglow_transient_off(void);
|
||||
int zmk_rgb_underglow_cycle_effect(int direction);
|
||||
int zmk_rgb_underglow_calc_effect(int direction);
|
||||
int zmk_rgb_underglow_select_effect(int effect);
|
||||
|
|
@ -27,3 +29,4 @@ int zmk_rgb_underglow_change_sat(int direction);
|
|||
int zmk_rgb_underglow_change_brt(int direction);
|
||||
int zmk_rgb_underglow_change_spd(int direction);
|
||||
int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color);
|
||||
int zmk_rgb_underglow_status(void);
|
||||
|
|
|
|||
5
app/include/zmk/split/bluetooth/peripheral_layers.h
Normal file
5
app/include/zmk/split/bluetooth/peripheral_layers.h
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
void set_peripheral_layers_state(uint32_t new_layers);
|
||||
bool peripheral_layer_active(uint8_t layer);
|
||||
uint8_t peripheral_highest_layer_active(void);
|
||||
|
|
@ -20,3 +20,4 @@
|
|||
#define ZMK_SPLIT_BT_UPDATE_HID_INDICATORS_UUID ZMK_BT_SPLIT_UUID(0x00000004)
|
||||
#define ZMK_SPLIT_BT_SELECT_PHYS_LAYOUT_UUID ZMK_BT_SPLIT_UUID(0x00000005)
|
||||
#define ZMK_SPLIT_BT_INPUT_EVENT_UUID ZMK_BT_SPLIT_UUID(0x00000006)
|
||||
#define ZMK_SPLIT_BT_UPDATE_LAYERS_UUID ZMK_BT_SPLIT_UUID(0x00000007)
|
||||
|
|
|
|||
|
|
@ -46,3 +46,5 @@ int zmk_split_central_update_hid_indicator(zmk_hid_indicators_t indicators);
|
|||
int zmk_split_central_get_peripheral_battery_level(uint8_t source, uint8_t *level);
|
||||
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING)
|
||||
|
||||
int zmk_split_central_update_layers(uint32_t layers);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/activity_state_changed.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
#include <zmk/events/split_peripheral_layer_changed.h>
|
||||
#endif
|
||||
#include <zmk/events/sensor_event.h>
|
||||
|
||||
#include <zmk/pm.h>
|
||||
|
|
@ -109,6 +112,9 @@ static int activity_init(void) {
|
|||
ZMK_LISTENER(activity, activity_event_listener);
|
||||
ZMK_SUBSCRIPTION(activity, zmk_position_state_changed);
|
||||
ZMK_SUBSCRIPTION(activity, zmk_sensor_event);
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT)
|
||||
ZMK_SUBSCRIPTION(activity, zmk_split_peripheral_layer_changed);
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_POINTING)
|
||||
|
||||
|
|
|
|||
|
|
@ -242,6 +242,8 @@ static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
|||
return zmk_rgb_underglow_set_hsb((struct zmk_led_hsb){.h = (binding->param2 >> 16) & 0xFFFF,
|
||||
.s = (binding->param2 >> 8) & 0xFF,
|
||||
.b = binding->param2 & 0xFF});
|
||||
case RGB_STATUS_CMD:
|
||||
return zmk_rgb_underglow_status();
|
||||
}
|
||||
|
||||
return -ENOTSUP;
|
||||
|
|
|
|||
|
|
@ -143,6 +143,23 @@ bool zmk_ble_profile_is_connected(uint8_t index) {
|
|||
return info.state == BT_CONN_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
int8_t zmk_ble_profile_status(uint8_t index) {
|
||||
if (index >= ZMK_BLE_PROFILE_COUNT)
|
||||
return -1;
|
||||
bt_addr_le_t *addr = &profiles[index].peer;
|
||||
struct bt_conn *conn;
|
||||
int result;
|
||||
if (!bt_addr_le_cmp(addr, BT_ADDR_LE_ANY)) {
|
||||
result = 0; // disconnected
|
||||
} else if ((conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr)) == NULL) {
|
||||
result = 1; // paired
|
||||
} else {
|
||||
result = 2; // connected
|
||||
bt_conn_unref(conn);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define CHECKED_ADV_STOP() \
|
||||
err = bt_le_adv_stop(); \
|
||||
advertising_status = ZMK_ADV_NONE; \
|
||||
|
|
|
|||
|
|
@ -319,6 +319,10 @@ static struct zmk_endpoint_instance get_selected_instance(void) {
|
|||
return instance;
|
||||
}
|
||||
|
||||
bool zmk_endpoints_preferred_transport_is_active(void) {
|
||||
return preferred_transport == get_selected_transport();
|
||||
}
|
||||
|
||||
static int zmk_endpoints_init(void) {
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
k_work_init_delayable(&endpoints_save_work, endpoints_save_preferred_work);
|
||||
|
|
|
|||
10
app/src/events/split_peripheral_layer_changed.c
Normal file
10
app/src/events/split_peripheral_layer_changed.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zmk/events/split_peripheral_layer_changed.h>
|
||||
|
||||
ZMK_EVENT_IMPL(zmk_split_peripheral_layer_changed);
|
||||
|
|
@ -136,7 +136,11 @@ static int ext_power_settings_commit() {
|
|||
data->status = true;
|
||||
k_work_schedule(&ext_power_save_work, K_NO_WAIT);
|
||||
|
||||
if (IS_ENABLED(CONFIG_ZMK_EXT_POWER_START)) {
|
||||
ext_power_enable(dev);
|
||||
} else {
|
||||
ext_power_disable(dev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -162,8 +166,12 @@ static int ext_power_generic_init(const struct device *dev) {
|
|||
k_work_init_delayable(&ext_power_save_work, ext_power_save_state_work);
|
||||
#endif
|
||||
|
||||
// Enable by default. We may get disabled again once settings load.
|
||||
// Set to default state by default. This may change again once settings load.
|
||||
if (IS_ENABLED(CONFIG_ZMK_EXT_POWER_START)) {
|
||||
ext_power_enable(dev);
|
||||
} else {
|
||||
ext_power_disable(dev);
|
||||
}
|
||||
|
||||
if (config->init_delay_ms) {
|
||||
k_msleep(config->init_delay_ms);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/matrix.h>
|
||||
#include <zmk/sensors.h>
|
||||
#include <zmk/virtual_key_position.h>
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE)
|
||||
#include <zmk/split/central.h>
|
||||
#endif
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/position_state_changed.h>
|
||||
|
|
@ -155,6 +158,9 @@ static inline int set_layer_state(zmk_keymap_layer_id_t layer_id, bool state) {
|
|||
if (ret < 0) {
|
||||
LOG_WRN("Failed to raise layer state changed (%d)", ret);
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE)
|
||||
zmk_split_central_update_layers(_zmk_keymap_layer_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -12,20 +12,36 @@
|
|||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zmk/battery.h>
|
||||
#include <zmk/ble.h>
|
||||
#include <zmk/endpoints.h>
|
||||
#include <zmk/keymap.h>
|
||||
#include <zmk/matrix.h>
|
||||
#include <zmk/behavior.h>
|
||||
|
||||
#include <zmk/hid_indicators.h>
|
||||
#include <zmk/usb.h>
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <zephyr/drivers/led_strip.h>
|
||||
#include <drivers/ext_power.h>
|
||||
#include <drivers/behavior.h>
|
||||
|
||||
#include <zmk/rgb_underglow.h>
|
||||
#include <zmk/rgb_effect.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>
|
||||
|
||||
#include <zmk/workqueue.h>
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING)
|
||||
#include <zmk/split/central.h>
|
||||
#endif
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#if !DT_HAS_CHOSEN(zmk_underglow)
|
||||
|
|
@ -44,25 +60,20 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
BUILD_ASSERT(CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN <= CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX,
|
||||
"ERROR: RGB underglow maximum brightness is less than minimum brightness");
|
||||
|
||||
enum rgb_underglow_effect {
|
||||
UNDERGLOW_EFFECT_SOLID,
|
||||
UNDERGLOW_EFFECT_BREATHE,
|
||||
UNDERGLOW_EFFECT_SPECTRUM,
|
||||
UNDERGLOW_EFFECT_SWIRL,
|
||||
UNDERGLOW_EFFECT_NUMBER // Used to track number of underglow effects
|
||||
};
|
||||
|
||||
struct rgb_underglow_state {
|
||||
struct zmk_led_hsb color;
|
||||
uint8_t animation_speed;
|
||||
uint8_t current_effect;
|
||||
uint16_t animation_step;
|
||||
bool on;
|
||||
bool status_active;
|
||||
uint16_t status_animation_step;
|
||||
};
|
||||
|
||||
static const struct device *led_strip;
|
||||
|
||||
static struct led_rgb pixels[STRIP_NUM_PIXELS];
|
||||
static struct led_rgb status_pixels[STRIP_NUM_PIXELS];
|
||||
|
||||
static struct rgb_underglow_state state;
|
||||
|
||||
|
|
@ -70,18 +81,22 @@ static struct rgb_underglow_state state;
|
|||
static const struct device *const ext_power = DEVICE_DT_GET(DT_INST(0, zmk_ext_power_generic));
|
||||
#endif
|
||||
|
||||
static struct zmk_led_hsb hsb_scale_min_max(struct zmk_led_hsb hsb) {
|
||||
void zmk_rgb_set_ext_power(void);
|
||||
|
||||
/* --- Public utility functions for effects --- */
|
||||
|
||||
struct zmk_led_hsb zmk_rgb_hsb_scale_min_max(struct zmk_led_hsb hsb) {
|
||||
hsb.b = CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN +
|
||||
(CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX - CONFIG_ZMK_RGB_UNDERGLOW_BRT_MIN) * hsb.b / BRT_MAX;
|
||||
return hsb;
|
||||
}
|
||||
|
||||
static struct zmk_led_hsb hsb_scale_zero_max(struct zmk_led_hsb hsb) {
|
||||
struct zmk_led_hsb zmk_rgb_hsb_scale_zero_max(struct zmk_led_hsb hsb) {
|
||||
hsb.b = hsb.b * CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX / BRT_MAX;
|
||||
return hsb;
|
||||
}
|
||||
|
||||
static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) {
|
||||
struct led_rgb zmk_rgb_hsb_to_rgb(struct zmk_led_hsb hsb) {
|
||||
float r = 0, g = 0, b = 0;
|
||||
|
||||
uint8_t i = hsb.h / 60;
|
||||
|
|
@ -130,71 +145,318 @@ static struct led_rgb hsb_to_rgb(struct zmk_led_hsb hsb) {
|
|||
return rgb;
|
||||
}
|
||||
|
||||
static void zmk_rgb_underglow_effect_solid(void) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
pixels[i] = hsb_to_rgb(hsb_scale_min_max(state.color));
|
||||
/* --- Built-in effects --- */
|
||||
|
||||
static void effect_solid_render(struct zmk_rgb_effect_ctx *ctx) {
|
||||
for (int i = 0; i < ctx->num_pixels; i++) {
|
||||
ctx->pixels[i] = zmk_rgb_hsb_to_rgb(zmk_rgb_hsb_scale_min_max(ctx->base_color));
|
||||
}
|
||||
}
|
||||
|
||||
static void zmk_rgb_underglow_effect_breathe(void) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
struct zmk_led_hsb hsb = state.color;
|
||||
hsb.b = abs(state.animation_step - 1200) / 12;
|
||||
static void effect_breathe_render(struct zmk_rgb_effect_ctx *ctx) {
|
||||
for (int i = 0; i < ctx->num_pixels; i++) {
|
||||
struct zmk_led_hsb hsb = ctx->base_color;
|
||||
hsb.b = abs(*ctx->animation_step - 1200) / 12;
|
||||
|
||||
pixels[i] = hsb_to_rgb(hsb_scale_zero_max(hsb));
|
||||
ctx->pixels[i] = zmk_rgb_hsb_to_rgb(zmk_rgb_hsb_scale_zero_max(hsb));
|
||||
}
|
||||
|
||||
state.animation_step += state.animation_speed * 10;
|
||||
*ctx->animation_step += ctx->animation_speed * 10;
|
||||
|
||||
if (state.animation_step > 2400) {
|
||||
state.animation_step = 0;
|
||||
if (*ctx->animation_step > 2400) {
|
||||
*ctx->animation_step = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void zmk_rgb_underglow_effect_spectrum(void) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
struct zmk_led_hsb hsb = state.color;
|
||||
hsb.h = state.animation_step;
|
||||
static void effect_spectrum_render(struct zmk_rgb_effect_ctx *ctx) {
|
||||
for (int i = 0; i < ctx->num_pixels; i++) {
|
||||
struct zmk_led_hsb hsb = ctx->base_color;
|
||||
hsb.h = *ctx->animation_step;
|
||||
|
||||
pixels[i] = hsb_to_rgb(hsb_scale_min_max(hsb));
|
||||
ctx->pixels[i] = zmk_rgb_hsb_to_rgb(zmk_rgb_hsb_scale_min_max(hsb));
|
||||
}
|
||||
|
||||
state.animation_step += state.animation_speed;
|
||||
state.animation_step = state.animation_step % HUE_MAX;
|
||||
*ctx->animation_step += ctx->animation_speed;
|
||||
*ctx->animation_step = *ctx->animation_step % HUE_MAX;
|
||||
}
|
||||
|
||||
static void zmk_rgb_underglow_effect_swirl(void) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
struct zmk_led_hsb hsb = state.color;
|
||||
hsb.h = (HUE_MAX / STRIP_NUM_PIXELS * i + state.animation_step) % HUE_MAX;
|
||||
static void effect_swirl_render(struct zmk_rgb_effect_ctx *ctx) {
|
||||
for (int i = 0; i < ctx->num_pixels; i++) {
|
||||
struct zmk_led_hsb hsb = ctx->base_color;
|
||||
hsb.h = (HUE_MAX / ctx->num_pixels * i + *ctx->animation_step) % HUE_MAX;
|
||||
|
||||
pixels[i] = hsb_to_rgb(hsb_scale_min_max(hsb));
|
||||
ctx->pixels[i] = zmk_rgb_hsb_to_rgb(zmk_rgb_hsb_scale_min_max(hsb));
|
||||
}
|
||||
|
||||
state.animation_step += state.animation_speed * 2;
|
||||
state.animation_step = state.animation_step % HUE_MAX;
|
||||
*ctx->animation_step += ctx->animation_speed * 2;
|
||||
*ctx->animation_step = *ctx->animation_step % HUE_MAX;
|
||||
}
|
||||
|
||||
static void zmk_rgb_underglow_tick(struct k_work *work) {
|
||||
switch (state.current_effect) {
|
||||
case UNDERGLOW_EFFECT_SOLID:
|
||||
zmk_rgb_underglow_effect_solid();
|
||||
break;
|
||||
case UNDERGLOW_EFFECT_BREATHE:
|
||||
zmk_rgb_underglow_effect_breathe();
|
||||
break;
|
||||
case UNDERGLOW_EFFECT_SPECTRUM:
|
||||
zmk_rgb_underglow_effect_spectrum();
|
||||
break;
|
||||
case UNDERGLOW_EFFECT_SWIRL:
|
||||
zmk_rgb_underglow_effect_swirl();
|
||||
break;
|
||||
ZMK_RGB_EFFECT_DEFINE(effect_solid, "Solid", effect_solid_render, 0, NULL, NULL);
|
||||
ZMK_RGB_EFFECT_DEFINE(effect_breathe, "Breathe", effect_breathe_render, 0, NULL, NULL);
|
||||
ZMK_RGB_EFFECT_DEFINE(effect_spectrum, "Spectrum", effect_spectrum_render, 0, NULL, NULL);
|
||||
ZMK_RGB_EFFECT_DEFINE(effect_swirl, "Swirl", effect_swirl_render, 0, NULL, NULL);
|
||||
|
||||
/* --- Effect registry helpers --- */
|
||||
|
||||
int zmk_rgb_effect_get_count(void) {
|
||||
int count;
|
||||
STRUCT_SECTION_COUNT(zmk_rgb_effect, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct zmk_rgb_effect *zmk_rgb_effect_get(int index) {
|
||||
int count = zmk_rgb_effect_get_count();
|
||||
if (index < 0 || index >= count) {
|
||||
return NULL;
|
||||
}
|
||||
struct zmk_rgb_effect *effect;
|
||||
STRUCT_SECTION_GET(zmk_rgb_effect, index, &effect);
|
||||
return effect;
|
||||
}
|
||||
|
||||
/* --- Status indicator overlay (separate from effects) --- */
|
||||
|
||||
static int zmk_led_generate_status(void);
|
||||
|
||||
static void zmk_led_write_pixels(void) {
|
||||
static struct led_rgb led_buffer[STRIP_NUM_PIXELS];
|
||||
int bat0;
|
||||
int blend = 0;
|
||||
int reset_ext_power = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING)
|
||||
bat0 = zmk_battery_state_of_charge();
|
||||
#else
|
||||
bat0 = 100;
|
||||
#endif
|
||||
|
||||
if (state.status_active) {
|
||||
blend = zmk_led_generate_status();
|
||||
}
|
||||
|
||||
int err = led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
|
||||
if (blend == 0 && bat0 >= 20) {
|
||||
led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
|
||||
return;
|
||||
}
|
||||
if (bat0 < 10) {
|
||||
memset(pixels, 0, sizeof(struct led_rgb) * STRIP_NUM_PIXELS);
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
|
||||
if (state.on) {
|
||||
int c_power = ext_power_get(ext_power);
|
||||
if (c_power && !state.status_active) {
|
||||
state.on = false;
|
||||
reset_ext_power = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (blend == 0) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
led_buffer[i] = pixels[i];
|
||||
}
|
||||
} else if (blend >= 256) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
led_buffer[i] = status_pixels[i];
|
||||
}
|
||||
} else if (blend < 256) {
|
||||
uint16_t blend_l = blend;
|
||||
uint16_t blend_r = 256 - blend;
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
led_buffer[i].r =
|
||||
((status_pixels[i].r * blend_l) >> 8) + ((pixels[i].r * blend_r) >> 8);
|
||||
led_buffer[i].g =
|
||||
((status_pixels[i].g * blend_l) >> 8) + ((pixels[i].g * blend_r) >> 8);
|
||||
led_buffer[i].b =
|
||||
((status_pixels[i].b * blend_l) >> 8) + ((pixels[i].b * blend_r) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (bat0 < 20) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
led_buffer[i].r = led_buffer[i].r >> 1;
|
||||
led_buffer[i].g = led_buffer[i].g >> 1;
|
||||
led_buffer[i].b = led_buffer[i].b >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
int err = led_strip_update_rgb(led_strip, led_buffer, STRIP_NUM_PIXELS);
|
||||
if (err < 0) {
|
||||
LOG_ERR("Failed to update the RGB strip (%d)", err);
|
||||
}
|
||||
|
||||
if (reset_ext_power) {
|
||||
zmk_rgb_set_ext_power();
|
||||
}
|
||||
}
|
||||
|
||||
#define UNDERGLOW_INDICATORS DT_PATH(underglow_indicators)
|
||||
|
||||
#if defined(DT_N_S_underglow_indicators_EXISTS)
|
||||
#define UNDERGLOW_INDICATORS_ENABLED 1
|
||||
#define LEFT_HALF
|
||||
#else
|
||||
#define UNDERGLOW_INDICATORS_ENABLED 0
|
||||
#define RIGHT_HALF
|
||||
#endif
|
||||
|
||||
#if !UNDERGLOW_INDICATORS_ENABLED
|
||||
static int zmk_led_generate_status(void) { return 0; }
|
||||
#else
|
||||
const uint8_t underglow_layer_state[] = DT_PROP(UNDERGLOW_INDICATORS, layer_state);
|
||||
const uint8_t underglow_ble_state[] = DT_PROP(UNDERGLOW_INDICATORS, ble_state);
|
||||
const uint8_t underglow_bat_lhs[] = DT_PROP(UNDERGLOW_INDICATORS, bat_lhs);
|
||||
const uint8_t underglow_bat_rhs[] = DT_PROP(UNDERGLOW_INDICATORS, bat_rhs);
|
||||
|
||||
#define HEXRGB(R, G, B) \
|
||||
((struct led_rgb){ \
|
||||
r : (CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX * (R)) / 0xff, \
|
||||
g : (CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX * (G)) / 0xff, \
|
||||
b : (CONFIG_ZMK_RGB_UNDERGLOW_BRT_MAX * (B)) / 0xff \
|
||||
})
|
||||
|
||||
const struct led_rgb red = HEXRGB(0xff, 0x00, 0x00);
|
||||
const struct led_rgb yellow = HEXRGB(0xff, 0xff, 0x00);
|
||||
const struct led_rgb green = HEXRGB(0x00, 0xff, 0x00);
|
||||
const struct led_rgb dull_green = HEXRGB(0x00, 0xff, 0x68);
|
||||
const struct led_rgb magenta = HEXRGB(0xff, 0x00, 0xff);
|
||||
const struct led_rgb white = HEXRGB(0xff, 0xff, 0xff);
|
||||
const struct led_rgb lilac = HEXRGB(0x6b, 0x1f, 0xce);
|
||||
|
||||
static void zmk_led_battery_level(int bat_level, const uint8_t *addresses, size_t addresses_len) {
|
||||
struct led_rgb bat_colour;
|
||||
|
||||
if (bat_level > 40) {
|
||||
bat_colour = green;
|
||||
} else if (bat_level > 20) {
|
||||
bat_colour = yellow;
|
||||
} else {
|
||||
bat_colour = red;
|
||||
}
|
||||
|
||||
for (int i = 0; i < addresses_len; i++) {
|
||||
int min_level = (i * 100) / (addresses_len - 1);
|
||||
if (bat_level >= min_level) {
|
||||
status_pixels[addresses[i]] = bat_colour;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void zmk_led_fill(struct led_rgb color, const uint8_t *addresses, size_t addresses_len) {
|
||||
for (int i = 0; i < addresses_len; i++) {
|
||||
status_pixels[addresses[i]] = color;
|
||||
}
|
||||
}
|
||||
|
||||
#define ZMK_LED_NUMLOCK_BIT BIT(0)
|
||||
#define ZMK_LED_CAPSLOCK_BIT BIT(1)
|
||||
#define ZMK_LED_SCROLLLOCK_BIT BIT(2)
|
||||
|
||||
static int zmk_led_generate_status(void) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
status_pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING)
|
||||
zmk_led_battery_level(zmk_battery_state_of_charge(), underglow_bat_lhs,
|
||||
DT_PROP_LEN(UNDERGLOW_INDICATORS, bat_lhs));
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING)
|
||||
uint8_t peripheral_level = 0;
|
||||
int rc = zmk_split_central_get_peripheral_battery_level(0, &peripheral_level);
|
||||
|
||||
if (rc == 0) {
|
||||
zmk_led_battery_level(peripheral_level, underglow_bat_rhs,
|
||||
DT_PROP_LEN(UNDERGLOW_INDICATORS, bat_rhs));
|
||||
} else if (rc == -ENOTCONN) {
|
||||
zmk_led_fill(red, underglow_bat_rhs, DT_PROP_LEN(UNDERGLOW_INDICATORS, bat_rhs));
|
||||
} else if (rc == -EINVAL) {
|
||||
LOG_ERR("Invalid peripheral index requested for battery level read: 0");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
zmk_hid_indicators_t led_flags = zmk_hid_indicators_get_current_profile();
|
||||
|
||||
if (led_flags & ZMK_LED_CAPSLOCK_BIT)
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, capslock)] = red;
|
||||
if (led_flags & ZMK_LED_NUMLOCK_BIT)
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, numlock)] = red;
|
||||
if (led_flags & ZMK_LED_SCROLLLOCK_BIT)
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, scrolllock)] = red;
|
||||
|
||||
for (uint8_t i = 0; i < DT_PROP_LEN(UNDERGLOW_INDICATORS, layer_state); i++) {
|
||||
if (zmk_keymap_layer_active(i))
|
||||
status_pixels[underglow_layer_state[i]] = magenta;
|
||||
}
|
||||
|
||||
struct zmk_endpoint_instance active_endpoint = zmk_endpoints_selected();
|
||||
|
||||
if (!zmk_endpoints_preferred_transport_is_active())
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, output_fallback)] = red;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BLE)
|
||||
int active_ble_profile_index = zmk_ble_active_profile_index();
|
||||
for (uint8_t i = 0;
|
||||
i < MIN(ZMK_BLE_PROFILE_COUNT, DT_PROP_LEN(UNDERGLOW_INDICATORS, ble_state)); i++) {
|
||||
int8_t status = zmk_ble_profile_status(i);
|
||||
int ble_pixel = underglow_ble_state[i];
|
||||
if (status == 2 && active_endpoint.transport == ZMK_TRANSPORT_BLE &&
|
||||
active_ble_profile_index == i) {
|
||||
status_pixels[ble_pixel] = white;
|
||||
} else if (status == 2) {
|
||||
status_pixels[ble_pixel] = dull_green;
|
||||
} else if (status == 1) {
|
||||
status_pixels[ble_pixel] = red;
|
||||
} else if (status == 0) {
|
||||
status_pixels[ble_pixel] = lilac;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
enum zmk_usb_conn_state usb_state = zmk_usb_get_conn_state();
|
||||
if (usb_state == ZMK_USB_CONN_HID &&
|
||||
active_endpoint.transport == ZMK_TRANSPORT_USB) {
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, usb_state)] = white;
|
||||
} else if (usb_state == ZMK_USB_CONN_HID) {
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, usb_state)] = dull_green;
|
||||
} else if (usb_state == ZMK_USB_CONN_POWERED) {
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, usb_state)] = red;
|
||||
} else if (usb_state == ZMK_USB_CONN_NONE) {
|
||||
status_pixels[DT_PROP(UNDERGLOW_INDICATORS, usb_state)] = lilac;
|
||||
}
|
||||
|
||||
int16_t blend = 256;
|
||||
if (state.status_animation_step < (500 / 25)) {
|
||||
blend = ((state.status_animation_step * 256) / (500 / 25));
|
||||
} else if (state.status_animation_step > (8000 / 25)) {
|
||||
blend = 256 - (((state.status_animation_step - (8000 / 25)) * 256) / (2000 / 25));
|
||||
}
|
||||
if (blend < 0)
|
||||
blend = 0;
|
||||
if (blend > 256)
|
||||
blend = 256;
|
||||
|
||||
return blend;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* --- Tick / animation loop --- */
|
||||
|
||||
static void zmk_rgb_underglow_tick(struct k_work *work) {
|
||||
struct zmk_rgb_effect *effect = zmk_rgb_effect_get(state.current_effect);
|
||||
if (effect && effect->render) {
|
||||
struct zmk_rgb_effect_ctx ctx = {
|
||||
.pixels = pixels,
|
||||
.num_pixels = STRIP_NUM_PIXELS,
|
||||
.base_color = state.color,
|
||||
.animation_step = &state.animation_step,
|
||||
.animation_speed = state.animation_speed,
|
||||
};
|
||||
effect->render(&ctx);
|
||||
}
|
||||
|
||||
zmk_led_write_pixels();
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(underglow_tick_work, zmk_rgb_underglow_tick);
|
||||
|
|
@ -209,11 +471,16 @@ static void zmk_rgb_underglow_tick_handler(struct k_timer *timer) {
|
|||
|
||||
K_TIMER_DEFINE(underglow_tick, zmk_rgb_underglow_tick_handler, NULL);
|
||||
|
||||
void zmk_rgb_request_refresh(void) {
|
||||
k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &underglow_tick_work);
|
||||
}
|
||||
|
||||
/* --- Settings persistence --- */
|
||||
|
||||
#if IS_ENABLED(CONFIG_SETTINGS)
|
||||
static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_cb, void *cb_arg) {
|
||||
const char *next;
|
||||
int rc;
|
||||
|
||||
if (settings_name_steq(name, "state", &next) && !next) {
|
||||
if (len != sizeof(state)) {
|
||||
return -EINVAL;
|
||||
|
|
@ -221,10 +488,13 @@ static int rgb_settings_set(const char *name, size_t len, settings_read_cb read_
|
|||
|
||||
rc = read_cb(cb_arg, &state, sizeof(state));
|
||||
if (rc >= 0) {
|
||||
int effect_count = zmk_rgb_effect_get_count();
|
||||
if (state.current_effect >= effect_count) {
|
||||
state.current_effect = 0;
|
||||
}
|
||||
if (state.on) {
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +515,6 @@ static struct k_work_delayable underglow_save_work;
|
|||
|
||||
static int zmk_rgb_underglow_init(void) {
|
||||
led_strip = DEVICE_DT_GET(STRIP_CHOSEN);
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
|
||||
if (!device_is_ready(ext_power)) {
|
||||
LOG_ERR("External power device \"%s\" is not ready", ext_power->name);
|
||||
|
|
@ -273,8 +542,18 @@ static int zmk_rgb_underglow_init(void) {
|
|||
state.on = zmk_usb_is_powered();
|
||||
#endif
|
||||
|
||||
int effect_count = zmk_rgb_effect_get_count();
|
||||
if (state.current_effect >= effect_count && effect_count > 0) {
|
||||
state.current_effect = 0;
|
||||
}
|
||||
|
||||
if (state.on) {
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
|
||||
struct zmk_rgb_effect *effect = zmk_rgb_effect_get(state.current_effect);
|
||||
if (effect && (effect->flags & ZMK_RGB_EFFECT_STATIC)) {
|
||||
zmk_rgb_request_refresh();
|
||||
} else {
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(25));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -297,72 +576,136 @@ int zmk_rgb_underglow_get_state(bool *on_off) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int zmk_rgb_underglow_on(void) {
|
||||
if (!led_strip)
|
||||
return -ENODEV;
|
||||
|
||||
void zmk_rgb_set_ext_power(void) {
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
|
||||
if (ext_power != NULL) {
|
||||
int rc = ext_power_enable(ext_power);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Unable to enable EXT_POWER: %d", rc);
|
||||
if (ext_power == NULL)
|
||||
return;
|
||||
int c_power = ext_power_get(ext_power);
|
||||
if (c_power < 0) {
|
||||
LOG_ERR("Unable to examine EXT_POWER: %d", c_power);
|
||||
c_power = 0;
|
||||
}
|
||||
int desired_state = state.on || state.status_active;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_BATTERY_REPORTING)
|
||||
if (state.on && !state.status_active) {
|
||||
if (zmk_battery_state_of_charge() < 10) {
|
||||
desired_state = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
state.on = true;
|
||||
state.animation_step = 0;
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(50));
|
||||
|
||||
return zmk_rgb_underglow_save_state();
|
||||
}
|
||||
|
||||
static void zmk_rgb_underglow_off_handler(struct k_work *work) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
|
||||
if (desired_state && !c_power) {
|
||||
int rc = ext_power_enable(ext_power);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Unable to enable EXT_POWER: %d", rc);
|
||||
}
|
||||
|
||||
led_strip_update_rgb(led_strip, pixels, STRIP_NUM_PIXELS);
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(underglow_off_work, zmk_rgb_underglow_off_handler);
|
||||
|
||||
int zmk_rgb_underglow_off(void) {
|
||||
if (!led_strip)
|
||||
return -ENODEV;
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_EXT_POWER)
|
||||
if (ext_power != NULL) {
|
||||
} else if (!desired_state && c_power) {
|
||||
int rc = ext_power_disable(ext_power);
|
||||
if (rc != 0) {
|
||||
LOG_ERR("Unable to disable EXT_POWER: %d", rc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int zmk_rgb_underglow_on(void) {
|
||||
zmk_rgb_underglow_transient_on();
|
||||
return zmk_rgb_underglow_save_state();
|
||||
}
|
||||
|
||||
int zmk_rgb_underglow_transient_on(void) {
|
||||
if (!led_strip)
|
||||
return -ENODEV;
|
||||
|
||||
state.on = true;
|
||||
zmk_rgb_set_ext_power();
|
||||
|
||||
state.animation_step = 0;
|
||||
|
||||
struct zmk_rgb_effect *effect = zmk_rgb_effect_get(state.current_effect);
|
||||
if (effect && effect->on_select) {
|
||||
effect->on_select();
|
||||
}
|
||||
if (effect && (effect->flags & ZMK_RGB_EFFECT_STATIC)) {
|
||||
zmk_rgb_request_refresh();
|
||||
} else {
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(25));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zmk_rgb_underglow_off_handler(struct k_work *work) {
|
||||
for (int i = 0; i < STRIP_NUM_PIXELS; i++) {
|
||||
pixels[i] = (struct led_rgb){r : 0, g : 0, b : 0};
|
||||
}
|
||||
zmk_led_write_pixels();
|
||||
}
|
||||
|
||||
K_WORK_DEFINE(underglow_off_work, zmk_rgb_underglow_off_handler);
|
||||
|
||||
int zmk_rgb_underglow_off(void) {
|
||||
zmk_rgb_underglow_transient_off();
|
||||
return zmk_rgb_underglow_save_state();
|
||||
}
|
||||
|
||||
int zmk_rgb_underglow_transient_off(void) {
|
||||
if (!led_strip)
|
||||
return -ENODEV;
|
||||
|
||||
struct zmk_rgb_effect *effect = zmk_rgb_effect_get(state.current_effect);
|
||||
if (effect && effect->on_deselect) {
|
||||
effect->on_deselect();
|
||||
}
|
||||
|
||||
k_work_submit_to_queue(zmk_workqueue_lowprio_work_q(), &underglow_off_work);
|
||||
|
||||
k_timer_stop(&underglow_tick);
|
||||
state.on = false;
|
||||
zmk_rgb_set_ext_power();
|
||||
|
||||
return zmk_rgb_underglow_save_state();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zmk_rgb_underglow_calc_effect(int direction) {
|
||||
return (state.current_effect + UNDERGLOW_EFFECT_NUMBER + direction) % UNDERGLOW_EFFECT_NUMBER;
|
||||
int count = zmk_rgb_effect_get_count();
|
||||
if (count == 0)
|
||||
return 0;
|
||||
return (state.current_effect + count + direction) % count;
|
||||
}
|
||||
|
||||
int zmk_rgb_underglow_select_effect(int effect) {
|
||||
if (!led_strip)
|
||||
return -ENODEV;
|
||||
|
||||
if (effect < 0 || effect >= UNDERGLOW_EFFECT_NUMBER) {
|
||||
int count = zmk_rgb_effect_get_count();
|
||||
if (effect < 0 || effect >= count) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
struct zmk_rgb_effect *old_eff = zmk_rgb_effect_get(state.current_effect);
|
||||
if (old_eff && old_eff->on_deselect) {
|
||||
old_eff->on_deselect();
|
||||
}
|
||||
|
||||
state.current_effect = effect;
|
||||
state.animation_step = 0;
|
||||
|
||||
struct zmk_rgb_effect *new_eff = zmk_rgb_effect_get(state.current_effect);
|
||||
if (new_eff && new_eff->on_select) {
|
||||
new_eff->on_select();
|
||||
}
|
||||
|
||||
if (state.on) {
|
||||
if (new_eff && (new_eff->flags & ZMK_RGB_EFFECT_STATIC)) {
|
||||
k_timer_stop(&underglow_tick);
|
||||
zmk_rgb_request_refresh();
|
||||
} else {
|
||||
k_timer_start(&underglow_tick, K_NO_WAIT, K_MSEC(25));
|
||||
}
|
||||
}
|
||||
|
||||
return zmk_rgb_underglow_save_state();
|
||||
}
|
||||
|
||||
|
|
@ -374,6 +717,52 @@ int zmk_rgb_underglow_toggle(void) {
|
|||
return state.on ? zmk_rgb_underglow_off() : zmk_rgb_underglow_on();
|
||||
}
|
||||
|
||||
/* --- Status overlay timer --- */
|
||||
|
||||
static void zmk_led_write_pixels_work(struct k_work *work);
|
||||
static void zmk_rgb_underglow_status_update(struct k_timer *timer);
|
||||
|
||||
K_WORK_DEFINE(underglow_write_work, zmk_led_write_pixels_work);
|
||||
K_TIMER_DEFINE(underglow_status_update_timer, zmk_rgb_underglow_status_update, NULL);
|
||||
|
||||
static void zmk_rgb_underglow_status_update(struct k_timer *timer) {
|
||||
if (!state.status_active)
|
||||
return;
|
||||
state.status_animation_step++;
|
||||
if (state.status_animation_step > (10000 / 25)) {
|
||||
state.status_active = false;
|
||||
k_timer_stop(&underglow_status_update_timer);
|
||||
}
|
||||
if (!k_work_is_pending(&underglow_write_work))
|
||||
k_work_submit(&underglow_write_work);
|
||||
}
|
||||
|
||||
static void zmk_led_write_pixels_work(struct k_work *work) {
|
||||
zmk_led_write_pixels();
|
||||
if (!state.status_active) {
|
||||
zmk_rgb_set_ext_power();
|
||||
}
|
||||
}
|
||||
|
||||
int zmk_rgb_underglow_status(void) {
|
||||
if (!state.status_active) {
|
||||
state.status_animation_step = 0;
|
||||
} else {
|
||||
if (state.status_animation_step > (500 / 25)) {
|
||||
state.status_animation_step = 500 / 25;
|
||||
}
|
||||
}
|
||||
state.status_active = true;
|
||||
zmk_led_write_pixels();
|
||||
zmk_rgb_set_ext_power();
|
||||
|
||||
k_timer_start(&underglow_status_update_timer, K_NO_WAIT, K_MSEC(25));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --- HSB control functions --- */
|
||||
|
||||
int zmk_rgb_underglow_set_hsb(struct zmk_led_hsb color) {
|
||||
if (color.h > HUE_MAX || color.s > SAT_MAX || color.b > BRT_MAX) {
|
||||
return -ENOTSUP;
|
||||
|
|
@ -460,6 +849,8 @@ int zmk_rgb_underglow_change_spd(int direction) {
|
|||
return zmk_rgb_underglow_save_state();
|
||||
}
|
||||
|
||||
/* --- Auto off / idle listeners --- */
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE) || \
|
||||
IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_USB)
|
||||
struct rgb_underglow_sleep_state {
|
||||
|
|
@ -473,7 +864,6 @@ static int rgb_underglow_auto_state(bool target_wake_state) {
|
|||
rgb_state_before_sleeping : false
|
||||
};
|
||||
|
||||
// wake up event while awake, or sleep event while sleeping -> no-op
|
||||
if (target_wake_state == sleep_state.is_awake) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -481,13 +871,13 @@ static int rgb_underglow_auto_state(bool target_wake_state) {
|
|||
|
||||
if (sleep_state.is_awake) {
|
||||
if (sleep_state.rgb_state_before_sleeping) {
|
||||
return zmk_rgb_underglow_on();
|
||||
return zmk_rgb_underglow_transient_on();
|
||||
} else {
|
||||
return zmk_rgb_underglow_off();
|
||||
return zmk_rgb_underglow_transient_off();
|
||||
}
|
||||
} else {
|
||||
sleep_state.rgb_state_before_sleeping = state.on;
|
||||
return zmk_rgb_underglow_off();
|
||||
return zmk_rgb_underglow_transient_off();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -509,8 +899,7 @@ static int rgb_underglow_event_listener(const zmk_event_t *eh) {
|
|||
}
|
||||
|
||||
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)
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_RGB_UNDERGLOW_AUTO_OFF_IDLE)
|
||||
ZMK_SUBSCRIPTION(rgb_underglow, zmk_activity_state_changed);
|
||||
|
|
|
|||
|
|
@ -4,9 +4,12 @@
|
|||
if (NOT CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE service.c)
|
||||
target_sources(app PRIVATE peripheral.c)
|
||||
target_sources(app PRIVATE peripheral_layers.c)
|
||||
|
||||
endif()
|
||||
if (CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
target_sources(app PRIVATE central.c)
|
||||
target_sources_ifdef(CONFIG_ZMK_SPLIT_BLE_PREF_IDLE app PRIVATE central_listener.c)
|
||||
endif()
|
||||
|
||||
if (CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_PROXY)
|
||||
|
|
|
|||
|
|
@ -74,6 +74,26 @@ config ZMK_SPLIT_BLE_PREF_TIMEOUT
|
|||
int "Supervision timeout to use for split central/peripheral connection"
|
||||
default 400
|
||||
|
||||
config ZMK_SPLIT_BLE_PREF_IDLE
|
||||
bool "Set slower split peripheral BLE params on idle to save power"
|
||||
default y
|
||||
|
||||
if ZMK_SPLIT_BLE_PREF_IDLE
|
||||
|
||||
config ZMK_SPLIT_BLE_PREF_IDLE_INT
|
||||
int "Peripheral idle connection interval in 1.25ms units"
|
||||
default 18
|
||||
|
||||
config ZMK_SPLIT_BLE_PREF_IDLE_LATENCY
|
||||
int "Peripheral idle latency in Connection Intervals"
|
||||
default 10
|
||||
|
||||
config ZMK_SPLIT_BLE_PREF_IDLE_TIMEOUT
|
||||
int "Peripheral idle supervision timeout in 10ms units"
|
||||
default 400
|
||||
|
||||
endif # ZMK_SPLIT_BLE_PREF_IDLE
|
||||
|
||||
endif # ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
||||
if !ZMK_SPLIT_ROLE_CENTRAL
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#include <zmk/pointing/input_split.h>
|
||||
#include <zmk/hid_indicators_types.h>
|
||||
#include <zmk/physical_layouts.h>
|
||||
#include <zmk/events/split_peripheral_layer_changed.h>
|
||||
|
||||
static int start_scanning(void);
|
||||
|
||||
|
|
@ -60,6 +61,8 @@ struct peripheral_slot {
|
|||
uint16_t update_hid_indicators;
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
uint16_t selected_physical_layout_handle;
|
||||
uint16_t update_layers_handle;
|
||||
|
||||
uint8_t position_state[POSITION_STATE_DATA_LEN];
|
||||
uint8_t changed_positions[POSITION_STATE_DATA_LEN];
|
||||
};
|
||||
|
|
@ -219,6 +222,7 @@ int release_peripheral_slot(int index) {
|
|||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
slot->update_hid_indicators = 0;
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
slot->update_layers_handle = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -620,6 +624,10 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
|
|||
LOG_DBG("Found update HID indicators handle");
|
||||
slot->update_hid_indicators = bt_gatt_attr_value_handle(attr);
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
} else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
|
||||
BT_UUID_DECLARE_128(ZMK_SPLIT_BT_UPDATE_LAYERS_UUID))) {
|
||||
LOG_DBG("Found update Layers handle");
|
||||
slot->update_layers_handle = bt_gatt_attr_value_handle(attr);
|
||||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_BLE_CENTRAL_BATTERY_LEVEL_FETCHING)
|
||||
} else if (!bt_uuid_cmp(((struct bt_gatt_chrc *)attr->user_data)->uuid,
|
||||
BT_UUID_BAS_BATTERY_LEVEL)) {
|
||||
|
|
@ -707,6 +715,8 @@ static uint8_t split_central_chrc_discovery_func(struct bt_conn *conn,
|
|||
}
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_INPUT_SPLIT)
|
||||
|
||||
subscribed = subscribed && slot->update_layers_handle;
|
||||
|
||||
return subscribed ? BT_GATT_ITER_STOP : BT_GATT_ITER_CONTINUE;
|
||||
}
|
||||
|
||||
|
|
@ -1145,6 +1155,42 @@ static struct settings_handler ble_central_settings_handler = {
|
|||
|
||||
#endif // IS_ENABLED(CONFIG_SETTINGS)
|
||||
|
||||
static uint32_t layers_for_peripheral = 0;
|
||||
|
||||
static void split_central_update_layers_callback(struct k_work *work) {
|
||||
uint32_t layers = layers_for_peripheral;
|
||||
for (int i = 0; i < ZMK_SPLIT_BLE_PERIPHERAL_COUNT; i++) {
|
||||
if (peripherals[i].state != PERIPHERAL_SLOT_STATE_CONNECTED) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peripherals[i].update_layers_handle == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int err =
|
||||
bt_gatt_write_without_response(peripherals[i].conn, peripherals[i].update_layers_handle,
|
||||
&layers, sizeof(layers), true);
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("Failed to send layers to peripheral (err %d)", err);
|
||||
} else {
|
||||
LOG_DBG("Sent Layers over to peripheral");
|
||||
raise_zmk_split_peripheral_layer_changed(
|
||||
(struct zmk_split_peripheral_layer_changed){.layers = layers});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static K_WORK_DEFINE(split_central_update_layers, split_central_update_layers_callback);
|
||||
|
||||
int zmk_split_central_update_layers(uint32_t new_layers) {
|
||||
layers_for_peripheral = new_layers;
|
||||
return k_work_submit_to_queue(&split_central_split_run_q, &split_central_update_layers);
|
||||
}
|
||||
|
||||
// valdur layers done
|
||||
|
||||
static int zmk_split_bt_central_init(void) {
|
||||
k_work_queue_start(&split_central_split_run_q, split_central_split_run_q_stack,
|
||||
K_THREAD_STACK_SIZEOF(split_central_split_run_q_stack),
|
||||
|
|
|
|||
87
app/src/split/bluetooth/central_listener.c
Normal file
87
app/src/split/bluetooth/central_listener.c
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The ZMK Contributors
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
|
||||
#include <zmk/event_manager.h>
|
||||
#include <zmk/events/activity_state_changed.h>
|
||||
|
||||
static void set_sleep_params(struct bt_conn *conn, void *data) {
|
||||
struct bt_conn_info info;
|
||||
|
||||
bt_conn_get_info(conn, &info);
|
||||
|
||||
if (info.role == BT_CONN_ROLE_CENTRAL) {
|
||||
int err =
|
||||
bt_conn_le_param_update(conn, BT_LE_CONN_PARAM(CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_INT,
|
||||
CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_INT,
|
||||
CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_LATENCY,
|
||||
CONFIG_ZMK_SPLIT_BLE_PREF_IDLE_TIMEOUT));
|
||||
|
||||
if (err) {
|
||||
LOG_DBG("Failed to sleep split connection: %d", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void set_wake_params(struct bt_conn *conn, void *data) {
|
||||
struct bt_conn_info info;
|
||||
|
||||
bt_conn_get_info(conn, &info);
|
||||
|
||||
if (info.role == BT_CONN_ROLE_CENTRAL) {
|
||||
int err = bt_conn_le_param_update(
|
||||
conn,
|
||||
BT_LE_CONN_PARAM(CONFIG_ZMK_SPLIT_BLE_PREF_INT, CONFIG_ZMK_SPLIT_BLE_PREF_INT,
|
||||
CONFIG_ZMK_SPLIT_BLE_PREF_LATENCY, CONFIG_ZMK_SPLIT_BLE_PREF_TIMEOUT));
|
||||
|
||||
if (err) {
|
||||
LOG_DBG("Failed to wake up split connection: %d", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sleep_all() {
|
||||
LOG_DBG("Setting idle connection parameters on peripherals");
|
||||
|
||||
bt_conn_foreach(BT_CONN_TYPE_LE, set_sleep_params, NULL);
|
||||
}
|
||||
|
||||
static void wake_all() {
|
||||
LOG_DBG("Waking up from idle connection parameters on peripherals");
|
||||
|
||||
bt_conn_foreach(BT_CONN_TYPE_LE, set_wake_params, NULL);
|
||||
}
|
||||
|
||||
int central_event_handler(const zmk_event_t *eh) {
|
||||
struct zmk_activity_state_changed *ev = as_zmk_activity_state_changed(eh);
|
||||
if (ev == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
switch (ev->state) {
|
||||
case ZMK_ACTIVITY_ACTIVE:
|
||||
wake_all();
|
||||
break;
|
||||
case ZMK_ACTIVITY_IDLE:
|
||||
sleep_all();
|
||||
break;
|
||||
case ZMK_ACTIVITY_SLEEP:
|
||||
break;
|
||||
default:
|
||||
LOG_WRN("Unhandled activity state: %d", ev->state);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ZMK_LISTENER(central, central_event_handler);
|
||||
ZMK_SUBSCRIPTION(central, zmk_activity_state_changed);
|
||||
25
app/src/split/bluetooth/peripheral_layers.c
Normal file
25
app/src/split/bluetooth/peripheral_layers.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include <zmk/split/bluetooth/peripheral_layers.h>
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
static uint32_t peripheral_layers = 0;
|
||||
|
||||
void set_peripheral_layers_state(uint32_t new_layers) { peripheral_layers = new_layers; }
|
||||
|
||||
bool peripheral_layer_active(uint8_t layer) {
|
||||
return (peripheral_layers & (BIT(layer))) == (BIT(layer));
|
||||
};
|
||||
|
||||
uint8_t peripheral_highest_layer_active(void) {
|
||||
if (peripheral_layers > 0) {
|
||||
for (uint8_t layer = ZMK_KEYMAP_LAYERS_LEN - 1; layer > 0; layer--) {
|
||||
if ((peripheral_layers & (BIT(layer))) == (BIT(layer)) || layer == 0) {
|
||||
return layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -31,9 +31,11 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|||
#if IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
#include <zmk/events/hid_indicators_changed.h>
|
||||
#endif // IS_ENABLED(CONFIG_ZMK_SPLIT_PERIPHERAL_HID_INDICATORS)
|
||||
#include <zmk/split/bluetooth/peripheral_layers.h>
|
||||
|
||||
#include <zmk/events/sensor_event.h>
|
||||
#include <zmk/sensors.h>
|
||||
#include <zmk/events/split_peripheral_layer_changed.h>
|
||||
|
||||
#if ZMK_KEYMAP_HAS_SENSORS
|
||||
static struct sensor_event last_sensor_event;
|
||||
|
|
@ -139,6 +141,31 @@ static ssize_t split_svc_get_selected_phys_layout(struct bt_conn *conn,
|
|||
return bt_gatt_attr_read(conn, attrs, buf, len, offset, &selected, sizeof(selected));
|
||||
}
|
||||
|
||||
static uint32_t layers = 0;
|
||||
|
||||
static void split_svc_update_layers_callback(struct k_work *work) {
|
||||
LOG_DBG("Setting peripheral layers: %x", layers);
|
||||
// set_peripheral_layers_state(layers);
|
||||
raise_zmk_split_peripheral_layer_changed(
|
||||
(struct zmk_split_peripheral_layer_changed){.layers = layers});
|
||||
}
|
||||
|
||||
static K_WORK_DEFINE(split_svc_update_layers_work, split_svc_update_layers_callback);
|
||||
|
||||
static ssize_t split_svc_update_layers(struct bt_conn *conn, const struct bt_gatt_attr *attr,
|
||||
const void *buf, uint16_t len, uint16_t offset,
|
||||
uint8_t flags) {
|
||||
if (offset + len > sizeof(uint32_t)) {
|
||||
return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
|
||||
}
|
||||
|
||||
memcpy((uint8_t *)&layers + offset, buf, len);
|
||||
|
||||
k_work_submit(&split_svc_update_layers_work);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZMK_INPUT_SPLIT)
|
||||
|
||||
static void split_input_events_ccc(const struct bt_gatt_attr *attr, uint16_t value) {
|
||||
|
|
@ -204,8 +231,11 @@ BT_GATT_SERVICE_DEFINE(
|
|||
BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_SELECT_PHYS_LAYOUT_UUID),
|
||||
BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ,
|
||||
BT_GATT_PERM_WRITE_ENCRYPT | BT_GATT_PERM_READ_ENCRYPT,
|
||||
split_svc_get_selected_phys_layout, split_svc_select_phys_layout,
|
||||
NULL), );
|
||||
split_svc_get_selected_phys_layout, split_svc_select_phys_layout, NULL),
|
||||
|
||||
BT_GATT_CHARACTERISTIC(BT_UUID_DECLARE_128(ZMK_SPLIT_BT_UPDATE_LAYERS_UUID),
|
||||
BT_GATT_CHRC_WRITE_WITHOUT_RESP, BT_GATT_PERM_WRITE_ENCRYPT, NULL,
|
||||
split_svc_update_layers, NULL), );
|
||||
|
||||
K_THREAD_STACK_DEFINE(service_q_stack, CONFIG_ZMK_SPLIT_BLE_PERIPHERAL_STACK_SIZE);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue