summaryrefslogtreecommitdiffstats
path: root/keyboards/annepro2/ap2_led.c
blob: c1d7c8166e88d0261c1393314d2a03e3ffd8bc31 (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
/* Copyright 2021 OpenAnnePro community
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <string.h>
#include <stdio.h>
#include "hal.h"
#include "annepro2.h"
#include "ap2_led.h"
#include "protocol.h"

ap2_led_t       led_mask[KEY_COUNT];
ap2_led_t       led_colors[KEY_COUNT];
ap2_led_status_t ap2_led_status;

void led_command_callback(const message_t *msg) {
    switch (msg->command) {
        case CMD_LED_STATUS:
            ap2_led_status.amount_of_profiles = msg->payload[0];
            ap2_led_status.current_profile    = msg->payload[1];
            ap2_led_status.matrix_enabled     = msg->payload[2];
            ap2_led_status.is_reactive        = msg->payload[3];
            ap2_led_status.led_intensity      = msg->payload[4];
            ap2_led_status.errors             = msg->payload[5];
            break;

#ifdef CONSOLE_ENABLE
        case CMD_LED_DEBUG:
            /* TODO: Don't use printf. */
            printf("LED:");
            for (int i = 0; i < msg->payload_size; i++) {
                printf("%02x ", msg->payload[i]);
            }
            for (int i = 0; i < msg->payload_size; i++) {
                printf("%c", msg->payload[i]);
            }
            printf("\n");
            break;
#endif
    }
}

void ap2_set_IAP(void) { proto_tx(CMD_LED_IAP, NULL, 0, 3); }

void ap2_led_disable(void) { proto_tx(CMD_LED_OFF, NULL, 0, 3); }

void ap2_led_enable(void) { proto_tx(CMD_LED_ON, NULL, 0, 3); }

void ap2_led_set_profile(uint8_t prof) { proto_tx(CMD_LED_SET_PROFILE, &prof, sizeof(prof), 3); }

void ap2_led_get_status(void) { proto_tx(CMD_LED_GET_STATUS, NULL, 0, 3); }

void ap2_led_next_profile(void) { proto_tx(CMD_LED_NEXT_PROFILE, NULL, 0, 3); }

void ap2_led_next_intensity(void) { proto_tx(CMD_LED_NEXT_INTENSITY, NULL, 0, 3); }

void ap2_led_next_animation_speed(void) { proto_tx(CMD_LED_NEXT_ANIMATION_SPEED, NULL, 0, 3); }

void ap2_led_prev_profile(void) { proto_tx(CMD_LED_PREV_PROFILE, NULL, 0, 3); }

void ap2_led_mask_set_key(uint8_t row, uint8_t col, ap2_led_t color) {
    uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
    proto_tx(CMD_LED_MASK_SET_KEY, payload, sizeof(payload), 1);
}

/* Push a whole local row to the shine */
void ap2_led_mask_set_row(uint8_t row) {
    uint8_t payload[NUM_COLUMN * sizeof(ap2_led_t) + 1];
    payload[0] = row;
    memcpy(payload + 1, &led_mask[ROWCOL2IDX(row, 0)], sizeof(*led_mask) * NUM_COLUMN);
    proto_tx(CMD_LED_MASK_SET_ROW, payload, sizeof(payload), 1);
}

/* Synchronize all rows */
void ap2_led_mask_set_all(void) {
    for (int row = 0; row < 5; row++) ap2_led_mask_set_row(row);
}

/* Set all keys to a given color */
void ap2_led_mask_set_mono(const ap2_led_t color) { proto_tx(CMD_LED_MASK_SET_MONO, (uint8_t *)&color, sizeof(color), 1); }

void ap2_led_colors_set_key(uint8_t row, uint8_t col, ap2_led_t color) {
    uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
    proto_tx(CMD_LED_COLOR_SET_KEY, payload, sizeof(payload), 1);
}

/* Push a whole local row to the shine */
void ap2_led_colors_set_row(uint8_t row) {
    uint8_t payload[NUM_COLUMN * sizeof(ap2_led_t) + 1];
    payload[0] = row;
    memcpy(payload + 1, &led_colors[ROWCOL2IDX(row, 0)], sizeof(*led_colors) * NUM_COLUMN);
    proto_tx(CMD_LED_COLOR_SET_ROW, payload, sizeof(payload), 1);
}

/* Synchronize all rows */
void ap2_led_colors_set_all(void) {
    for (int row = 0; row < 5; row++) ap2_led_colors_set_row(row);
}

/* Set all keys to a given color */
void ap2_led_colors_set_mono(const ap2_led_t color) { proto_tx(CMD_LED_COLOR_SET_MONO, (uint8_t *)&color, sizeof(color), 1); }

void ap2_led_set_manual_control(uint8_t manual) {
    uint8_t payload[] = {manual};
    proto_tx(CMD_LED_SET_MANUAL, payload, sizeof(payload), 1);
}

void ap2_led_blink(uint8_t row, uint8_t col, ap2_led_t color, uint8_t count, uint8_t hundredths) {
    uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha, count, hundredths};
    proto_tx(CMD_LED_KEY_BLINK, payload, sizeof(payload), 1);
}

void ap2_led_set_foreground_color(uint8_t red, uint8_t green, uint8_t blue) {
    ap2_led_t color = {.p.red = red, .p.green = green, .p.blue = blue, .p.alpha = 0xff};
    ap2_led_mask_set_mono(color);
}

void ap2_led_reset_foreground_color(void) {
    ap2_led_t color = {
        .p.red   = 0,
        .p.green = 0,
        .p.blue  = 0,
        .p.alpha = 0,
    };
    ap2_led_mask_set_mono(color);
}

void ap2_led_sticky_set_key(uint8_t row, uint8_t col, ap2_led_t color) {
    uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
    proto_tx(CMD_LED_STICKY_SET_KEY, payload, sizeof(payload), 1);
}

void ap2_led_unset_sticky_key(uint8_t row, uint8_t col) {
    uint8_t payload[] = {row, col};
    proto_tx(CMD_LED_STICKY_UNSET_KEY, payload, sizeof(payload), 1);
}

void ap2_led_unset_sticky_row(uint8_t row) {
    uint8_t payload[] = {row};
    proto_tx(CMD_LED_STICKY_UNSET_ROW, payload, sizeof(payload), 1);
}
void ap2_led_unset_sticky_all(void) {
    proto_tx(CMD_LED_STICKY_UNSET_ALL, NULL, 0, 1);
}

/*
 * Currently keypresses are unified with other messages, still with single 1
 * byte payload. Transfer is normally fast enough for that to not be a problem -
 * especially with asynchronous message reading.
 *
 *
 * Previous description:
 * If enabled, this data is sent to LED MCU on every keypress.
 * In order to improve performance, both row and column values
 * are packed into a single byte.
 * Row range is [0, 4] and requires only 3 bits.
 * Column range is [0, 13] and requires 4 bits.
 *
 * In order to differentiate this command from regular commands,
 * the leftmost bit is set to 1 (0b10000000).
 * Following it are 3 bits of row and 4 bits of col.
 * 1 + 3 + 4 = 8 bits - only a single byte is sent for every keypress.
 */
void ap2_led_forward_keypress(uint8_t row, uint8_t col) {
    const uint8_t payload = row << 4 | col;
    proto_tx(CMD_LED_KEY_DOWN, &payload, 1, 1);
}