Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature backlight #904

Merged
merged 8 commits into from
Feb 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ if ((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_BLE_ROLE_CENTRAL)
target_sources(app PRIVATE src/keymap.c)
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/battery.c)
Expand All @@ -76,6 +77,7 @@ endif()
target_sources_ifdef(CONFIG_USB app PRIVATE src/usb.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/hog.c)
target_sources_ifdef(CONFIG_ZMK_RGB_UNDERGLOW app PRIVATE src/rgb_underglow.c)
target_sources_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)
Expand Down
33 changes: 31 additions & 2 deletions app/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ menu "Display/LED Options"

rsource "src/display/Kconfig"

config ZMK_RGB_UNDERGLOW
menuconfig ZMK_RGB_UNDERGLOW
bool "RGB Adressable LED Underglow"
select LED_STRIP

Expand Down Expand Up @@ -320,6 +320,35 @@ config ZMK_RGB_UNDERGLOW_ON_START
#ZMK_RGB_UNDERGLOW
endif

menuconfig ZMK_BACKLIGHT
bool "LED backlight"
select LED

if ZMK_BACKLIGHT

config ZMK_BACKLIGHT_BRT_STEP
int "Brightness step in percent"
range 1 100
default 20

config ZMK_BACKLIGHT_BRT_START
int "Default brightness in percent"
range 1 100
default 40

config ZMK_BACKLIGHT_ON_START
bortoz marked this conversation as resolved.
Show resolved Hide resolved
bool "Default backlight state"
default y

config ZMK_BACKLIGHT_AUTO_OFF_IDLE
bool "Turn off backlight when keyboard goes into idle state"

config ZMK_BACKLIGHT_AUTO_OFF_USB
bool "Turn off backlight when USB is disconnected"

#ZMK_BACKLIGHT
endif

#Display/LED Options
endmenu

Expand Down Expand Up @@ -370,7 +399,7 @@ config ZMK_COMBO_MAX_KEYS_PER_COMBO
int "Maximum number of keys per combo"
default 4

#Display/LED Options
#Combo options
endmenu

menu "Advanced"
Expand Down
1 change: 1 addition & 0 deletions app/dts/behaviors.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@
#include <behaviors/outputs.dtsi>
#include <behaviors/caps_word.dtsi>
#include <behaviors/key_repeat.dtsi>
#include <behaviors/backlight.dtsi>
15 changes: 15 additions & 0 deletions app/dts/behaviors/backlight.dtsi
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

/ {
behaviors {
/omit-if-no-ref/ bl: behavior_backlight {
compatible = "zmk,behavior-backlight";
label = "BCKLGHT";
#binding-cells = <2>;
};
};
};
8 changes: 8 additions & 0 deletions app/dts/bindings/behaviors/zmk,behavior-backlight.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2021 The ZMK Contributors
# SPDX-License-Identifier: MIT

description: Backlight behavior

compatible: "zmk,behavior-backlight"

include: two_param.yaml
21 changes: 21 additions & 0 deletions app/include/dt-bindings/zmk/backlight.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#define BL_ON_CMD 0
#define BL_OFF_CMD 1
#define BL_TOG_CMD 2
#define BL_INC_CMD 3
#define BL_DEC_CMD 4
#define BL_CYCLE_CMD 5
#define BL_SET_CMD 6

#define BL_ON BL_ON_CMD 0
#define BL_OFF BL_OFF_CMD 0
#define BL_TOG BL_TOG_CMD 0
#define BL_INC BL_INC_CMD 0
#define BL_DEC BL_DEC_CMD 0
#define BL_CYCLE BL_CYCLE_CMD 0
#define BL_SET BL_SET_CMD
17 changes: 17 additions & 0 deletions app/include/zmk/backlight.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#pragma once

int zmk_backlight_on();
int zmk_backlight_off();
int zmk_backlight_toggle();
bool zmk_backlight_is_on();

int zmk_backlight_set_brt(uint8_t brightness);
uint8_t zmk_backlight_get_brt();
uint8_t zmk_backlight_calc_brt(int direction);
uint8_t zmk_backlight_calc_brt_cycle();
189 changes: 189 additions & 0 deletions app/src/backlight.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright (c) 2021 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/

#include <device.h>
#include <devicetree.h>
#include <init.h>
#include <kernel.h>

#include <drivers/led.h>
#include <logging/log.h>
#include <settings/settings.h>

#include <zmk/activity.h>
#include <zmk/backlight.h>
bortoz marked this conversation as resolved.
Show resolved Hide resolved
#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);

BUILD_ASSERT(DT_HAS_CHOSEN(zmk_backlight),
"CONFIG_ZMK_BACKLIGHT is enabled but no zmk,backlight chosen node found");

static const struct device *const backlight_dev = DEVICE_DT_GET(DT_CHOSEN(zmk_backlight));

#define CHILD_COUNT(...) +1
#define DT_NUM_CHILD(node_id) (DT_FOREACH_CHILD(node_id, CHILD_COUNT))

