summaryrefslogtreecommitdiff
path: root/quantum/vialrgb.c
blob: 7986cc81d07489dea61e3c1f2750ba6e527e3b20 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Based on https://github.com/qmk/qmk_firmware/pull/13036 */

#include "vialrgb.h"

#include <inttypes.h>
#include <string.h>
#include "rgb_matrix.h"
#include "vial.h"

typedef struct {
    uint16_t vialrgb_id;
    uint16_t qmk_id;
} vialrgb_supported_mode_t;

#include "vialrgb_effects.inc"

#define SUPPORTED_MODES_LENGTH (sizeof(supported_modes)/sizeof(*supported_modes))

#ifdef RGB_MATRIX_EFFECT_VIALRGB_DIRECT
HSV g_direct_mode_colors[RGB_MATRIX_LED_COUNT];
#endif

static void get_supported(uint8_t *args, uint8_t length) {
    /* retrieve supported effects (VialRGB IDs) with ID > gt */
    uint16_t gt;
    memcpy(&gt, args, sizeof(gt));
    memset(args, 0xFF, length);
    for (size_t i = 0; i < SUPPORTED_MODES_LENGTH; ++i) {
        uint16_t id = pgm_read_word(&supported_modes[i].vialrgb_id);
        if (id > gt && length >= sizeof(id)) {
            memcpy(args, &id, sizeof(id));
            length -= sizeof(id);
            args += sizeof(id);
        }
    }
}

static uint16_t qmk_id_to_vialrgb_id(uint16_t id) {
    for (size_t i = 0; i < SUPPORTED_MODES_LENGTH; ++i) {
        uint16_t qmk_id = pgm_read_word(&supported_modes[i].qmk_id);
        uint16_t vialrgb_id = pgm_read_word(&supported_modes[i].vialrgb_id);
        if (qmk_id == id)
            return vialrgb_id;
    }
    return 0;
}

static uint16_t vialrgb_id_to_qmk_id(uint16_t id) {
    for (size_t i = 0; i < SUPPORTED_MODES_LENGTH; ++i) {
        uint16_t qmk_id = pgm_read_word(&supported_modes[i].qmk_id);
        uint16_t vialrgb_id = pgm_read_word(&supported_modes[i].vialrgb_id);
        if (vialrgb_id == id)
            return qmk_id;
    }
    return 0;
}

static uint16_t get_mode(void) {
    /* Get current mode as vialrgb ID */
    if (!rgb_matrix_is_enabled())
        return VIALRGB_EFFECT_OFF;
    return qmk_id_to_vialrgb_id(rgb_matrix_get_mode());
}

static void set_mode(uint16_t mode) {
    /* Set a mode as vialrgb ID */
    if (mode == VIALRGB_EFFECT_OFF) {
        rgb_matrix_disable_noeeprom();
    } else {
        rgb_matrix_enable_noeeprom();
        rgb_matrix_mode_noeeprom(vialrgb_id_to_qmk_id(mode));
    }
}

#ifdef RGB_MATRIX_EFFECT_VIALRGB_DIRECT
static void get_matrix_pos_for_led(uint16_t led, uint8_t *output) {
    /* reset initially so if we cannot locate the led, it's considered not part of kb matrix */
    output[0] = output[1] = 0xFF;
    /* this is kinda O(n^2) but what can you do */
    for (size_t row = 0; row < MATRIX_ROWS; ++row)
        for (size_t col = 0; col < MATRIX_COLS; ++col)
            if (g_led_config.matrix_co[row][col] == led) {
                output[0] = row;
                output[1] = col;
                return;
            }
}

static void fast_set_leds(uint8_t *args, size_t length) {
    /* Set multiple leds HSV, first 2 bytes are index of the first led, then number of leds, followed by HSV for the leds */
    /* we have 32-2-2-1=27 total bytes available, so can set up to 9 leds per packet */
    if (length < 3) return;

    uint16_t first_index = args[0] | (args[1] << 8);
    uint8_t num_leds = args[2];
    length -= 3;
    args += 3;

    if (num_leds * 3 > length) return;

    for (size_t i = 0; i < num_leds; ++i) {
        if (i + first_index >= RGB_MATRIX_LED_COUNT)
            break;
        g_direct_mode_colors[i + first_index].h = args[i * 3 + 0];
        g_direct_mode_colors[i + first_index].s = args[i * 3 + 1];
        uint8_t val = args[i * 3 + 2];
        g_direct_mode_colors[i + first_index].v = (val > RGB_MATRIX_MAXIMUM_BRIGHTNESS) ? RGB_MATRIX_MAXIMUM_BRIGHTNESS : val;
    }
}
#endif

void vialrgb_get_value(uint8_t *data, uint8_t length) {
    if (length != VIAL_RAW_EPSIZE) return;

    /* data[0] is used by VIA command id */
    uint8_t cmd = data[1];
    uint8_t *args = &data[2];
    switch (cmd) {
    case vialrgb_get_info:
        args[0] = VIALRGB_PROTOCOL_VERSION & 0xFF;
        args[1] = VIALRGB_PROTOCOL_VERSION >> 8;
        args[2] = RGB_MATRIX_MAXIMUM_BRIGHTNESS;
        break;
    case vialrgb_get_mode: {
        uint16_t vialrgb_id = get_mode();
        args[0] = vialrgb_id & 0xFF;
        args[1] = vialrgb_id >> 8;
        args[2] = rgb_matrix_get_speed();
        args[3] = rgb_matrix_get_hue();
        args[4] = rgb_matrix_get_sat();
        args[5] = rgb_matrix_get_val();
        break;
    }
    case vialrgb_get_supported: {
        get_supported(args, length - 2);
        break;
    }
#ifdef RGB_MATRIX_EFFECT_VIALRGB_DIRECT
    case vialrgb_get_number_leds: {
        args[0] = RGB_MATRIX_LED_COUNT & 0xFF;
        args[1] = RGB_MATRIX_LED_COUNT >> 8;
        break;
    }
    case vialrgb_get_led_info: {
        uint16_t led = (args[0] & 0xFF) | (args[1] >> 8);
        if (led >= RGB_MATRIX_LED_COUNT) return;
        // x, y
        args[0] = g_led_config.point[led].x;
        args[1] = g_led_config.point[led].y;
        // flags
        args[2] = g_led_config.flags[led];
        // position in keyboard matrix (if it's keyboard LED, otherwise 0xFF)
        get_matrix_pos_for_led(led, &args[3]);
        break;
    }
#endif
    }
}

void vialrgb_set_value(uint8_t *data, uint8_t length) {
    if (length != VIAL_RAW_EPSIZE) return;

    /* data[0] is used by VIA command id */
    uint8_t cmd = data[1];
    uint8_t *args = &data[2];
    switch (cmd) {
    case vialrgb_set_mode: {
        uint16_t vialrgb_id = args[0] | (args[1] << 8);
        set_mode(vialrgb_id);
        rgb_matrix_set_speed_noeeprom(args[2]);
        rgb_matrix_sethsv_noeeprom(args[3], args[4], args[5]);
        break;
    }
#ifdef RGB_MATRIX_EFFECT_VIALRGB_DIRECT
    case vialrgb_direct_fastset: {
        fast_set_leds(args, length);
        break;
    }
#endif
    }
}

void vialrgb_save(uint8_t *data, uint8_t length) {
    (void)data;
    (void)length;

    eeconfig_update_rgb_matrix();
}