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" {
|
||||
#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
|
||||
* @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.
|
||||
*/
|
||||
|
@ -41,9 +57,23 @@ typedef void (*animation_api_render_frame)(const struct device *dev, struct anim
|
|||
size_t num_pixels);
|
||||
|
||||
struct animation_api {
|
||||
animation_api_start on_start;
|
||||
animation_api_stop on_stop;
|
||||
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,
|
||||
size_t num_pixels) {
|
||||
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,
|
||||
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 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)];
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
|
||||
static void zmk_animation_tick(struct k_work *work) {
|
||||
LOG_DBG("Animation tick");
|
||||
animation_render_frame(animation_root, &pixels[0], pixels_size);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
#if defined(CONFIG_ZMK_ANIMATION_PIXEL_DISTANCE) && (CONFIG_ZMK_ANIMATION_PIXEL_DISTANCE == 1)
|
||||
// Prefill the pixel distance lookup table
|
||||
|
@ -140,7 +165,7 @@ static int zmk_animation_init(const struct device *dev) {
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 const struct animation_api animation_compose_api = {
|
||||
.on_start = animation_compose_start,
|
||||
.on_stop = animation_compose_stop,
|
||||
.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->num_events += 1;
|
||||
|
||||
zmk_animation_request_frames(config->event_frames);
|
||||
|
||||
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);
|
||||
|
||||
if (config->ripple_width > abs(pixel_distance - event->distance)) {
|
||||
float intensity =
|
||||
1.0f - (float)abs(pixel_distance - event->distance) / (float)config->ripple_width;
|
||||
float intensity = 1.0f - (float)abs(pixel_distance - event->distance) /
|
||||
(float)config->ripple_width;
|
||||
|
||||
struct zmk_color_rgb color = {
|
||||
.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) {
|
||||
const struct animation_ripple_config *config = dev->config;
|
||||
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 = {
|
||||
.on_start = animation_ripple_start,
|
||||
.on_stop = animation_ripple_stop,
|
||||
.render_frame = animation_ripple_render_frame,
|
||||
};
|
||||
|
||||
|
|
|
@ -25,23 +25,16 @@ struct animation_solid_config {
|
|||
};
|
||||
|
||||
struct animation_solid_data {
|
||||
bool has_changed;
|
||||
|
||||
uint16_t counter;
|
||||
|
||||
struct zmk_color_hsl current_hsl;
|
||||
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;
|
||||
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 to = (from + 1) % config->num_colors;
|
||||
|
||||
|
@ -51,8 +44,6 @@ static void animation_solid_tick(const struct device *dev) {
|
|||
(data->counter % config->transition_duration) /
|
||||
(float)config->transition_duration);
|
||||
|
||||
data->has_changed = !zmk_cmp_hsl(&data->current_hsl, &next_hsl);
|
||||
|
||||
data->current_hsl = next_hsl;
|
||||
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;
|
||||
struct animation_solid_data *data = dev->data;
|
||||
|
||||
animation_solid_tick(dev);
|
||||
|
||||
for (size_t i = 0; i < config->pixel_map_size; ++i) {
|
||||
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) {
|
||||
|
@ -80,16 +86,12 @@ static int animation_solid_init(const struct device *dev) {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
static const struct animation_api animation_solid_api = {
|
||||
.on_start = animation_solid_start,
|
||||
.on_stop = animation_solid_stop,
|
||||
.render_frame = animation_solid_render_frame,
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue