leds.c (3423B)
1 /* Copyright 2018-2021 James Laird-Wah, Islam Sharabash 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 "leds.h" 18 #include <string.h> 19 #include "i2c_master.h" 20 #include "led_tables.h" 21 #include "rgb_matrix.h" 22 #include "wait.h" 23 #include "raise.h" 24 #include "wire-protocol-constants.h" 25 #include "print.h" 26 27 // Color order of LEDs is Green, Red, Blue. 28 typedef struct PACKED { 29 uint8_t r; 30 uint8_t g; 31 uint8_t b; 32 } raiseRGB; 33 34 #define LEDS_PER_HAND 72 35 #define LED_BANKS 9 36 #define LEDS_PER_BANK 8 37 #define LED_BYTES_PER_BANK (sizeof(raiseRGB) * LEDS_PER_BANK) 38 39 // shifting << 1 is because drivers/chibios/i2c_master.h expects the address 40 // shifted. 41 // 0x58 and 0x59 are the addresses defined in dygma/raise/Hand.h 42 #define I2C_ADDR_LEFT (0x58 << 1) 43 #define I2C_ADDR_RIGHT (0x59 << 1) 44 #define I2C_ADDR(hand) ((hand) ? I2C_ADDR_RIGHT : I2C_ADDR_LEFT) 45 #define LEFT 0 46 #define RIGHT 1 47 48 static raiseRGB led_pending[2 * LEDS_PER_HAND]; 49 static raiseRGB led_state[2 * LEDS_PER_HAND]; 50 51 static void set_color(int index, uint8_t r, uint8_t g, uint8_t b) { 52 int sled = led_map[index]; 53 // The red component of the LED is apparently stronger than the others. 54 // From: https://github.com/keyboardio/Kaleidoscope/blob/aba8c9ee66bbb5ded15135618d2b2964ee82b2cc/plugins/Kaleidoscope-Hardware-Dygma-Raise/src/kaleidoscope/device/dygma/raise/RaiseSide.cpp#L235-L242 55 if (r >= 26) { 56 r -= 26; 57 } 58 led_pending[sled].r = r; 59 led_pending[sled].g = g; 60 led_pending[sled].b = b; 61 } 62 63 static void set_color_all(uint8_t r, uint8_t g, uint8_t b) { 64 for (int i = 0; i < RGB_MATRIX_LED_COUNT; i++) set_color(i, r, g, b); 65 } 66 67 static void init(void) { 68 set_color_all(0,0,0); 69 } 70 71 static void flush(void) { 72 uint8_t command[1 + LED_BYTES_PER_BANK]; 73 74 // SUBTLE(ibash) alternate hands when transmitting led data, otherwise the 75 // mcu in the hand seems to have trouble keeping up with the i2c 76 // transmission 77 for (int bank = 0; bank < LED_BANKS; bank++) { 78 for (int hand = 0; hand < 2; hand++) { 79 int addr = I2C_ADDR(hand); 80 int i = (hand * LEDS_PER_HAND) + (bank * LEDS_PER_BANK); 81 82 if (memcmp(&led_state[i], &led_pending[i], LED_BYTES_PER_BANK) == 0) { 83 // No change. 84 continue; 85 } 86 87 // Update LED state 88 memcpy(&led_state[i], &led_pending[i], LED_BYTES_PER_BANK); 89 90 command[0] = TWI_CMD_LED_BASE + bank; 91 memcpy(&command[1], &led_pending[i], LED_BYTES_PER_BANK); 92 i2c_transmit(addr, command, sizeof(command), I2C_TIMEOUT); 93 94 // delay to prevent issues with the i2c bus 95 wait_us(10); 96 } 97 } 98 } 99 100 const rgb_matrix_driver_t rgb_matrix_driver = {.init = init, .flush = flush, .set_color = set_color, .set_color_all = set_color_all};