~ruther/qmk_firmware

b93d07198a18063594a59dd193d0961622087868 — Fred Sundvik 9 years ago 315edb4
Suspend support for the visualizer
3 files changed, 103 insertions(+), 30 deletions(-)

M example_integration/visualizer_user.c
M visualizer.c
M visualizer.h
M example_integration/visualizer_user.c => example_integration/visualizer_user.c +1 -1
@@ 65,7 65,7 @@ static keyframe_animation_t startup_animation = {
    .num_frames = 4,
    .loop = false,
    .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

M visualizer.c => visualizer.c +88 -26
@@ 52,10 52,14 @@ static visualizer_keyboard_status_t current_status = {
    .layer = 0xFFFFFFFF,
    .default_layer = 0xFFFFFFFF,
    .leds = 0xFFFFFFFF,
    .suspended = false,
};

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;


@@ 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) {
    dprintf("Animation frame%d, left %d, delta %d\n", animation->current_frame,
            animation->time_left_in_frame, delta);


@@ 252,7 267,19 @@ bool keyframe_display_layer_bitmap(keyframe_animation_t* animation, visualizer_s
}
#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)state;
    dprint("User visualizer inited\n");


@@ 268,13 295,15 @@ static THD_FUNCTION(visualizerThread, arg) {
    event_listener_t event_listener;
    chEvtRegister(&layer_changed_event, &event_listener, 0);

    visualizer_state_t state = {
        .status = {
            .default_layer = 0xFFFFFFFF,
            .layer = 0xFFFFFFFF,
            .leds = 0xFFFFFFFF,
        },
    visualizer_keyboard_status_t initial_status = {
        .default_layer = 0xFFFFFFFF,
        .layer = 0xFFFFFFFF,
        .leds = 0xFFFFFFFF,
        .suspended = false,
    };

    visualizer_state_t state = {
        .status = initial_status,
        .current_lcd_color = 0,
#ifdef LCD_ENABLE
        .font_fixed5x8 = gdispOpenFont("fixed_5x8"),


@@ 301,17 330,36 @@ static THD_FUNCTION(visualizerThread, arg) {
        bool enabled = visualizer_enabled;
        if (!same_status(&state.status, &current_status)) {
            if (visualizer_enabled) {
                state.status = current_status;
                update_user_visualizer_state(&state);
                state.prev_lcd_color = state.current_lcd_color;
                if (current_status.suspended) {
                    stop_all_keyframe_animations();
                    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;
        for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) {
            if (animations[i]) {
                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) {
            sleep_time = 0;
        }


@@ 354,7 402,24 @@ void visualizer_init(void) {
                              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
    // 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.


@@ 379,25 444,22 @@ void visualizer_set_state(uint32_t default_state, uint32_t state, uint32_t leds)
            .layer = state,
            .default_layer = default_state,
            .leds = leds,
            .suspended = current_status.suspended,
        };
        if (!same_status(&current_status, &new_status)) {
            changed = true;
            current_status = new_status;
        }
    }
    if (changed) {
        chEvtBroadcast(&layer_changed_event);
    update_status(changed);
}

    }
#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_suspend(void) {
    current_status.suspended = true;
    update_status(true);
}

void visualizer_resume(void) {
    current_status.suspended = false;
    update_status(true);
}

M visualizer.h => visualizer.h +14 -3
@@ 38,8 38,12 @@ SOFTWARE.

// This need to be called once at the start
void visualizer_init(void);
// This should be called before every matrix scan
void visualizer_set_state(uint32_t default_state, uint32_t state, uint32_t leds);
// This should be called at every matrix scan
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
#define MAX_VISUALIZER_KEY_FRAMES 8


@@ 50,6 54,7 @@ typedef struct {
    uint32_t layer;
    uint32_t default_layer;
    uint32_t leds; // See led.h for available statuses
    bool suspended;
} visualizer_keyboard_status_t;

// 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);
// 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_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
// 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
void initialize_user_visualizer(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 */