Alessandro Bortolin
3 years ago
committed by
Pete Johanson
9 changed files with 371 additions and 2 deletions
@ -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 = "BACKLIGHT"; |
||||||
|
#binding-cells = <1>; |
||||||
|
}; |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,8 @@ |
|||||||
|
# Copyright (c) 2021 The ZMK Contributors |
||||||
|
# SPDX-License-Identifier: MIT |
||||||
|
|
||||||
|
description: Backlight behavior |
||||||
|
|
||||||
|
compatible: "zmk,behavior-backlight" |
||||||
|
|
||||||
|
include: one_param.yaml |
@ -0,0 +1,11 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The ZMK Contributors |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
#define BL_TOG 0 |
||||||
|
#define BL_ON 1 |
||||||
|
#define BL_OFF 2 |
||||||
|
#define BL_INC 3 |
||||||
|
#define BL_DEC 4 |
@ -0,0 +1,19 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The ZMK Contributors |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
int zmk_backlight_set_on(bool on); |
||||||
|
bool zmk_backlight_is_on(); |
||||||
|
|
||||||
|
int zmk_backlight_set_brt(int brt); |
||||||
|
int zmk_backlight_get_brt(); |
||||||
|
|
||||||
|
int zmk_backlight_toggle(); |
||||||
|
int zmk_backlight_on(); |
||||||
|
int zmk_backlight_off(); |
||||||
|
int zmk_backlight_inc(); |
||||||
|
int zmk_backlight_dec(); |
@ -0,0 +1,224 @@ |
|||||||
|
/*
|
||||||
|
* 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> |
||||||
|
#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))) |
||||||
|
|
||||||
|
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 = state.on ? state.brightness : 0; |
||||||
|
for (int i = 0; i < BACKLIGHT_NUM_LEDS; i++) { |
||||||
|
int rc = led_set_brightness(backlight_dev, i, brt); |
||||||
|
if (rc != 0) { |
||||||
|
return rc; |
||||||
|
} |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_SETTINGS) |
||||||
|
static int backlight_settings_set(const char *name, size_t len, settings_read_cb read_cb, |
||||||
|
void *cb_arg) { |
||||||
|
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)); |
||||||
|
if (rc < 0) { |
||||||
|
return rc; |
||||||
|
} |
||||||
|
|
||||||
|
return zmk_backlight_update(); |
||||||
|
} |
||||||
|
|
||||||
|
return -ENOENT; |
||||||
|
} |
||||||
|
|
||||||
|
static struct settings_handler backlight_conf = {.name = "backlight", |
||||||
|
.h_set = backlight_settings_set}; |
||||||
|
|
||||||
|
static void zmk_backlight_save_state_work() { |
||||||
|
settings_save_one("backlight/state", &state, sizeof(state)); |
||||||
|
} |
||||||
|
|
||||||
|
static struct k_delayed_work backlight_save_work; |
||||||
|
#endif // IS_ENABLED(CONFIG_SETTINGS)
|
||||||
|
|
||||||
|
static int zmk_backlight_save_state() { |
||||||
|
#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 |
||||||
|
} |
||||||
|
|
||||||
|
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 err = settings_register(&backlight_conf); |
||||||
|
if (err) { |
||||||
|
LOG_ERR("Failed to register the backlight settings handler (err %d)", err); |
||||||
|
return err; |
||||||
|
} |
||||||
|
|
||||||
|
k_delayed_work_init(&backlight_save_work, zmk_backlight_save_state_work); |
||||||
|
|
||||||
|
settings_load_subtree("backlight"); |
||||||
|
#endif |
||||||
|
|
||||||
|
return zmk_backlight_update(); |
||||||
|
} |
||||||
|
|
||||||
|
int zmk_backlight_set_on(bool on) { |
||||||
|
if (!state.on && state.brightness == 0) { |
||||||
|
state.brightness = CONFIG_ZMK_BACKLIGHT_BRT_STEP; |
||||||
|
} |
||||||
|
state.on = on; |
||||||
|
|
||||||
|
int rc = zmk_backlight_update(); |
||||||
|
if (rc != 0) { |
||||||
|
return rc; |
||||||
|
} |
||||||
|
|
||||||
|
return zmk_backlight_save_state(); |
||||||
|
} |
||||||
|
|
||||||
|
bool zmk_backlight_is_on() { return state.on; } |
||||||
|
|
||||||
|
int zmk_backlight_set_brt(int brt) { |
||||||
|
state.on = (brt > 0); |
||||||
|
state.brightness = CLAMP(brt, 0, 100); |
||||||
|
|
||||||
|
int rc = zmk_backlight_update(); |
||||||
|
if (rc != 0) { |
||||||
|
return rc; |
||||||
|
} |
||||||
|
|
||||||
|
return zmk_backlight_save_state(); |
||||||
|
} |
||||||
|
|
||||||
|
int zmk_backlight_get_brt() { return state.on ? state.brightness : 0; } |
||||||
|
|
||||||
|
int zmk_backlight_toggle() { return zmk_backlight_set_on(!state.on); } |
||||||
|
|
||||||
|
int zmk_backlight_on() { return zmk_backlight_set_on(true); } |
||||||
|
|
||||||
|
int zmk_backlight_off() { return zmk_backlight_set_on(false); } |
||||||
|
|
||||||
|
int zmk_backlight_inc() { |
||||||
|
if (!state.on) { |
||||||
|
return zmk_backlight_set_brt(MAX(state.brightness, CONFIG_ZMK_BACKLIGHT_BRT_STEP)); |
||||||
|
} |
||||||
|
return zmk_backlight_set_brt(state.brightness + CONFIG_ZMK_BACKLIGHT_BRT_STEP); |
||||||
|
} |
||||||
|
|
||||||
|
int zmk_backlight_dec() { |
||||||
|
return zmk_backlight_set_brt(state.brightness - CONFIG_ZMK_BACKLIGHT_BRT_STEP); |
||||||
|
} |
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) |
||||||
|
static bool auto_off_idle_prev_state = false; |
||||||
|
#endif |
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) |
||||||
|
static bool auto_off_usb_prev_state = false; |
||||||
|
#endif |
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_IDLE) || IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) |
||||||
|
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)) { |
||||||
|
bool new_state = (zmk_activity_get_state() == ZMK_ACTIVITY_ACTIVE); |
||||||
|
if (state.on == new_state) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if (new_state) { |
||||||
|
state.on = auto_off_idle_prev_state; |
||||||
|
auto_off_idle_prev_state = false; |
||||||
|
} else { |
||||||
|
state.on = false; |
||||||
|
auto_off_idle_prev_state = true; |
||||||
|
} |
||||||
|
return zmk_backlight_update(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ZMK_BACKLIGHT_AUTO_OFF_USB) |
||||||
|
if (as_zmk_usb_conn_state_changed(eh)) { |
||||||
|
bool new_state = zmk_usb_is_powered(); |
||||||
|
if (state.on == new_state) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if (new_state) { |
||||||
|
state.on = auto_off_usb_prev_state; |
||||||
|
auto_off_usb_prev_state = false; |
||||||
|
} else { |
||||||
|
state.on = false; |
||||||
|
auto_off_usb_prev_state = true; |
||||||
|
} |
||||||
|
return zmk_backlight_update(); |
||||||
|
} |
||||||
|
#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); |
@ -0,0 +1,56 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 The ZMK Contributors |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: MIT |
||||||
|
*/ |
||||||
|
|
||||||
|
#define DT_DRV_COMPAT zmk_behavior_backlight |
||||||
|
|
||||||
|
#include <device.h> |
||||||
|
#include <drivers/behavior.h> |
||||||
|
#include <logging/log.h> |
||||||
|
|
||||||
|
#include <dt-bindings/zmk/backlight.h> |
||||||
|
#include <zmk/backlight.h> |
||||||
|
#include <zmk/keymap.h> |
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); |
||||||
|
|
||||||
|
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) |
||||||
|
|
||||||
|
static int behavior_backlight_init(const struct device *dev) { return 0; } |
||||||
|
|
||||||
|
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding, |
||||||
|
struct zmk_behavior_binding_event event) { |
||||||
|
switch (binding->param1) { |
||||||
|
case BL_TOG: |
||||||
|
return zmk_backlight_toggle(); |
||||||
|
case BL_ON: |
||||||
|
return zmk_backlight_on(); |
||||||
|
case BL_OFF: |
||||||
|
return zmk_backlight_off(); |
||||||
|
case BL_INC: |
||||||
|
return zmk_backlight_inc(); |
||||||
|
case BL_DEC: |
||||||
|
return zmk_backlight_dec(); |
||||||
|
default: |
||||||
|
LOG_ERR("Unknown backlight command: %d", binding->param1); |
||||||
|
} |
||||||
|
|
||||||
|
return -ENOTSUP; |
||||||
|
} |
||||||
|
|
||||||
|
static int on_keymap_binding_released(struct zmk_behavior_binding *binding, |
||||||
|
struct zmk_behavior_binding_event event) { |
||||||
|
return ZMK_BEHAVIOR_OPAQUE; |
||||||
|
} |
||||||
|
|
||||||
|
static const struct behavior_driver_api behavior_backlight_driver_api = { |
||||||
|
.binding_pressed = on_keymap_binding_pressed, |
||||||
|
.binding_released = on_keymap_binding_released, |
||||||
|
}; |
||||||
|
|
||||||
|
DEVICE_DT_INST_DEFINE(0, behavior_backlight_init, device_pm_control_nop, NULL, NULL, APPLICATION, |
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_backlight_driver_api); |
||||||
|
|
||||||
|
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ |
Loading…
Reference in new issue