Implement control animation and basic animation behaviors
This commit is contained in:
parent
69de72c6f4
commit
fc8b91a2ba
9 changed files with 383 additions and 1 deletions
|
@ -82,9 +82,11 @@ target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/battery.c)
|
||||||
|
|
||||||
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/color.c)
|
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/color.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_compose.c)
|
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_compose.c)
|
||||||
|
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_control.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_ripple.c)
|
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_ripple.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_solid.c)
|
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation_solid.c)
|
||||||
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation.c)
|
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/animation/animation.c)
|
||||||
|
target_sources_ifdef(CONFIG_ZMK_ANIMATION app PRIVATE src/behaviors/behavior_animation.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_status_changed.c)
|
||||||
add_subdirectory(src/split)
|
add_subdirectory(src/split)
|
||||||
|
|
|
@ -19,3 +19,4 @@
|
||||||
#include <behaviors/key_repeat.dtsi>
|
#include <behaviors/key_repeat.dtsi>
|
||||||
#include <behaviors/backlight.dtsi>
|
#include <behaviors/backlight.dtsi>
|
||||||
#include <behaviors/macros.dtsi>
|
#include <behaviors/macros.dtsi>
|
||||||
|
#include <behaviors/animation.dtsi>
|
||||||
|
|
15
app/dts/behaviors/animation.dtsi
Normal file
15
app/dts/behaviors/animation.dtsi
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/ {
|
||||||
|
behaviors {
|
||||||
|
/omit-if-no-ref/ animation: behavior_animation {
|
||||||
|
compatible = "zmk,behavior-animation";
|
||||||
|
label = "ANIMATION";
|
||||||
|
#binding-cells = <1>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
23
app/dts/bindings/animations/zmk,animation-control.yaml
Normal file
23
app/dts/bindings/animations/zmk,animation-control.yaml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Copyright (c) 2020, The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Higher-order animation which allows for controlling animation drivers
|
||||||
|
placed underneath it by turning them on and off, cycling though them,
|
||||||
|
or changing the brightness.
|
||||||
|
|
||||||
|
compatible: "zmk,animation-control"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
animations:
|
||||||
|
type: phandles
|
||||||
|
required: true
|
||||||
|
description: |
|
||||||
|
Animations to be combined.
|
||||||
|
|
||||||
|
brightness-steps:
|
||||||
|
type: int
|
||||||
|
required: false
|
||||||
|
default: 5
|
||||||
|
description: |
|
||||||
|
How many brightness steps should be supported.
|
8
app/dts/bindings/behaviors/zmk,behavior-animation.yaml
Normal file
8
app/dts/bindings/behaviors/zmk,behavior-animation.yaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Copyright (c) 2020 The ZMK Contributors
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
description: Animation Action
|
||||||
|
|
||||||
|
compatible: "zmk,behavior-animation"
|
||||||
|
|
||||||
|
include: one_param.yaml
|
|
@ -13,3 +13,44 @@
|
||||||
#else
|
#else
|
||||||
#define HSL(h, s, l) (h + (s << 16) + (l << 24))
|
#define HSL(h, s, l) (h + (s << 16) + (l << 24))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation blending modes
|
||||||
|
*/
|
||||||
|
#define BLENDING_MODE_NORMAL 0
|
||||||
|
#define BLENDING_MODE_MULTIPLY 1
|
||||||
|
#define BLENDING_MODE_LIGHTEN 2
|
||||||
|
#define BLENDING_MODE_DARKEN 3
|
||||||
|
#define BLENDING_MODE_SCREEN 4
|
||||||
|
#define BLENDING_MODE_SUBTRACT 5
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation control commands
|
||||||
|
*/
|
||||||
|
#define ANIMATION_CMD_TOGGLE 0
|
||||||
|
#define ANIMATION_CMD_NEXT 1
|
||||||
|
#define ANIMATION_CMD_PREVIOUS 2
|
||||||
|
#define ANIMATION_CMD_SELECT 3
|
||||||
|
#define ANIMATION_CMD_BRIGHTEN 4
|
||||||
|
#define ANIMATION_CMD_DIM 5
|
||||||
|
#define ANIMATION_CMD_NEXT_CONTROL_ZONE 6
|
||||||
|
#define ANIMATION_CMD_PREVIOUS_CONTROL_ZONE 7
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic animation command macro
|
||||||
|
*/
|
||||||
|
#define ANIMATION_CONTROL_CMD(command, zone, param) ((zone << 24) | (command << 16) | (param))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation behavior helpers
|
||||||
|
*/
|
||||||
|
#define ANIMATION_TOGGLE(zone) ANIMATION_CONTROL_CMD(ANIMATION_CMD_TOGGLE, zone, 0)
|
||||||
|
#define ANIMATION_NEXT(zone) ANIMATION_CONTROL_CMD(ANIMATION_CMD_NEXT, zone, 0)
|
||||||
|
#define ANIMATION_PREVIOUS(zone) ANIMATION_CONTROL_CMD(ANIMATION_CMD_PREVIOUS, zone, 0)
|
||||||
|
#define ANIMATION_SELECT(zone, target_animation) \
|
||||||
|
ANIMATION_CONTROL_CMD(ANIMATION_CMD_SELECT, zone, target_animation)
|
||||||
|
#define ANIMATION_BRIGHTEN(zone) ANIMATION_CONTROL_CMD(ANIMATION_CMD_BRIGHTEN, zone, 0)
|
||||||
|
#define ANIMATION_DIM(zone) ANIMATION_CONTROL_CMD(ANIMATION_CMD_DIM, zone, 0)
|
||||||
|
#define ANIMATION_NEXT_CONTROL_ZONE ANIMATION_CONTROL_CMD(ANIMATION_CMD_NEXT_CONTROL_ZONE, 0, 0)
|
||||||
|
#define ANIMATION_PREVIOUS_CONTROL_ZONE \
|
||||||
|
ANIMATION_CONTROL_CMD(ANIMATION_CMD_PREVIOUS_CONTROL_ZONE, 0, 0)
|
||||||
|
|
24
app/include/zmk/animation/animation_control.h
Normal file
24
app/include/zmk/animation/animation_control.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <device.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation control commands
|
||||||
|
*/
|
||||||
|
#define ANIMATION_CMD_TOGGLE 0
|
||||||
|
#define ANIMATION_CMD_NEXT 1
|
||||||
|
#define ANIMATION_CMD_PREVIOUS 2
|
||||||
|
#define ANIMATION_CMD_SELECT 3
|
||||||
|
#define ANIMATION_CMD_BRIGHTEN 4
|
||||||
|
#define ANIMATION_CMD_DIM 5
|
||||||
|
#define ANIMATION_CMD_NEXT_CONTROL_ZONE 6
|
||||||
|
#define ANIMATION_CMD_PREVIOUS_CONTROL_ZONE 7
|
||||||
|
|
||||||
|
int animation_control_handle_command(const struct device *dev, uint8_t command, uint8_t param);
|
175
app/src/animation/animation_control.c
Normal file
175
app/src/animation/animation_control.c
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT zmk_animation_control
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <drivers/animation.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
|
||||||
|
#include <zmk/animation.h>
|
||||||
|
#include <zmk/animation/animation_control.h>
|
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
// Zephyr 2.7.0 comes with DT_INST_FOREACH_PROP_ELEM
|
||||||
|
// that we can't use quite yet as we're still on 2.5.*
|
||||||
|
#define ZMK_DT_INST_FOREACH_PROP_ELEM(inst, prop, fn) \
|
||||||
|
UTIL_LISTIFY(DT_INST_PROP_LEN(inst, prop), fn, DT_DRV_INST(inst), prop)
|
||||||
|
|
||||||
|
#define PHANDLE_TO_DEVICE(idx, node_id, prop) DEVICE_DT_GET(DT_PHANDLE_BY_IDX(node_id, prop, idx)),
|
||||||
|
|
||||||
|
struct animation_control_config {
|
||||||
|
const struct device **animations;
|
||||||
|
const size_t animations_size;
|
||||||
|
const uint8_t brightness_steps;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct animation_control_data {
|
||||||
|
bool active;
|
||||||
|
uint8_t brightness;
|
||||||
|
size_t current_animation;
|
||||||
|
};
|
||||||
|
|
||||||
|
int animation_control_handle_command(const struct device *dev, uint8_t command, uint8_t param) {
|
||||||
|
const struct animation_control_config *config = dev->config;
|
||||||
|
struct animation_control_data *data = dev->data;
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case ANIMATION_CMD_TOGGLE:
|
||||||
|
data->active = !data->active;
|
||||||
|
|
||||||
|
if (data->active) {
|
||||||
|
animation_start(config->animations[data->current_animation]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
animation_stop(config->animations[data->current_animation]);
|
||||||
|
break;
|
||||||
|
case ANIMATION_CMD_NEXT:
|
||||||
|
data->current_animation++;
|
||||||
|
|
||||||
|
if (data->current_animation == config->animations_size) {
|
||||||
|
data->current_animation = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ANIMATION_CMD_PREVIOUS:
|
||||||
|
if (data->current_animation == 0) {
|
||||||
|
data->current_animation = config->animations_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->current_animation--;
|
||||||
|
break;
|
||||||
|
case ANIMATION_CMD_SELECT:
|
||||||
|
if (config->animations_size < param) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->current_animation = param;
|
||||||
|
break;
|
||||||
|
case ANIMATION_CMD_DIM:
|
||||||
|
if (data->brightness == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->brightness--;
|
||||||
|
|
||||||
|
if (data->brightness == 0) {
|
||||||
|
animation_stop(config->animations[data->current_animation]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ANIMATION_CMD_BRIGHTEN:
|
||||||
|
if (data->brightness == config->brightness_steps) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->brightness == 0) {
|
||||||
|
animation_start(config->animations[data->current_animation]);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->brightness++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force refresh
|
||||||
|
zmk_animation_request_frames(1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void animation_control_start(const struct device *dev) {
|
||||||
|
const struct animation_control_config *config = dev->config;
|
||||||
|
const struct animation_control_data *data = dev->data;
|
||||||
|
|
||||||
|
if (!data->active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
animation_start(config->animations[data->current_animation]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void animation_control_stop(const struct device *dev) {
|
||||||
|
const struct animation_control_config *config = dev->config;
|
||||||
|
const struct animation_control_data *data = dev->data;
|
||||||
|
|
||||||
|
animation_stop(config->animations[data->current_animation]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void animation_control_render_frame(const struct device *dev, struct animation_pixel *pixels,
|
||||||
|
size_t num_pixels) {
|
||||||
|
const struct animation_control_config *config = dev->config;
|
||||||
|
const struct animation_control_data *data = dev->data;
|
||||||
|
|
||||||
|
if (!data->active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
animation_render_frame(config->animations[data->current_animation], pixels, num_pixels);
|
||||||
|
|
||||||
|
if (data->brightness == config->brightness_steps) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float brightness = (float)data->brightness / (float)config->brightness_steps;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < num_pixels; ++i) {
|
||||||
|
pixels[i].value.r *= brightness;
|
||||||
|
pixels[i].value.g *= brightness;
|
||||||
|
pixels[i].value.b *= brightness;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int animation_control_init(const struct device *dev) { return 0; }
|
||||||
|
|
||||||
|
static const struct animation_api animation_control_api = {
|
||||||
|
.on_start = animation_control_start,
|
||||||
|
.on_stop = animation_control_stop,
|
||||||
|
.render_frame = animation_control_render_frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ANIMATION_CONTROL_DEVICE(idx) \
|
||||||
|
\
|
||||||
|
static const struct device *animation_control_##idx##_animations[] = { \
|
||||||
|
ZMK_DT_INST_FOREACH_PROP_ELEM(idx, animations, PHANDLE_TO_DEVICE)}; \
|
||||||
|
\
|
||||||
|
static const struct animation_control_config animation_control_##idx##_config = { \
|
||||||
|
.animations = animation_control_##idx##_animations, \
|
||||||
|
.animations_size = DT_INST_PROP_LEN(idx, animations), \
|
||||||
|
.brightness_steps = DT_INST_PROP(idx, brightness_steps) - 1, \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
static struct animation_control_data animation_control_##idx##_data = { \
|
||||||
|
.active = true, \
|
||||||
|
.brightness = DT_INST_PROP(idx, brightness_steps) - 1, \
|
||||||
|
.current_animation = 0, \
|
||||||
|
}; \
|
||||||
|
\
|
||||||
|
DEVICE_DT_INST_DEFINE(idx, &animation_control_init, NULL, &animation_control_##idx##_data, \
|
||||||
|
&animation_control_##idx##_config, POST_KERNEL, \
|
||||||
|
CONFIG_APPLICATION_INIT_PRIORITY, &animation_control_api);
|
||||||
|
|
||||||
|
DT_INST_FOREACH_STATUS_OKAY(ANIMATION_CONTROL_DEVICE);
|
93
app/src/behaviors/behavior_animation.c
Normal file
93
app/src/behaviors/behavior_animation.c
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 The ZMK Contributors
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <drivers/behavior.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
|
||||||
|
#include <zmk/animation/animation_control.h>
|
||||||
|
|
||||||
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT zmk_animation_control
|
||||||
|
|
||||||
|
#define DEVICE_ADDR(idx) DEVICE_DT_GET(DT_INST(idx, zmk_animation_control)),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control animation instance pointers.
|
||||||
|
*/
|
||||||
|
static const struct device *control_animations[] = {DT_INST_FOREACH_STATUS_OKAY(DEVICE_ADDR)};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of control animation instance pointers array.
|
||||||
|
*/
|
||||||
|
static const uint8_t control_animations_size = sizeof(control_animations);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of the current default control animation instance.
|
||||||
|
*/
|
||||||
|
static uint8_t current_zone = 0;
|
||||||
|
|
||||||
|
#define DT_DRV_COMPAT zmk_behavior_animation
|
||||||
|
|
||||||
|
static int
|
||||||
|
on_keymap_binding_convert_central_state_dependent_params(struct zmk_behavior_binding *binding,
|
||||||
|
struct zmk_behavior_binding_event event) {
|
||||||
|
if ((binding->param1 >> 24) == 0xff) {
|
||||||
|
binding->param1 = (current_zone << 24) | (binding->param1 & 0x00ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||||
|
struct zmk_behavior_binding_event event) {
|
||||||
|
uint8_t value = binding->param1 & 0xff;
|
||||||
|
uint8_t command = (binding->param1 >> 16) & 0xff;
|
||||||
|
uint8_t zone = (binding->param1 >> 24) & 0xff;
|
||||||
|
|
||||||
|
if (command == ANIMATION_CMD_NEXT_CONTROL_ZONE) {
|
||||||
|
current_zone++;
|
||||||
|
|
||||||
|
if (current_zone == control_animations_size) {
|
||||||
|
current_zone = 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == ANIMATION_CMD_PREVIOUS_CONTROL_ZONE) {
|
||||||
|
if (current_zone == 0) {
|
||||||
|
current_zone = control_animations_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_zone--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (control_animations_size <= zone) {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return animation_control_handle_command(control_animations[zone], command, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||||
|
struct zmk_behavior_binding_event event) {
|
||||||
|
return ZMK_BEHAVIOR_OPAQUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int behavior_animation_init(const struct device *dev) { return 0; }
|
||||||
|
|
||||||
|
static const struct behavior_driver_api behavior_animation_driver_api = {
|
||||||
|
.binding_convert_central_state_dependent_params =
|
||||||
|
on_keymap_binding_convert_central_state_dependent_params,
|
||||||
|
.binding_pressed = on_keymap_binding_pressed,
|
||||||
|
.binding_released = on_keymap_binding_released,
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE_DT_INST_DEFINE(0, behavior_animation_init, device_pm_control_nop, NULL, NULL, APPLICATION,
|
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &behavior_animation_driver_api);
|
Loading…
Add table
Reference in a new issue