qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

ap2_led.c (6564B)


      1 /* Copyright 2021 OpenAnnePro community
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 2 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15  */
     16 
     17 #include <string.h>
     18 #include <stdio.h>
     19 #include "hal.h"
     20 #include "annepro2.h"
     21 #include "ap2_led.h"
     22 #include "protocol.h"
     23 
     24 ap2_led_t       led_mask[KEY_COUNT];
     25 ap2_led_t       led_colors[KEY_COUNT];
     26 ap2_led_status_t ap2_led_status;
     27 
     28 void led_command_callback(const message_t *msg) {
     29     switch (msg->command) {
     30         case CMD_LED_STATUS:
     31             ap2_led_status.amount_of_profiles = msg->payload[0];
     32             ap2_led_status.current_profile    = msg->payload[1];
     33             ap2_led_status.matrix_enabled     = msg->payload[2];
     34             ap2_led_status.is_reactive        = msg->payload[3];
     35             ap2_led_status.led_intensity      = msg->payload[4];
     36             ap2_led_status.errors             = msg->payload[5];
     37             break;
     38 
     39 #ifdef CONSOLE_ENABLE
     40         case CMD_LED_DEBUG:
     41             /* TODO: Don't use printf. */
     42             printf("LED:");
     43             for (int i = 0; i < msg->payload_size; i++) {
     44                 printf("%02x ", msg->payload[i]);
     45             }
     46             for (int i = 0; i < msg->payload_size; i++) {
     47                 printf("%c", msg->payload[i]);
     48             }
     49             printf("\n");
     50             break;
     51 #endif
     52     }
     53 }
     54 
     55 void ap2_set_IAP(void) { proto_tx(CMD_LED_IAP, NULL, 0, 3); }
     56 
     57 void ap2_led_disable(void) { proto_tx(CMD_LED_OFF, NULL, 0, 3); }
     58 
     59 void ap2_led_enable(void) { proto_tx(CMD_LED_ON, NULL, 0, 3); }
     60 
     61 void ap2_led_set_profile(uint8_t prof) { proto_tx(CMD_LED_SET_PROFILE, &prof, sizeof(prof), 3); }
     62 
     63 void ap2_led_next_profile(void) { proto_tx(CMD_LED_NEXT_PROFILE, NULL, 0, 3); }
     64 
     65 void ap2_led_next_intensity(void) { proto_tx(CMD_LED_NEXT_INTENSITY, NULL, 0, 3); }
     66 
     67 void ap2_led_next_animation_speed(void) { proto_tx(CMD_LED_NEXT_ANIMATION_SPEED, NULL, 0, 3); }
     68 
     69 void ap2_led_prev_profile(void) { proto_tx(CMD_LED_PREV_PROFILE, NULL, 0, 3); }
     70 
     71 void ap2_led_mask_set_key(uint8_t row, uint8_t col, ap2_led_t color) {
     72     uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
     73     proto_tx(CMD_LED_MASK_SET_KEY, payload, sizeof(payload), 1);
     74 }
     75 
     76 /* Push a whole local row to the shine */
     77 void ap2_led_mask_set_row(uint8_t row) {
     78     uint8_t payload[NUM_COLUMN * sizeof(ap2_led_t) + 1];
     79     payload[0] = row;
     80     memcpy(payload + 1, &led_mask[ROWCOL2IDX(row, 0)], sizeof(*led_mask) * NUM_COLUMN);
     81     proto_tx(CMD_LED_MASK_SET_ROW, payload, sizeof(payload), 1);
     82 }
     83 
     84 /* Synchronize all rows */
     85 void ap2_led_mask_set_all(void) {
     86     for (int row = 0; row < 5; row++) ap2_led_mask_set_row(row);
     87 }
     88 
     89 /* Set all keys to a given color */
     90 void ap2_led_mask_set_mono(const ap2_led_t color) { proto_tx(CMD_LED_MASK_SET_MONO, (uint8_t *)&color, sizeof(color), 1); }
     91 
     92 void ap2_led_colors_set_key(uint8_t row, uint8_t col, ap2_led_t color) {
     93     uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
     94     proto_tx(CMD_LED_COLOR_SET_KEY, payload, sizeof(payload), 1);
     95 }
     96 
     97 /* Push a whole local row to the shine */
     98 void ap2_led_colors_set_row(uint8_t row) {
     99     uint8_t payload[NUM_COLUMN * sizeof(ap2_led_t) + 1];
    100     payload[0] = row;
    101     memcpy(payload + 1, &led_colors[ROWCOL2IDX(row, 0)], sizeof(*led_colors) * NUM_COLUMN);
    102     proto_tx(CMD_LED_COLOR_SET_ROW, payload, sizeof(payload), 1);
    103 }
    104 
    105 /* Synchronize all rows */
    106 void ap2_led_colors_set_all(void) {
    107     for (int row = 0; row < 5; row++) ap2_led_colors_set_row(row);
    108 }
    109 
    110 /* Set all keys to a given color */
    111 void ap2_led_colors_set_mono(const ap2_led_t color) { proto_tx(CMD_LED_COLOR_SET_MONO, (uint8_t *)&color, sizeof(color), 1); }
    112 
    113 void ap2_led_set_manual_control(uint8_t manual) {
    114     uint8_t payload[] = {manual};
    115     proto_tx(CMD_LED_SET_MANUAL, payload, sizeof(payload), 1);
    116 }
    117 
    118 void ap2_led_blink(uint8_t row, uint8_t col, ap2_led_t color, uint8_t count, uint8_t hundredths) {
    119     uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha, count, hundredths};
    120     proto_tx(CMD_LED_KEY_BLINK, payload, sizeof(payload), 1);
    121 }
    122 
    123 void ap2_led_set_foreground_color(uint8_t red, uint8_t green, uint8_t blue) {
    124     ap2_led_t color = {.p.red = red, .p.green = green, .p.blue = blue, .p.alpha = 0xff};
    125     ap2_led_mask_set_mono(color);
    126 }
    127 
    128 void ap2_led_reset_foreground_color(void) {
    129     ap2_led_t color = {
    130         .p.red   = 0,
    131         .p.green = 0,
    132         .p.blue  = 0,
    133         .p.alpha = 0,
    134     };
    135     ap2_led_mask_set_mono(color);
    136 }
    137 
    138 void ap2_led_sticky_set_key(uint8_t row, uint8_t col, ap2_led_t color) {
    139     uint8_t payload[] = {row, col, color.p.blue, color.p.green, color.p.red, color.p.alpha};
    140     proto_tx(CMD_LED_STICKY_SET_KEY, payload, sizeof(payload), 1);
    141 }
    142 
    143 void ap2_led_unset_sticky_key(uint8_t row, uint8_t col) {
    144     uint8_t payload[] = {row, col};
    145     proto_tx(CMD_LED_STICKY_UNSET_KEY, payload, sizeof(payload), 1);
    146 }
    147 
    148 void ap2_led_unset_sticky_row(uint8_t row) {
    149     uint8_t payload[] = {row};
    150     proto_tx(CMD_LED_STICKY_UNSET_ROW, payload, sizeof(payload), 1);
    151 }
    152 void ap2_led_unset_sticky_all(void) {
    153     proto_tx(CMD_LED_STICKY_UNSET_ALL, NULL, 0, 1);
    154 }
    155 
    156 /*
    157  * Currently keypresses are unified with other messages, still with single 1
    158  * byte payload. Transfer is normally fast enough for that to not be a problem -
    159  * especially with asynchronous message reading.
    160  *
    161  *
    162  * Previous description:
    163  * If enabled, this data is sent to LED MCU on every keypress.
    164  * In order to improve performance, both row and column values
    165  * are packed into a single byte.
    166  * Row range is [0, 4] and requires only 3 bits.
    167  * Column range is [0, 13] and requires 4 bits.
    168  *
    169  * In order to differentiate this command from regular commands,
    170  * the leftmost bit is set to 1 (0b10000000).
    171  * Following it are 3 bits of row and 4 bits of col.
    172  * 1 + 3 + 4 = 8 bits - only a single byte is sent for every keypress.
    173  */
    174 void ap2_led_forward_keypress(uint8_t row, uint8_t col) {
    175     const uint8_t payload = row << 4 | col;
    176     proto_tx(CMD_LED_KEY_DOWN, &payload, 1, 1);
    177 }