aboutsummaryrefslogtreecommitdiff
path: root/quantum/visualizer/visualizer.c
diff options
context:
space:
mode:
authorFred Sundvik <fsundvik@gmail.com>2016-07-06 20:30:58 +0300
committerFred Sundvik <fsundvik@gmail.com>2016-07-06 20:30:58 +0300
commit6c296557909501b71fe344ce379e74094cf77c8e (patch)
treee02fdb7bb85a16de027c6c1946817e96d5304ab3 /quantum/visualizer/visualizer.c
parentf727801bc69b3db28f84b7b8986756193bbfd21e (diff)
parent73d890a2c9c34b905cd5e74e7146fdd4578dcb96 (diff)
downloadqmk_firmware-6c296557909501b71fe344ce379e74094cf77c8e.tar.gz
qmk_firmware-6c296557909501b71fe344ce379e74094cf77c8e.zip
Merge commit '73d890a2c9c34b905cd5e74e7146fdd4578dcb96' into add_visualizer
Diffstat (limited to 'quantum/visualizer/visualizer.c')
-rw-r--r--quantum/visualizer/visualizer.c104
1 files changed, 86 insertions, 18 deletions
diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c
index 605be3059..c24073405 100644
--- a/quantum/visualizer/visualizer.c
+++ b/quantum/visualizer/visualizer.c
@@ -23,9 +23,11 @@ SOFTWARE.
23*/ 23*/
24 24
25#include "visualizer.h" 25#include "visualizer.h"
26#include "ch.h"
27#include "config.h" 26#include "config.h"
28#include <string.h> 27#include <string.h>
28#ifdef PROTOCOL_CHIBIOS
29#include "ch.h"
30#endif
29 31
30#ifdef LCD_ENABLE 32#ifdef LCD_ENABLE
31#include "gfx.h" 33#include "gfx.h"
@@ -68,7 +70,6 @@ static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboa
68 status1->suspended == status2->suspended; 70 status1->suspended == status2->suspended;
69} 71}
70 72
71static event_source_t layer_changed_event;
72static bool visualizer_enabled = false; 73static bool visualizer_enabled = false;
73 74
74#define MAX_SIMULTANEOUS_ANIMATIONS 4 75#define MAX_SIMULTANEOUS_ANIMATIONS 4
@@ -83,6 +84,18 @@ static remote_object_t* remote_objects[] = {
83 84
84#endif 85#endif
85 86
87GDisplay* LCD_DISPLAY = 0;
88GDisplay* LED_DISPLAY = 0;
89
90__attribute__((weak))
91GDisplay* get_lcd_display(void) {
92 return gdispGetDisplay(0);
93}
94
95__attribute__((weak))
96GDisplay* get_led_display(void) {
97 return gdispGetDisplay(1);
98}
86 99
87void start_keyframe_animation(keyframe_animation_t* animation) { 100void start_keyframe_animation(keyframe_animation_t* animation) {
88 animation->current_frame = -1; 101 animation->current_frame = -1;
@@ -106,6 +119,8 @@ void stop_keyframe_animation(keyframe_animation_t* animation) {
106 animation->current_frame = animation->num_frames; 119 animation->current_frame = animation->num_frames;
107 animation->time_left_in_frame = 0; 120 animation->time_left_in_frame = 0;
108 animation->need_update = true; 121 animation->need_update = true;
122 animation->first_update_of_frame = false;
123 animation->last_update_of_frame = false;
109 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) { 124 for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
110 if (animations[i] == animation) { 125 if (animations[i] == animation) {
111 animations[i] = NULL; 126 animations[i] = NULL;
@@ -120,12 +135,15 @@ void stop_all_keyframe_animations(void) {
120 animations[i]->current_frame = animations[i]->num_frames; 135 animations[i]->current_frame = animations[i]->num_frames;
121 animations[i]->time_left_in_frame = 0; 136 animations[i]->time_left_in_frame = 0;
122 animations[i]->need_update = true; 137 animations[i]->need_update = true;
138 animations[i]->first_update_of_frame = false;
139 animations[i]->last_update_of_frame = false;
123 animations[i] = NULL; 140 animations[i] = NULL;
124 } 141 }
125 } 142 }
126} 143}
127 144
128static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systime_t delta, systime_t* sleep_time) { 145static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) {
146 // TODO: Clean up this messy code
129 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame, 147 dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
130 animation->time_left_in_frame, delta); 148 animation->time_left_in_frame, delta);
131 if (animation->current_frame == animation->num_frames) { 149 if (animation->current_frame == animation->num_frames) {
@@ -136,16 +154,20 @@ static bool update_keyframe_animation(keyframe_animation_t* animation, visualize
136 animation->current_frame = 0; 154 animation->current_frame = 0;
137 animation->time_left_in_frame = animation->frame_lengths[0]; 155 animation->time_left_in_frame = animation->frame_lengths[0];
138 animation->need_update = true; 156 animation->need_update = true;
157 animation->first_update_of_frame = true;
139 } else { 158 } else {
140 animation->time_left_in_frame -= delta; 159 animation->time_left_in_frame -= delta;
141 while (animation->time_left_in_frame <= 0) { 160 while (animation->time_left_in_frame <= 0) {
142 int left = animation->time_left_in_frame; 161 int left = animation->time_left_in_frame;
143 if (animation->need_update) { 162 if (animation->need_update) {
144 animation->time_left_in_frame = 0; 163 animation->time_left_in_frame = 0;
164 animation->last_update_of_frame = true;
145 (*animation->frame_functions[animation->current_frame])(animation, state); 165 (*animation->frame_functions[animation->current_frame])(animation, state);
166 animation->last_update_of_frame = false;
146 } 167 }
147 animation->current_frame++; 168 animation->current_frame++;
148 animation->need_update = true; 169 animation->need_update = true;
170 animation->first_update_of_frame = true;
149 if (animation->current_frame == animation->num_frames) { 171 if (animation->current_frame == animation->num_frames) {
150 if (animation->loop) { 172 if (animation->loop) {
151 animation->current_frame = 0; 173 animation->current_frame = 0;
@@ -162,16 +184,32 @@ static bool update_keyframe_animation(keyframe_animation_t* animation, visualize
162 } 184 }
163 if (animation->need_update) { 185 if (animation->need_update) {
164 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state); 186 animation->need_update = (*animation->frame_functions[animation->current_frame])(animation, state);
187 animation->first_update_of_frame = false;
165 } 188 }
166 189
167 int wanted_sleep = animation->need_update ? 10 : animation->time_left_in_frame; 190 systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame;
168 if ((unsigned)wanted_sleep < *sleep_time) { 191 if (wanted_sleep < *sleep_time) {
169 *sleep_time = wanted_sleep; 192 *sleep_time = wanted_sleep;
170 } 193 }
171 194
172 return true; 195 return true;
173} 196}
174 197
198void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) {
199 int next_frame = animation->current_frame + 1;
200 if (next_frame == animation->num_frames) {
201 next_frame = 0;
202 }
203 keyframe_animation_t temp_animation = *animation;
204 temp_animation.current_frame = next_frame;
205 temp_animation.time_left_in_frame = animation->frame_lengths[next_frame];
206 temp_animation.first_update_of_frame = true;
207 temp_animation.last_update_of_frame = false;
208 temp_animation.need_update = false;
209 visualizer_state_t temp_state = *state;
210 (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state);
211}
212
175bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) { 213bool keyframe_no_operation(keyframe_animation_t* animation, visualizer_state_t* state) {
176 (void)animation; 214 (void)animation;
177 (void)state; 215 (void)state;
@@ -303,12 +341,13 @@ bool enable_visualization(keyframe_animation_t* animation, visualizer_state_t* s
303} 341}
304 342
305// TODO: Optimize the stack size, this is probably way too big 343// TODO: Optimize the stack size, this is probably way too big
306static THD_WORKING_AREA(visualizerThreadStack, 1024); 344static DECLARE_THREAD_STACK(visualizerThreadStack, 1024);
307static THD_FUNCTION(visualizerThread, arg) { 345static DECLARE_THREAD_FUNCTION(visualizerThread, arg) {
308 (void)arg; 346 (void)arg;
309 347
310 event_listener_t event_listener; 348 GListener event_listener;
311 chEvtRegister(&layer_changed_event, &event_listener, 0); 349 geventListenerInit(&event_listener);
350 geventAttachSource(&event_listener, (GSourceHandle)&current_status, 0);
312 351
313 visualizer_keyboard_status_t initial_status = { 352 visualizer_keyboard_status_t initial_status = {
314 .default_layer = 0xFFFFFFFF, 353 .default_layer = 0xFFFFFFFF,
@@ -335,12 +374,12 @@ static THD_FUNCTION(visualizerThread, arg) {
335 LCD_INT(state.current_lcd_color)); 374 LCD_INT(state.current_lcd_color));
336#endif 375#endif
337 376
338 systime_t sleep_time = TIME_INFINITE; 377 systemticks_t sleep_time = TIME_INFINITE;
339 systime_t current_time = chVTGetSystemTimeX(); 378 systemticks_t current_time = gfxSystemTicks();
340 379
341 while(true) { 380 while(true) {
342 systime_t new_time = chVTGetSystemTimeX(); 381 systemticks_t new_time = gfxSystemTicks();
343 systime_t delta = new_time - current_time; 382 systemticks_t delta = new_time - current_time;
344 current_time = new_time; 383 current_time = new_time;
345 bool enabled = visualizer_enabled; 384 bool enabled = visualizer_enabled;
346 if (!same_status(&state.status, &current_status)) { 385 if (!same_status(&state.status, &current_status)) {
@@ -373,6 +412,13 @@ static THD_FUNCTION(visualizerThread, arg) {
373 update_keyframe_animation(animations[i], &state, delta, &sleep_time); 412 update_keyframe_animation(animations[i], &state, delta, &sleep_time);
374 } 413 }
375 } 414 }
415#ifdef LED_ENABLE
416 gdispGFlush(LED_DISPLAY);
417#endif
418
419#ifdef EMULATOR
420 draw_emulator();
421#endif
376 // The animation can enable the visualizer 422 // The animation can enable the visualizer
377 // And we might need to update the state when that happens 423 // And we might need to update the state when that happens
378 // so don't sleep 424 // so don't sleep
@@ -380,7 +426,7 @@ static THD_FUNCTION(visualizerThread, arg) {
380 sleep_time = 0; 426 sleep_time = 0;
381 } 427 }
382 428
383 systime_t after_update = chVTGetSystemTimeX(); 429 systemticks_t after_update = gfxSystemTicks();
384 unsigned update_delta = after_update - current_time; 430 unsigned update_delta = after_update - current_time;
385 if (sleep_time != TIME_INFINITE) { 431 if (sleep_time != TIME_INFINITE) {
386 if (sleep_time > update_delta) { 432 if (sleep_time > update_delta) {
@@ -391,12 +437,24 @@ static THD_FUNCTION(visualizerThread, arg) {
391 } 437 }
392 } 438 }
393 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time); 439 dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time);
394 chEvtWaitOneTimeout(EVENT_MASK(0), sleep_time); 440#ifdef PROTOCOL_CHIBIOS
441 // The gEventWait function really takes milliseconds, even if the documentation says ticks.
442 // Unfortunately there's no generic ugfx conversion from system time to milliseconds,
443 // so let's do it in a platform dependent way.
444
445 // On windows the system ticks is the same as milliseconds anyway
446 if (sleep_time != TIME_INFINITE) {
447 sleep_time = ST2MS(sleep_time);
448 }
449#endif
450 geventEventWait(&event_listener, sleep_time);
395 } 451 }
396#ifdef LCD_ENABLE 452#ifdef LCD_ENABLE
397 gdispCloseFont(state.font_fixed5x8); 453 gdispCloseFont(state.font_fixed5x8);
398 gdispCloseFont(state.font_dejavusansbold12); 454 gdispCloseFont(state.font_dejavusansbold12);
399#endif 455#endif
456
457 return 0;
400} 458}
401 459
402void visualizer_init(void) { 460void visualizer_init(void) {
@@ -411,16 +469,26 @@ void visualizer_init(void) {
411#ifdef USE_SERIAL_LINK 469#ifdef USE_SERIAL_LINK
412 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) ); 470 add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) );
413#endif 471#endif
472
473#ifdef LCD_ENABLE
474 LCD_DISPLAY = get_lcd_display();
475#endif
476#ifdef LED_ENABLE
477 LED_DISPLAY = get_led_display();
478#endif
479
414 // We are using a low priority thread, the idea is to have it run only 480 // We are using a low priority thread, the idea is to have it run only
415 // when the main thread is sleeping during the matrix scanning 481 // when the main thread is sleeping during the matrix scanning
416 chEvtObjectInit(&layer_changed_event); 482 gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack),
417 (void)chThdCreateStatic(visualizerThreadStack, sizeof(visualizerThreadStack),
418 VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL); 483 VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL);
419} 484}
420 485
421void update_status(bool changed) { 486void update_status(bool changed) {
422 if (changed) { 487 if (changed) {
423 chEvtBroadcast(&layer_changed_event); 488 GSourceListener* listener = geventGetSourceListener((GSourceHandle)&current_status, NULL);
489 if (listener) {
490 geventSendEvent(listener);
491 }
424 } 492 }
425#ifdef USE_SERIAL_LINK 493#ifdef USE_SERIAL_LINK
426 static systime_t last_update = 0; 494 static systime_t last_update = 0;