Implement animation activation/deactivation API and frame scheduling
This commit is contained in:
parent
6697fc4582
commit
19790f2e1a
6 changed files with 117 additions and 23 deletions
|
@ -31,9 +31,25 @@ struct animation_pixel {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef animation_start
|
||||||
|
* @brief Callback API for starting an animation.
|
||||||
|
*
|
||||||
|
* @see animation_start() for argument descriptions.
|
||||||
|
*/
|
||||||
|
typedef void (*animation_api_start)(const struct device *dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef animation_stop
|
||||||
|
* @brief Callback API for stopping an animation.
|
||||||
|
*
|
||||||
|
* @see animation_stop() for argument descriptions.
|
||||||
|
*/
|
||||||
|
typedef void (*animation_api_stop)(const struct device *dev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef animation_render_frame
|
* @typedef animation_render_frame
|
||||||
* @brief Callback API for generating the next animation frame
|
* @brief Callback API for generating the next animation frame.
|
||||||
*
|
*
|
||||||
* @see animation_render_frame() for argument descriptions.
|
* @see animation_render_frame() for argument descriptions.
|
||||||
*/
|
*/
|
||||||
|
@ -41,9 +57,23 @@ typedef void (*animation_api_render_frame)(const struct device *dev, struct anim
|
||||||
size_t num_pixels);
|
size_t num_pixels);
|
||||||
|
|
||||||
struct animation_api {
|
struct animation_api {
|
||||||
|
animation_api_start on_start;
|
||||||
|
animation_api_stop on_stop;
|
||||||
animation_api_render_frame render_frame;
|
animation_api_render_frame render_frame;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void animation_start(const struct device *dev) {
|
||||||
|
const struct animation_api *api = (const struct animation_api *)dev->api;
|
||||||
|
|
||||||
|
return api->on_start(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void animation_stop(const struct device *dev) {
|
||||||
|
const struct animation_api *api = (const struct animation_api *)dev->api;
|
||||||
|
|
||||||
|
return api->on_stop(dev);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void animation_render_frame(const struct device *dev, struct animation_pixel *pixels,
|
static inline void animation_render_frame(const struct device *dev, struct animation_pixel *pixels,
|
||||||
size_t num_pixels) {
|
size_t num_pixels) {
|
||||||
const struct animation_api *api = (const struct animation_api *)dev->api;
|
const struct animation_api *api = (const struct animation_api *)dev->api;
|
||||||
|
|
|
@ -78,6 +78,8 @@ bool zmk_cmp_hsl(const struct zmk_color_hsl *a, const struct zmk_color_hsl *b);
|
||||||
void zmk_interpolate_hsl(const struct zmk_color_hsl *from, const struct zmk_color_hsl *to,
|
void zmk_interpolate_hsl(const struct zmk_color_hsl *from, const struct zmk_color_hsl *to,
|
||||||
struct zmk_color_hsl *result, float step);
|
struct zmk_color_hsl *result, float step);
|
||||||
|
|
||||||
|
void zmk_animation_request_frames(uint32_t frames);
|
||||||
|
|
||||||
struct zmk_color_rgb __zmk_apply_blending_mode(struct zmk_color_rgb base_value,
|
struct zmk_color_rgb __zmk_apply_blending_mode(struct zmk_color_rgb base_value,
|
||||||
struct zmk_color_rgb blend_value, uint8_t mode);
|
struct zmk_color_rgb blend_value, uint8_t mode);
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,11 @@ static const size_t pixels_size = DT_INST_PROP_LEN(0, pixels);
|
||||||
*/
|
*/
|
||||||
static struct led_rgb px_buffer[DT_INST_PROP_LEN(0, pixels)];
|
static struct led_rgb px_buffer[DT_INST_PROP_LEN(0, pixels)];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Counter for animation frames that have been requested but have yet to be executed.
|
||||||
|
*/
|
||||||
|
static uint32_t animation_timer_countdown = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conditional implementation of zmk_animation_get_pixel_by_key_position
|
* Conditional implementation of zmk_animation_get_pixel_by_key_position
|
||||||
* if key-pixels is set.
|
* if key-pixels is set.
|
||||||
|
@ -103,6 +108,7 @@ uint8_t zmk_animation_get_pixel_distance(size_t pixel_idx, size_t other_pixel_id
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void zmk_animation_tick(struct k_work *work) {
|
static void zmk_animation_tick(struct k_work *work) {
|
||||||
|
LOG_DBG("Animation tick");
|
||||||
animation_render_frame(animation_root, &pixels[0], pixels_size);
|
animation_render_frame(animation_root, &pixels[0], pixels_size);
|
||||||
|
|
||||||
for (size_t i = 0; i < pixels_size; ++i) {
|
for (size_t i = 0; i < pixels_size; ++i) {
|
||||||
|
@ -120,10 +126,29 @@ static void zmk_animation_tick(struct k_work *work) {
|
||||||
|
|
||||||
K_WORK_DEFINE(animation_work, zmk_animation_tick);
|
K_WORK_DEFINE(animation_work, zmk_animation_tick);
|
||||||
|
|
||||||
static void zmk_animation_tick_handler(struct k_timer *timer) { k_work_submit(&animation_work); }
|
static void zmk_animation_tick_handler(struct k_timer *timer) {
|
||||||
|
if (--animation_timer_countdown == 0) {
|
||||||
|
k_timer_stop(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
k_work_submit(&animation_work);
|
||||||
|
}
|
||||||
|
|
||||||
K_TIMER_DEFINE(animation_tick, zmk_animation_tick_handler, NULL);
|
K_TIMER_DEFINE(animation_tick, zmk_animation_tick_handler, NULL);
|
||||||
|
|
||||||
|
void zmk_animation_request_frames(uint32_t frames) {
|
||||||
|
if (frames <= animation_timer_countdown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animation_timer_countdown == 0) {
|
||||||
|
k_timer_start(&animation_tick, K_MSEC(1000 / CONFIG_ZMK_ANIMATION_FPS),
|
||||||
|
K_MSEC(1000 / CONFIG_ZMK_ANIMATION_FPS));
|
||||||
|
}
|
||||||
|
|
||||||
|
animation_timer_countdown = frames;
|
||||||
|
}
|
||||||
|
|
||||||
static int zmk_animation_init(const struct device *dev) {
|
static int zmk_animation_init(const struct device *dev) {
|
||||||
#if defined(CONFIG_ZMK_ANIMATION_PIXEL_DISTANCE) && (CONFIG_ZMK_ANIMATION_PIXEL_DISTANCE == 1)
|
#if defined(CONFIG_ZMK_ANIMATION_PIXEL_DISTANCE) && (CONFIG_ZMK_ANIMATION_PIXEL_DISTANCE == 1)
|
||||||
// Prefill the pixel distance lookup table
|
// Prefill the pixel distance lookup table
|
||||||
|
@ -140,7 +165,7 @@ static int zmk_animation_init(const struct device *dev) {
|
||||||
|
|
||||||
LOG_INF("ZMK Animation Ready");
|
LOG_INF("ZMK Animation Ready");
|
||||||
|
|
||||||
k_timer_start(&animation_tick, K_NO_WAIT, K_MSEC(1000 / CONFIG_ZMK_ANIMATION_FPS));
|
animation_start(animation_root);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,27 @@ static void animation_compose_render_frame(const struct device *dev, struct anim
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void animation_compose_start(const struct device *dev) {
|
||||||
|
const struct animation_compose_config *config = dev->config;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < config->animations_size; ++i) {
|
||||||
|
animation_start(config->animations[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void animation_compose_stop(const struct device *dev) {
|
||||||
|
const struct animation_compose_config *config = dev->config;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < config->animations_size; ++i) {
|
||||||
|
animation_stop(config->animations[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int animation_compose_init(const struct device *dev) { return 0; }
|
static int animation_compose_init(const struct device *dev) { return 0; }
|
||||||
|
|
||||||
static const struct animation_api animation_compose_api = {
|
static const struct animation_api animation_compose_api = {
|
||||||
|
.on_start = animation_compose_start,
|
||||||
|
.on_stop = animation_compose_stop,
|
||||||
.render_frame = animation_compose_render_frame,
|
.render_frame = animation_compose_render_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,8 @@ static int animation_ripple_on_key_press(const struct device *dev, const zmk_eve
|
||||||
data->events_end = (data->events_end + 1) % config->event_buffer_size;
|
data->events_end = (data->events_end + 1) % config->event_buffer_size;
|
||||||
data->num_events += 1;
|
data->num_events += 1;
|
||||||
|
|
||||||
|
zmk_animation_request_frames(config->event_frames);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,8 +98,8 @@ static void animation_ripple_render_frame(const struct device *dev, struct anima
|
||||||
uint8_t pixel_distance = zmk_animation_get_pixel_distance(event->pixel_id, j);
|
uint8_t pixel_distance = zmk_animation_get_pixel_distance(event->pixel_id, j);
|
||||||
|
|
||||||
if (config->ripple_width > abs(pixel_distance - event->distance)) {
|
if (config->ripple_width > abs(pixel_distance - event->distance)) {
|
||||||
float intensity =
|
float intensity = 1.0f - (float)abs(pixel_distance - event->distance) /
|
||||||
1.0f - (float)abs(pixel_distance - event->distance) / (float)config->ripple_width;
|
(float)config->ripple_width;
|
||||||
|
|
||||||
struct zmk_color_rgb color = {
|
struct zmk_color_rgb color = {
|
||||||
.r = intensity * data->color_rgb.r,
|
.r = intensity * data->color_rgb.r,
|
||||||
|
@ -125,6 +127,19 @@ static void animation_ripple_render_frame(const struct device *dev, struct anima
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void animation_ripple_start(const struct device *dev) {
|
||||||
|
// Nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
static void animation_ripple_stop(const struct device *dev) {
|
||||||
|
struct animation_ripple_data *data = dev->data;
|
||||||
|
|
||||||
|
// Cancel the processing of any ongoing events.
|
||||||
|
data->num_events = 0;
|
||||||
|
data->events_start = 0;
|
||||||
|
data->events_end = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int animation_ripple_init(const struct device *dev) {
|
static int animation_ripple_init(const struct device *dev) {
|
||||||
const struct animation_ripple_config *config = dev->config;
|
const struct animation_ripple_config *config = dev->config;
|
||||||
struct animation_ripple_data *data = dev->data;
|
struct animation_ripple_data *data = dev->data;
|
||||||
|
@ -135,6 +150,8 @@ static int animation_ripple_init(const struct device *dev) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct animation_api animation_ripple_api = {
|
static const struct animation_api animation_ripple_api = {
|
||||||
|
.on_start = animation_ripple_start,
|
||||||
|
.on_stop = animation_ripple_stop,
|
||||||
.render_frame = animation_ripple_render_frame,
|
.render_frame = animation_ripple_render_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,23 +25,16 @@ struct animation_solid_config {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct animation_solid_data {
|
struct animation_solid_data {
|
||||||
bool has_changed;
|
|
||||||
|
|
||||||
uint16_t counter;
|
uint16_t counter;
|
||||||
|
|
||||||
struct zmk_color_hsl current_hsl;
|
struct zmk_color_hsl current_hsl;
|
||||||
struct zmk_color_rgb current_rgb;
|
struct zmk_color_rgb current_rgb;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void animation_solid_tick(const struct device *dev) {
|
static void animation_solid_update_color(const struct device *dev) {
|
||||||
const struct animation_solid_config *config = dev->config;
|
const struct animation_solid_config *config = dev->config;
|
||||||
struct animation_solid_data *data = dev->data;
|
struct animation_solid_data *data = dev->data;
|
||||||
|
|
||||||
// Animation only contains a single color, nothing to do
|
|
||||||
if (config->num_colors == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t from = data->counter / config->transition_duration;
|
const size_t from = data->counter / config->transition_duration;
|
||||||
const size_t to = (from + 1) % config->num_colors;
|
const size_t to = (from + 1) % config->num_colors;
|
||||||
|
|
||||||
|
@ -51,8 +44,6 @@ static void animation_solid_tick(const struct device *dev) {
|
||||||
(data->counter % config->transition_duration) /
|
(data->counter % config->transition_duration) /
|
||||||
(float)config->transition_duration);
|
(float)config->transition_duration);
|
||||||
|
|
||||||
data->has_changed = !zmk_cmp_hsl(&data->current_hsl, &next_hsl);
|
|
||||||
|
|
||||||
data->current_hsl = next_hsl;
|
data->current_hsl = next_hsl;
|
||||||
zmk_hsl_to_rgb(&data->current_hsl, &data->current_rgb);
|
zmk_hsl_to_rgb(&data->current_hsl, &data->current_rgb);
|
||||||
|
|
||||||
|
@ -64,11 +55,26 @@ static void animation_solid_render_frame(const struct device *dev, struct animat
|
||||||
const struct animation_solid_config *config = dev->config;
|
const struct animation_solid_config *config = dev->config;
|
||||||
struct animation_solid_data *data = dev->data;
|
struct animation_solid_data *data = dev->data;
|
||||||
|
|
||||||
animation_solid_tick(dev);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < config->pixel_map_size; ++i) {
|
for (size_t i = 0; i < config->pixel_map_size; ++i) {
|
||||||
pixels[config->pixel_map[i]].value = data->current_rgb;
|
pixels[config->pixel_map[i]].value = data->current_rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config->num_colors == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request frames on counter reset
|
||||||
|
if (data->counter == 0) {
|
||||||
|
zmk_animation_request_frames(config->duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
animation_solid_update_color(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void animation_solid_start(const struct device *dev) { zmk_animation_request_frames(1); }
|
||||||
|
|
||||||
|
static void animation_solid_stop(const struct device *dev) {
|
||||||
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
|
|
||||||
static int animation_solid_init(const struct device *dev) {
|
static int animation_solid_init(const struct device *dev) {
|
||||||
|
@ -80,16 +86,12 @@ static int animation_solid_init(const struct device *dev) {
|
||||||
|
|
||||||
zmk_hsl_to_rgb(&data->current_hsl, &data->current_rgb);
|
zmk_hsl_to_rgb(&data->current_hsl, &data->current_rgb);
|
||||||
|
|
||||||
// if (config->num_colors == 1) {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// start timer here, so the only option is inline
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct animation_api animation_solid_api = {
|
static const struct animation_api animation_solid_api = {
|
||||||
|
.on_start = animation_solid_start,
|
||||||
|
.on_stop = animation_solid_stop,
|
||||||
.render_frame = animation_solid_render_frame,
|
.render_frame = animation_solid_render_frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue