mirror of
https://github.com/qmk/qmk_firmware.git
synced 2024-11-27 05:36:52 +00:00
Suspend support for the visualizer
This commit is contained in:
parent
315edb4826
commit
b93d07198a
@ -65,7 +65,7 @@ static keyframe_animation_t startup_animation = {
|
|||||||
.num_frames = 4,
|
.num_frames = 4,
|
||||||
.loop = false,
|
.loop = false,
|
||||||
.frame_lengths = {0, MS2ST(1000), MS2ST(5000), 0},
|
.frame_lengths = {0, MS2ST(1000), MS2ST(5000), 0},
|
||||||
.frame_functions = {display_welcome, keyframe_animate_backlight_color, keyframe_no_operation, user_visualizer_inited},
|
.frame_functions = {display_welcome, keyframe_animate_backlight_color, keyframe_no_operation, enable_visualization},
|
||||||
};
|
};
|
||||||
|
|
||||||
// The color animation animates the LCD color when you change layers
|
// The color animation animates the LCD color when you change layers
|
||||||
|
116
visualizer.c
116
visualizer.c
@ -52,10 +52,14 @@ static visualizer_keyboard_status_t current_status = {
|
|||||||
.layer = 0xFFFFFFFF,
|
.layer = 0xFFFFFFFF,
|
||||||
.default_layer = 0xFFFFFFFF,
|
.default_layer = 0xFFFFFFFF,
|
||||||
.leds = 0xFFFFFFFF,
|
.leds = 0xFFFFFFFF,
|
||||||
|
.suspended = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
|
static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) {
|
||||||
return memcmp(status1, status2, sizeof(visualizer_keyboard_status_t)) == 0;
|
return status1->layer == status2->layer &&
|
||||||
|
status1->default_layer == status2->default_layer &&
|
||||||
|
status1->leds == status2->leds &&
|
||||||
|
status1->suspended == status2->suspended;
|
||||||
}
|
}
|
||||||
|
|
||||||
static event_source_t layer_changed_event;
|
static event_source_t layer_changed_event;
|
||||||
@ -104,6 +108,17 @@ void stop_keyframe_animation(keyframe_animation_t* animation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void stop_all_keyframe_animations(void) {
|
||||||
|
for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
|
||||||
|
if (animations[i]) {
|
||||||
|
animations[i]->current_frame = animations[i]->num_frames;
|
||||||
|
animations[i]->time_left_in_frame = 0;
|
||||||
|
animations[i]->need_update = true;
|
||||||
|
animations[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systime_t delta, systime_t* sleep_time) {
|
static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systime_t delta, systime_t* sleep_time) {
|
||||||
dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
|
dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
|
||||||
animation->time_left_in_frame, delta);
|
animation->time_left_in_frame, delta);
|
||||||
@ -252,7 +267,19 @@ bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_s
|
|||||||
}
|
}
|
||||||
#endif // LCD_ENABLE
|
#endif // LCD_ENABLE
|
||||||
|
|
||||||
bool user_visualizer_inited(keyframe_animation_t* animation, visualizer_state_t* state) {
|
bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
|
||||||
|
(void)animation;
|
||||||
|
(void)state;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state) {
|
||||||
|
(void)animation;
|
||||||
|
(void)state;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state) {
|
||||||
(void)animation;
|
(void)animation;
|
||||||
(void)state;
|
(void)state;
|
||||||
dprint("User visualizer inited\n");
|
dprint("User visualizer inited\n");
|
||||||
@ -268,13 +295,15 @@ static THD_FUNCTION(visualizerThread, arg) {
|
|||||||
event_listener_t event_listener;
|
event_listener_t event_listener;
|
||||||
chEvtRegister(&layer_changed_event, &event_listener, 0);
|
chEvtRegister(&layer_changed_event, &event_listener, 0);
|
||||||
|
|
||||||
visualizer_state_t state = {
|
visualizer_keyboard_status_t initial_status = {
|
||||||
.status = {
|
.default_layer = 0xFFFFFFFF,
|
||||||
.default_layer = 0xFFFFFFFF,
|
.layer = 0xFFFFFFFF,
|
||||||
.layer = 0xFFFFFFFF,
|
.leds = 0xFFFFFFFF,
|
||||||
.leds = 0xFFFFFFFF,
|
.suspended = false,
|
||||||
},
|
};
|
||||||
|
|
||||||
|
visualizer_state_t state = {
|
||||||
|
.status = initial_status,
|
||||||
.current_lcd_color = 0,
|
.current_lcd_color = 0,
|
||||||
#ifdef LCD_ENABLE
|
#ifdef LCD_ENABLE
|
||||||
.font_fixed5x8 = gdispOpenFont("fixed_5x8"),
|
.font_fixed5x8 = gdispOpenFont("fixed_5x8"),
|
||||||
@ -301,17 +330,36 @@ static THD_FUNCTION(visualizerThread, arg) {
|
|||||||
bool enabled = visualizer_enabled;
|
bool enabled = visualizer_enabled;
|
||||||
if (!same_status(&state.status, ¤t_status)) {
|
if (!same_status(&state.status, ¤t_status)) {
|
||||||
if (visualizer_enabled) {
|
if (visualizer_enabled) {
|
||||||
state.status = current_status;
|
if (current_status.suspended) {
|
||||||
update_user_visualizer_state(&state);
|
stop_all_keyframe_animations();
|
||||||
state.prev_lcd_color = state.current_lcd_color;
|
visualizer_enabled = false;
|
||||||
|
state.status = current_status;
|
||||||
|
user_visualizer_suspend(&state);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
state.status = current_status;
|
||||||
|
update_user_visualizer_state(&state);
|
||||||
|
state.prev_lcd_color = state.current_lcd_color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!enabled && state.status.suspended && current_status.suspended == false) {
|
||||||
|
// Setting the status to the initial status will force an update
|
||||||
|
// when the visualizer is enabled again
|
||||||
|
state.status = initial_status;
|
||||||
|
state.status.suspended = false;
|
||||||
|
stop_all_keyframe_animations();
|
||||||
|
user_visualizer_resume(&state);
|
||||||
|
}
|
||||||
sleep_time = TIME_INFINITE;
|
sleep_time = TIME_INFINITE;
|
||||||
for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
|
for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
|
||||||
if (animations[i]) {
|
if (animations[i]) {
|
||||||
update_keyframe_animation(animations[i], &state, delta, &sleep_time);
|
update_keyframe_animation(animations[i], &state, delta, &sleep_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// The animation can enable the visualizer
|
||||||
|
// And we might need to update the state when that happens
|
||||||
|
// so don't sleep
|
||||||
if (enabled != visualizer_enabled) {
|
if (enabled != visualizer_enabled) {
|
||||||
sleep_time = 0;
|
sleep_time = 0;
|
||||||
}
|
}
|
||||||
@ -354,7 +402,24 @@ void visualizer_init(void) {
|
|||||||
LOWPRIO, visualizerThread, NULL);
|
LOWPRIO, visualizerThread, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visualizer_set_state(uint32_t default_state, uint32_t state, uint32_t leds) {
|
void update_status(bool changed) {
|
||||||
|
if (changed) {
|
||||||
|
chEvtBroadcast(&layer_changed_event);
|
||||||
|
}
|
||||||
|
#ifdef USE_SERIAL_LINK
|
||||||
|
static systime_t last_update = 0;
|
||||||
|
systime_t current_update = chVTGetSystemTimeX();
|
||||||
|
systime_t delta = current_update - last_update;
|
||||||
|
if (changed || delta > MS2ST(10)) {
|
||||||
|
last_update = current_update;
|
||||||
|
visualizer_keyboard_status_t* r = begin_write_current_status();
|
||||||
|
*r = current_status;
|
||||||
|
end_write_current_status();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds) {
|
||||||
// Note that there's a small race condition here, the thread could read
|
// Note that there's a small race condition here, the thread could read
|
||||||
// a state where one of these are set but not the other. But this should
|
// a state where one of these are set but not the other. But this should
|
||||||
// not really matter as it will be fixed during the next loop step.
|
// not really matter as it will be fixed during the next loop step.
|
||||||
@ -379,25 +444,22 @@ void visualizer_set_state(uint32_t default_state, uint32_t state, uint32_t leds)
|
|||||||
.layer = state,
|
.layer = state,
|
||||||
.default_layer = default_state,
|
.default_layer = default_state,
|
||||||
.leds = leds,
|
.leds = leds,
|
||||||
|
.suspended = current_status.suspended,
|
||||||
};
|
};
|
||||||
if (!same_status(¤t_status, &new_status)) {
|
if (!same_status(¤t_status, &new_status)) {
|
||||||
changed = true;
|
changed = true;
|
||||||
current_status = new_status;
|
current_status = new_status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (changed) {
|
update_status(changed);
|
||||||
chEvtBroadcast(&layer_changed_event);
|
}
|
||||||
|
|
||||||
}
|
void visualizer_suspend(void) {
|
||||||
#ifdef USE_SERIAL_LINK
|
current_status.suspended = true;
|
||||||
static systime_t last_update = 0;
|
update_status(true);
|
||||||
systime_t current_update = chVTGetSystemTimeX();
|
}
|
||||||
systime_t delta = current_update - last_update;
|
|
||||||
if (changed || delta > MS2ST(10)) {
|
void visualizer_resume(void) {
|
||||||
last_update = current_update;
|
current_status.suspended = false;
|
||||||
visualizer_keyboard_status_t* r = begin_write_current_status();
|
update_status(true);
|
||||||
*r = current_status;
|
|
||||||
end_write_current_status();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
17
visualizer.h
17
visualizer.h
@ -38,8 +38,12 @@ SOFTWARE.
|
|||||||
|
|
||||||
// This need to be called once at the start
|
// This need to be called once at the start
|
||||||
void visualizer_init(void);
|
void visualizer_init(void);
|
||||||
// This should be called before every matrix scan
|
// This should be called at every matrix scan
|
||||||
void visualizer_set_state(uint32_t default_state, uint32_t state, uint32_t leds);
|
void visualizer_update(uint32_t default_state, uint32_t state, uint32_t leds);
|
||||||
|
// This should be called when the keyboard goes to suspend state
|
||||||
|
void visualizer_suspend(void);
|
||||||
|
// This should be called when the keyboard wakes up from suspend state
|
||||||
|
void visualizer_resume(void);
|
||||||
|
|
||||||
// If you need support for more than 8 keyframes per animation, you can change this
|
// If you need support for more than 8 keyframes per animation, you can change this
|
||||||
#define MAX_VISUALIZER_KEY_FRAMES 8
|
#define MAX_VISUALIZER_KEY_FRAMES 8
|
||||||
@ -50,6 +54,7 @@ typedef struct {
|
|||||||
uint32_t layer;
|
uint32_t layer;
|
||||||
uint32_t default_layer;
|
uint32_t default_layer;
|
||||||
uint32_t leds; // See led.h for available statuses
|
uint32_t leds; // See led.h for available statuses
|
||||||
|
bool suspended;
|
||||||
} visualizer_keyboard_status_t;
|
} visualizer_keyboard_status_t;
|
||||||
|
|
||||||
// The state struct is used by the various keyframe functions
|
// The state struct is used by the various keyframe functions
|
||||||
@ -108,13 +113,19 @@ bool keyframe_set_backlight_color(keyframe_animation_t* animation, visualizer_st
|
|||||||
bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
|
bool keyframe_display_layer_text(keyframe_animation_t* animation, visualizer_state_t* state);
|
||||||
// Displays a bitmap (0/1) of all the currently active layers
|
// Displays a bitmap (0/1) of all the currently active layers
|
||||||
bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
|
bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_state_t* state);
|
||||||
|
|
||||||
|
bool keyframe_disable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
|
||||||
|
bool keyframe_enable_lcd_and_backlight(keyframe_animation_t* animation, visualizer_state_t* state);
|
||||||
|
|
||||||
// Call this once, when the initial animation has finished, alternatively you can call it
|
// Call this once, when the initial animation has finished, alternatively you can call it
|
||||||
// directly from the initalize_user_visualizer function (the animation can be null)
|
// directly from the initalize_user_visualizer function (the animation can be null)
|
||||||
bool user_visualizer_inited(keyframe_animation_t* animation, visualizer_state_t* state);
|
bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* state);
|
||||||
|
|
||||||
// These two functions have to be implemented by the user
|
// These two functions have to be implemented by the user
|
||||||
void initialize_user_visualizer(visualizer_state_t* state);
|
void initialize_user_visualizer(visualizer_state_t* state);
|
||||||
void update_user_visualizer_state(visualizer_state_t* state);
|
void update_user_visualizer_state(visualizer_state_t* state);
|
||||||
|
void user_visualizer_suspend(visualizer_state_t* state);
|
||||||
|
void user_visualizer_resume(visualizer_state_t* state);
|
||||||
|
|
||||||
|
|
||||||
#endif /* VISUALIZER_H */
|
#endif /* VISUALIZER_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user