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/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_solid.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)
|
||||
add_subdirectory(src/split)
|
||||
|
|
|
@ -19,3 +19,4 @@
|
|||
#include <behaviors/key_repeat.dtsi>
|
||||
#include <behaviors/backlight.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
|
||||
#define HSL(h, s, l) (h + (s << 16) + (l << 24))
|
||||
#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