diff options
Diffstat (limited to 'quantum/visualizer/visualizer.c')
| -rw-r--r-- | quantum/visualizer/visualizer.c | 483 | 
1 files changed, 0 insertions, 483 deletions
| diff --git a/quantum/visualizer/visualizer.c b/quantum/visualizer/visualizer.c deleted file mode 100644 index 709affbb77..0000000000 --- a/quantum/visualizer/visualizer.c +++ /dev/null @@ -1,483 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2016 Fred Sundvik - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "config.h" -#include "visualizer.h" -#include <string.h> -#ifdef PROTOCOL_CHIBIOS -#    include <ch.h> -#endif - -#include "gfx.h" - -#ifdef LCD_BACKLIGHT_ENABLE -#    include "lcd_backlight.h" -#endif - -//#define DEBUG_VISUALIZER - -#ifdef DEBUG_VISUALIZER -#    include "debug.h" -#else -#    include "nodebug.h" -#endif - -#ifdef SERIAL_LINK_ENABLE -#    include "serial_link/protocol/transport.h" -#    include "serial_link/system/serial_link.h" -#endif - -#include "action_util.h" - -// Define this in config.h -#ifndef VISUALIZER_THREAD_PRIORITY -// The visualizer needs gfx thread priorities -#    define VISUALIZER_THREAD_PRIORITY (NORMAL_PRIORITY - 2) -#endif - -static visualizer_keyboard_status_t current_status = {.layer         = 0xFFFFFFFF, -                                                      .default_layer = 0xFFFFFFFF, -                                                      .leds          = 0xFFFFFFFF, -#ifdef BACKLIGHT_ENABLE -                                                      .backlight_level = 0, -#endif -                                                      .mods      = 0xFF, -                                                      .suspended = false, -#ifdef VISUALIZER_USER_DATA_SIZE -                                                      .user_data = {0} -#endif -}; - -static bool same_status(visualizer_keyboard_status_t* status1, visualizer_keyboard_status_t* status2) { -    return status1->layer == status2->layer && status1->default_layer == status2->default_layer && status1->mods == status2->mods && status1->leds == status2->leds && status1->suspended == status2->suspended -#ifdef BACKLIGHT_ENABLE -           && status1->backlight_level == status2->backlight_level -#endif -#ifdef VISUALIZER_USER_DATA_SIZE -           && memcmp(status1->user_data, status2->user_data, VISUALIZER_USER_DATA_SIZE) == 0 -#endif -        ; -} - -static bool visualizer_enabled = false; - -#ifdef VISUALIZER_USER_DATA_SIZE -static uint8_t user_data[VISUALIZER_USER_DATA_SIZE]; -#endif - -#define MAX_SIMULTANEOUS_ANIMATIONS 4 -static keyframe_animation_t* animations[MAX_SIMULTANEOUS_ANIMATIONS] = {}; - -#ifdef SERIAL_LINK_ENABLE -MASTER_TO_ALL_SLAVES_OBJECT(current_status, visualizer_keyboard_status_t); - -static remote_object_t* remote_objects[] = { -    REMOTE_OBJECT(current_status), -}; - -#endif - -GDisplay* LCD_DISPLAY = 0; -GDisplay* LED_DISPLAY = 0; - -#ifdef LCD_DISPLAY_NUMBER -__attribute__((weak)) GDisplay* get_lcd_display(void) { return gdispGetDisplay(LCD_DISPLAY_NUMBER); } -#endif - -#ifdef LED_DISPLAY_NUMBER -__attribute__((weak)) GDisplay* get_led_display(void) { return gdispGetDisplay(LED_DISPLAY_NUMBER); } -#endif - -void start_keyframe_animation(keyframe_animation_t* animation) { -    animation->current_frame      = -1; -    animation->time_left_in_frame = 0; -    animation->need_update        = true; -    int free_index                = -1; -    for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { -        if (animations[i] == animation) { -            return; -        } -        if (free_index == -1 && animations[i] == NULL) { -            free_index = i; -        } -    } -    if (free_index != -1) { -        animations[free_index] = animation; -    } -} - -void stop_keyframe_animation(keyframe_animation_t* animation) { -    animation->current_frame         = animation->num_frames; -    animation->time_left_in_frame    = 0; -    animation->need_update           = true; -    animation->first_update_of_frame = false; -    animation->last_update_of_frame  = false; -    for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { -        if (animations[i] == animation) { -            animations[i] = NULL; -            return; -        } -    } -} - -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]->first_update_of_frame = false; -            animations[i]->last_update_of_frame  = false; -            animations[i]                        = NULL; -        } -    } -} - -static uint8_t get_num_running_animations(void) { -    uint8_t count = 0; -    for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { -        count += animations[i] ? 1 : 0; -    } -    return count; -} - -static bool update_keyframe_animation(keyframe_animation_t* animation, visualizer_state_t* state, systemticks_t delta, systemticks_t* sleep_time) { -    // TODO: Clean up this messy code -    dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame, animation->time_left_in_frame, delta); -    if (animation->current_frame == animation->num_frames) { -        animation->need_update = false; -        return false; -    } -    if (animation->current_frame == -1) { -        animation->current_frame         = 0; -        animation->time_left_in_frame    = animation->frame_lengths[0]; -        animation->need_update           = true; -        animation->first_update_of_frame = true; -    } else { -        animation->time_left_in_frame -= delta; -        while (animation->time_left_in_frame <= 0) { -            int left = animation->time_left_in_frame; -            if (animation->need_update) { -                animation->time_left_in_frame   = 0; -                animation->last_update_of_frame = true; -                (*animation->frame_functions[animation->current_frame])(animation, state); -                animation->last_update_of_frame = false; -            } -            animation->current_frame++; -            animation->need_update           = true; -            animation->first_update_of_frame = true; -            if (animation->current_frame == animation->num_frames) { -                if (animation->loop) { -                    animation->current_frame = 0; -                } else { -                    stop_keyframe_animation(animation); -                    return false; -                } -            } -            delta                         = -left; -            animation->time_left_in_frame = animation->frame_lengths[animation->current_frame]; -            animation->time_left_in_frame -= delta; -        } -    } -    if (animation->need_update) { -        animation->need_update           = (*animation->frame_functions[animation->current_frame])(animation, state); -        animation->first_update_of_frame = false; -    } - -    systemticks_t wanted_sleep = animation->need_update ? gfxMillisecondsToTicks(10) : (unsigned)animation->time_left_in_frame; -    if (wanted_sleep < *sleep_time) { -        *sleep_time = wanted_sleep; -    } - -    return true; -} - -void run_next_keyframe(keyframe_animation_t* animation, visualizer_state_t* state) { -    int next_frame = animation->current_frame + 1; -    if (next_frame == animation->num_frames) { -        next_frame = 0; -    } -    keyframe_animation_t temp_animation  = *animation; -    temp_animation.current_frame         = next_frame; -    temp_animation.time_left_in_frame    = animation->frame_lengths[next_frame]; -    temp_animation.first_update_of_frame = true; -    temp_animation.last_update_of_frame  = false; -    temp_animation.need_update           = false; -    visualizer_state_t temp_state        = *state; -    (*temp_animation.frame_functions[next_frame])(&temp_animation, &temp_state); -} - -// TODO: Optimize the stack size, this is probably way too big -static DECLARE_THREAD_STACK(visualizerThreadStack, 1024); -static DECLARE_THREAD_FUNCTION(visualizerThread, arg) { -    (void)arg; - -    GListener event_listener; -    geventListenerInit(&event_listener); -    geventAttachSource(&event_listener, (GSourceHandle)¤t_status, 0); - -    visualizer_keyboard_status_t initial_status = { -        .default_layer = 0xFFFFFFFF, -        .layer         = 0xFFFFFFFF, -        .mods          = 0xFF, -        .leds          = 0xFFFFFFFF, -        .suspended     = false, -#ifdef BACKLIGHT_ENABLE -        .backlight_level = 0, -#endif -#ifdef VISUALIZER_USER_DATA_SIZE -        .user_data = {0}, -#endif -    }; - -    visualizer_state_t state = {.status            = initial_status, -                                .current_lcd_color = 0, -#ifdef LCD_ENABLE -                                .font_fixed5x8         = gdispOpenFont("fixed_5x8"), -                                .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12") -#endif -    }; -    initialize_user_visualizer(&state); -    state.prev_lcd_color = state.current_lcd_color; - -#ifdef LCD_BACKLIGHT_ENABLE -    lcd_backlight_color(LCD_HUE(state.current_lcd_color), LCD_SAT(state.current_lcd_color), LCD_INT(state.current_lcd_color)); -#endif - -    systemticks_t sleep_time   = TIME_INFINITE; -    systemticks_t current_time = gfxSystemTicks(); -    bool          force_update = true; - -    while (true) { -        systemticks_t new_time = gfxSystemTicks(); -        systemticks_t delta    = new_time - current_time; -        current_time           = new_time; -        bool enabled           = visualizer_enabled; -        if (force_update || !same_status(&state.status, ¤t_status)) { -            force_update = false; -#if BACKLIGHT_ENABLE -            if (current_status.backlight_level != state.status.backlight_level) { -                if (current_status.backlight_level != 0) { -                    gdispGSetPowerMode(LED_DISPLAY, powerOn); -                    uint16_t percent = (uint16_t)current_status.backlight_level * 100 / BACKLIGHT_LEVELS; -                    gdispGSetBacklight(LED_DISPLAY, percent); -                } else { -                    gdispGSetPowerMode(LED_DISPLAY, powerOff); -                } -                state.status.backlight_level = current_status.backlight_level; -            } -#endif -            if (visualizer_enabled) { -                if (current_status.suspended) { -                    stop_all_keyframe_animations(); -                    visualizer_enabled = false; -                    state.status       = current_status; -                    user_visualizer_suspend(&state); -                } else { -                    visualizer_keyboard_status_t prev_status = state.status; -                    state.status                             = current_status; -                    update_user_visualizer_state(&state, &prev_status); -                } -                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); -            state.prev_lcd_color = state.current_lcd_color; -        } -        sleep_time = TIME_INFINITE; -        for (int i = 0; i < MAX_SIMULTANEOUS_ANIMATIONS; i++) { -            if (animations[i]) { -                update_keyframe_animation(animations[i], &state, delta, &sleep_time); -            } -        } -#ifdef BACKLIGHT_ENABLE -        gdispGFlush(LED_DISPLAY); -#endif - -#ifdef LCD_ENABLE -        gdispGFlush(LCD_DISPLAY); -#endif - -#ifdef EMULATOR -        draw_emulator(); -#endif -        // Enable the visualizer when the startup or the suspend animation has finished -        if (!visualizer_enabled && state.status.suspended == false && get_num_running_animations() == 0) { -            visualizer_enabled = true; -            force_update       = true; -            sleep_time         = 0; -        } - -        systemticks_t after_update = gfxSystemTicks(); -        unsigned      update_delta = after_update - current_time; -        if (sleep_time != TIME_INFINITE) { -            if (sleep_time > update_delta) { -                sleep_time -= update_delta; -            } else { -                sleep_time = 0; -            } -        } -        dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time); -#ifdef PROTOCOL_CHIBIOS -        // The gEventWait function really takes milliseconds, even if the documentation says ticks. -        // Unfortunately there's no generic ugfx conversion from system time to milliseconds, -        // so let's do it in a platform dependent way. - -        // On windows the system ticks is the same as milliseconds anyway -        if (sleep_time != TIME_INFINITE) { -            sleep_time = TIME_I2MS(sleep_time); -        } -#endif -        geventEventWait(&event_listener, sleep_time); -    } -#ifdef LCD_ENABLE -    gdispCloseFont(state.font_fixed5x8); -    gdispCloseFont(state.font_dejavusansbold12); -#endif - -    return 0; -} - -void visualizer_init(void) { -    gfxInit(); - -#ifdef LCD_BACKLIGHT_ENABLE -    lcd_backlight_init(); -#endif - -#ifdef SERIAL_LINK_ENABLE -    add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*)); -#endif - -#ifdef LCD_ENABLE -    LCD_DISPLAY = get_lcd_display(); -#endif - -#ifdef BACKLIGHT_ENABLE -    LED_DISPLAY = get_led_display(); -#endif - -    // We are using a low priority thread, the idea is to have it run only -    // when the main thread is sleeping during the matrix scanning -    gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack), VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL); -} - -void update_status(bool changed) { -    if (changed) { -        GSourceListener* listener = geventGetSourceListener((GSourceHandle)¤t_status, NULL); -        if (listener) { -            geventSendEvent(listener); -        } -    } -#ifdef SERIAL_LINK_ENABLE -    static systime_t last_update    = 0; -    systime_t        current_update = chVTGetSystemTimeX(); -    systime_t        delta          = current_update - last_update; -    if (changed || delta > TIME_MS2I(10)) { -        last_update                     = current_update; -        visualizer_keyboard_status_t* r = begin_write_current_status(); -        *r                              = current_status; -        end_write_current_status(); -    } -#endif -} - -uint8_t visualizer_get_mods() { -    uint8_t mods = get_mods(); - -#ifndef NO_ACTION_ONESHOT -    if (!has_oneshot_mods_timed_out()) { -        mods |= get_oneshot_mods(); -    } -#endif -    return mods; -} - -#ifdef VISUALIZER_USER_DATA_SIZE -void visualizer_set_user_data(void* u) { memcpy(user_data, u, VISUALIZER_USER_DATA_SIZE); } -#endif - -void visualizer_update(layer_state_t default_state, layer_state_t state, uint8_t mods, uint32_t leds) { -    // 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 -    // not really matter as it will be fixed during the next loop step. -    // Alternatively a mutex could be used instead of the volatile variables - -    bool changed = false; -#ifdef SERIAL_LINK_ENABLE -    if (is_serial_link_connected()) { -        visualizer_keyboard_status_t* new_status = read_current_status(); -        if (new_status) { -            if (!same_status(¤t_status, new_status)) { -                changed        = true; -                current_status = *new_status; -            } -        } -    } else { -#else -    { -#endif -        visualizer_keyboard_status_t new_status = { -            .layer         = state, -            .default_layer = default_state, -            .mods          = mods, -            .leds          = leds, -#ifdef BACKLIGHT_ENABLE -            .backlight_level = current_status.backlight_level, -#endif -            .suspended = current_status.suspended, -        }; -#ifdef VISUALIZER_USER_DATA_SIZE -        memcpy(new_status.user_data, user_data, VISUALIZER_USER_DATA_SIZE); -#endif -        if (!same_status(¤t_status, &new_status)) { -            changed        = true; -            current_status = new_status; -        } -    } -    update_status(changed); -} - -void visualizer_suspend(void) { -    current_status.suspended = true; -    update_status(true); -} - -void visualizer_resume(void) { -    current_status.suspended = false; -    update_status(true); -} - -#ifdef BACKLIGHT_ENABLE -void backlight_set(uint8_t level) { -    current_status.backlight_level = level; -    update_status(true); -} -#endif | 
