summaryrefslogtreecommitdiffstats
path: root/quantum/painter/qp_internal.c
blob: ea23aef7c34ff0a039050a5ee63e776aaa40229a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright 2023 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later

#include "qp_internal.h"

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quantum Painter Core API: device registration

enum {
    // Work out how many devices we're actually going to be instantiating
    // NOTE: We intentionally do not include surfaces here, despite them conforming to the same API.
    QP_NUM_DEVICES = (ILI9163_NUM_DEVICES)   // ILI9163
                     + (ILI9341_NUM_DEVICES) // ILI9341
                     + (ILI9488_NUM_DEVICES) // ILI9488
                     + (ST7789_NUM_DEVICES)  // ST7789
                     + (ST7735_NUM_DEVICES)  // ST7735
                     + (GC9A01_NUM_DEVICES)  // GC9A01
                     + (SSD1351_NUM_DEVICES) // SSD1351
};

static painter_device_t qp_devices[QP_NUM_DEVICES] = {NULL};

bool qp_internal_register_device(painter_device_t driver) {
    for (uint8_t i = 0; i < QP_NUM_DEVICES; i++) {
        if (qp_devices[i] == NULL) {
            qp_devices[i] = driver;
            return true;
        }
    }

    // We should never get here -- someone has screwed up their device counts during config
    qp_dprintf("qp_internal_register_device: no more space for devices!\n");
    return false;
}

#if (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0
static void qp_internal_display_timeout_task(void) {
    // Handle power on/off state
    static bool display_on                  = true;
    bool        should_change_display_state = false;
    bool        target_display_state        = false;
    if (last_input_activity_elapsed() < (QUANTUM_PAINTER_DISPLAY_TIMEOUT)) {
        should_change_display_state = display_on == false;
        target_display_state        = true;
    } else {
        should_change_display_state = display_on == true;
        target_display_state        = false;
    }

    if (should_change_display_state) {
        for (uint8_t i = 0; i < QP_NUM_DEVICES; i++) {
            if (qp_devices[i] != NULL) {
                qp_power(qp_devices[i], target_display_state);
            }
        }

        display_on = target_display_state;
    }
}
#endif // (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Quantum Painter Core API: qp_internal_task

_Static_assert((QUANTUM_PAINTER_TASK_THROTTLE) > 0 && (QUANTUM_PAINTER_TASK_THROTTLE) < 1000, "QUANTUM_PAINTER_TASK_THROTTLE must be between 1 and 999");

void qp_internal_task(void) {
    // Perform throttling of the internal processing of Quantum Painter
    static uint32_t last_tick = 0;
    uint32_t        now       = timer_read32();
    if (TIMER_DIFF_32(now, last_tick) < (QUANTUM_PAINTER_TASK_THROTTLE)) {
        return;
    }
    last_tick = now;

#if (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0
    qp_internal_display_timeout_task();
#endif // (QUANTUM_PAINTER_DISPLAY_TIMEOUT) > 0

    // Handle animations
    void qp_internal_animation_tick(void);
    qp_internal_animation_tick();

#ifdef QUANTUM_PAINTER_LVGL_INTEGRATION_ENABLE
    // Run LVGL ticks
    void qp_lvgl_internal_tick(void);
    qp_lvgl_internal_tick();
#endif

    // Flush (render) dirty regions to corresponding displays
    for (uint8_t i = 0; i < QP_NUM_DEVICES; i++) {
        if (qp_devices[i] != NULL) {
            qp_flush(qp_devices[i]);
        }
    }
}