Implement animation activation/deactivation API and frame scheduling

This commit is contained in:
Kuba Birecki 2021-12-21 18:14:42 +01:00
parent 6697fc4582
commit 19790f2e1a
6 changed files with 117 additions and 23 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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;
} }

View file

@ -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,
}; };

View file

@ -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,
}; };

View file

@ -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,
}; };