#define BACKLIGHT_NUM_LEDS (DT_NUM_CHILD(DT_CHOSEN(zmk_backlight)))

#define BRT_MAX 100

struct backlight_state {
uint8_t brightness;
bool on;
};

static struct backlight_state state = {.brightness = CONFIG_ZMK_BACKLIGHT_BRT_START,
.on = IS_ENABLED(CONFIG_ZMK_BACKLIGHT_ON_START)};

static int zmk_backlight_update() {
uint8_t brt = zmk_backlight_get_brt();
LOG_DBG("Update backlight brightness: %d%%", brt);

for (int i = 0; i < BACKLIGHT_NUM_LEDS; i++) {
int rc = led_set_brightness(backlight_dev, i, brt);
if (rc != 0) {
LOG_ERR("Failed to update backlight LED %d: %d", i, rc);
return rc;
}
}
return 0;
}

#if IS_ENABLED(CONFIG_SETTINGS)
static int backlight_settings_load_cb(const char *name, size_t len, settings_read_cb read_cb,
void *cb_arg, void *param) {
const char *next;
if (settings_name_steq(name, "state", &next) && !next) {
if (len != sizeof(state)) {
return -EINVAL;
}

int rc = read_cb(cb_arg, &state, sizeof(state));
return MIN(rc, 0);
}
return -ENOENT;
}

static void backlight_save_work_handler(struct k_work *work) {
settings_save_one("backlight/state", &state, sizeof(state));
}

static K_DELAYED_WORK_DEFINE(backlight_save_work, backlight_save_work_handler);
#endif

static int zmk_backlight_init(const struct device *_arg) {
if (!device_is_ready(backlight_dev)) {
LOG_ERR("Backlight device \"%s\" is not ready", backlight_dev->name);
return -ENODEV;
}

#if IS_ENABLED(CONFIG_SETTINGS)
settings_subsys_init();
int rc = settings_load_subtree_direct("backlight", backlight_settings_load_cb, NULL);
if (rc != 0) {
LOG_ERR("Failed to load backlight settings: %d", rc);
}
#endif

return zmk_backlight_update();
}

static int zmk_backlight_update_and_save() {
int rc = zmk_backlight_update();
if (rc != 0) {
return rc;
}

#if IS_ENABLED(CONFIG_SETTINGS)
k_delayed_work_cancel(&backlight_save_work);
return k_delayed_work_submit(&backlight_save_work, K_MSEC(CONFIG_ZMK_SETTINGS_SAVE_DEBOUNCE));
#else
return 0;
#endif
}

int zmk_backlight_on() {
state.brightness = MAX(state.brightness, CONFIG_ZMK_BACKLIGHT_BRT_STEP);
state.on = true;
bortoz marked this conversation as resolved.
Show resolved Hide resolved
return zmk_backlight_update_and_save();
}

int zmk_backlight_off() {
state.on = false;
return zmk_backlight_update_and_save();
}

int zmk_backlight_toggle() { return state.on ? zmk_backlight_off() : zmk_backlight_on(); }

bool zmk_backlight_is_on() { return state.on; }

int zmk_backlight_set_brt(uint8_t brightness) {
state.brightness = MIN(brightness, BRT_MAX);
state.on = (state.brightness > 0);
return zmk_backlight_update_and_save();
}

uint8_t zmk_backlight_get_brt() { return state.on ? state.brightness : 0; }

uint8_t zmk_backlight_calc_brt(int direction) {
int brt = state.brightness + (direction * CONFIG_ZMK_BACKLIGHT_BRT_STEP);
return CLAMP(brt, 0, BRT_MAX);
}

uint8_t zmk_backlight_calc_brt_cycle() {
if (state.brightness == BRT_MAX) {
return 0;
} else {
return zmk_backlight_calc_brt(1);
}
}

#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB)
static int backlight_auto_state(bool *prev_state, bool new_state) {
if (state.on == new_state) {
return 0;
}
state.on = new_state && *prev_state;
*prev_state = !new_state;
return zmk_backlight_update();
}

static int backlight_event_listener(const zmk_event_t *eh) {

#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE)
if (as_zmk_activity_state_changed(eh)) {
static bool prev_state = false;
return backlight_auto_state(&prev_state, zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE);
}
#endif

#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB)
if (as_zmk_usb_conn_state_changed(eh)) {
static bool prev_state = false;
return backlight_auto_state(&prev_state, zmk_usb_is_powered());
}
#endif

return -ENOTSUP;
}

ZMK_LISTENER(backlight, backlight_event_listener);
#endif // IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) ||
// IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB)

#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE)
ZMK_SUBSCRIPTION(backlight, zmk_activity_state_changed);
#endif

#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB)
ZMK_SUBSCRIPTION(backlight, zmk_usb_conn_state_changed);
#endif

SYS_INIT(zmk_backlight_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);
Loading