aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Humbert <jack.humb@gmail.com>2018-05-08 15:24:18 -0400
committerGitHub <noreply@github.com>2018-05-08 15:24:18 -0400
commit14b7602a65dedaf51db1c9288144765d43a83a15 (patch)
tree8e21e6b77db1581deaeecfa3373fe70470e64c1f
parent46dca121fd2f51c4f5b87e48af37f43340591433 (diff)
downloadqmk_firmware-14b7602a65dedaf51db1c9288144765d43a83a15.tar.gz
qmk_firmware-14b7602a65dedaf51db1c9288144765d43a83a15.zip
Adds IS31FL3731 RGB Matrix Implementation (#2910)
* adds is31fl3731 rgb matrix implementation * fix build script for force pushes * allow bootloader size to be overwritten * adds planck light implementation * split led config into 2 arrays * idk * betterize register handling * update planck implementation * update planck * refine rgb interface * cleanup names, rgb matrix * start documentation * finish up docs * add effects list * clean-up merge * add RGB_MATRIX_SKIP_FRAMES * add support for at90usb1286 to bootloader options
-rw-r--r--bootloader.mk23
-rw-r--r--common_features.mk9
-rw-r--r--docs/feature_rgb_matrix.md141
-rw-r--r--drivers/avr/TWIlib.c232
-rw-r--r--drivers/avr/TWIlib.h82
-rw-r--r--drivers/avr/is31fl3731.c258
-rw-r--r--drivers/avr/is31fl3731.h214
-rw-r--r--keyboards/planck/light/config.h19
-rw-r--r--keyboards/planck/light/light.c141
-rw-r--r--keyboards/planck/light/light.h4
-rw-r--r--keyboards/planck/light/rules.mk4
-rw-r--r--keyboards/planck/rules.mk2
-rw-r--r--quantum/color.c87
-rw-r--r--quantum/color.h55
-rw-r--r--quantum/quantum.c23
-rw-r--r--quantum/quantum.h6
-rw-r--r--quantum/rgb.h47
-rw-r--r--quantum/rgb_matrix.c873
-rw-r--r--quantum/rgb_matrix.h135
19 files changed, 2336 insertions, 19 deletions
diff --git a/bootloader.mk b/bootloader.mk
index 55352f3d4..f30e38dd0 100644
--- a/bootloader.mk
+++ b/bootloader.mk
@@ -32,17 +32,32 @@
32ifeq ($(strip $(BOOTLOADER)), atmel-dfu) 32ifeq ($(strip $(BOOTLOADER)), atmel-dfu)
33 OPT_DEFS += -DBOOTLOADER_ATMEL_DFU 33 OPT_DEFS += -DBOOTLOADER_ATMEL_DFU
34 OPT_DEFS += -DBOOTLOADER_DFU 34 OPT_DEFS += -DBOOTLOADER_DFU
35 BOOTLOADER_SIZE = 4096 35 ifeq ($(strip $(MCU)), atmega32u4)
36 BOOTLOADER_SIZE = 4096
37 endif
38 ifeq ($(strip $(MCU)), at90usb1286)
39 BOOTLOADER_SIZE = 8192
40 endif
36endif 41endif
37ifeq ($(strip $(BOOTLOADER)), lufa-dfu) 42ifeq ($(strip $(BOOTLOADER)), lufa-dfu)
38 OPT_DEFS += -DBOOTLOADER_LUFA_DFU 43 OPT_DEFS += -DBOOTLOADER_LUFA_DFU
39 OPT_DEFS += -DBOOTLOADER_DFU 44 OPT_DEFS += -DBOOTLOADER_DFU
40 BOOTLOADER_SIZE = 4096 45 ifeq ($(strip $(MCU)), atmega32u4)
46 BOOTLOADER_SIZE = 4096
47 endif
48 ifeq ($(strip $(MCU)), at90usb1286)
49 BOOTLOADER_SIZE = 8192
50 endif
41endif 51endif
42ifeq ($(strip $(BOOTLOADER)), qmk-dfu) 52ifeq ($(strip $(BOOTLOADER)), qmk-dfu)
43 OPT_DEFS += -DBOOTLOADER_QMK_DFU 53 OPT_DEFS += -DBOOTLOADER_QMK_DFU
44 OPT_DEFS += -DBOOTLOADER_DFU 54 OPT_DEFS += -DBOOTLOADER_DFU
45 BOOTLOADER_SIZE = 4096 55 ifeq ($(strip $(MCU)), atmega32u4)
56 BOOTLOADER_SIZE = 4096
57 endif
58 ifeq ($(strip $(MCU)), at90usb1286)
59 BOOTLOADER_SIZE = 8192
60 endif
46endif 61endif
47ifeq ($(strip $(BOOTLOADER)), halfkay) 62ifeq ($(strip $(BOOTLOADER)), halfkay)
48 OPT_DEFS += -DBOOTLOADER_HALFKAY 63 OPT_DEFS += -DBOOTLOADER_HALFKAY
@@ -59,4 +74,4 @@ endif
59 74
60ifdef BOOTLOADER_SIZE 75ifdef BOOTLOADER_SIZE
61 OPT_DEFS += -DBOOTLOADER_SIZE=$(strip $(BOOTLOADER_SIZE)) 76 OPT_DEFS += -DBOOTLOADER_SIZE=$(strip $(BOOTLOADER_SIZE))
62endif \ No newline at end of file 77endif
diff --git a/common_features.mk b/common_features.mk
index 7bd43afdb..7ba7d4815 100644
--- a/common_features.mk
+++ b/common_features.mk
@@ -114,6 +114,15 @@ ifeq ($(strip $(RGBLIGHT_ENABLE)), yes)
114 endif 114 endif
115endif 115endif
116 116
117ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
118 OPT_DEFS += -DRGB_MATRIX_ENABLE
119 SRC += is31fl3731.c
120 SRC += TWIlib.c
121 SRC += $(QUANTUM_DIR)/color.c
122 SRC += $(QUANTUM_DIR)/rgb_matrix.c
123 CIE1931_CURVE = yes
124endif
125
117ifeq ($(strip $(TAP_DANCE_ENABLE)), yes) 126ifeq ($(strip $(TAP_DANCE_ENABLE)), yes)
118 OPT_DEFS += -DTAP_DANCE_ENABLE 127 OPT_DEFS += -DTAP_DANCE_ENABLE
119 SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c 128 SRC += $(QUANTUM_DIR)/process_keycode/process_tap_dance.c
diff --git a/docs/feature_rgb_matrix.md b/docs/feature_rgb_matrix.md
new file mode 100644
index 000000000..dfc103247
--- /dev/null
+++ b/docs/feature_rgb_matrix.md
@@ -0,0 +1,141 @@
1# RGB Matrix Lighting
2
3There is basic support for addressable RGB matrix lighting with the I2C IS31FL3731 RGB controller. To enable it, add this to your `rules.mk`:
4
5 RGB_MATRIX_ENABLE = yes
6
7Configure the hardware via your `config.h`:
8
9 // This is a 7-bit address, that gets left-shifted and bit 0
10 // set to 0 for write, 1 for read (as per I2C protocol)
11 // The address will vary depending on your wiring:
12 // 0b1110100 AD <-> GND
13 // 0b1110111 AD <-> VCC
14 // 0b1110101 AD <-> SCL
15 // 0b1110110 AD <-> SDA
16 #define DRIVER_ADDR_1 0b1110100
17 #define DRIVER_ADDR_2 0b1110110
18
19 #define DRIVER_COUNT 2
20 #define DRIVER_1_LED_TOTAL 25
21 #define DRIVER_2_LED_TOTAL 24
22 #define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL
23
24Currently only 2 drivers are supported, but it would be trivial to support all 4 combinations.
25
26Define these arrays listing all the LEDs in your `<keyboard>.c`:
27
28 const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
29 /* Refer to IS31 manual for these locations
30 * driver
31 * | R location
32 * | | G location
33 * | | | B location
34 * | | | | */
35 {0, C1_3, C2_3, C3_3},
36 ....
37 }
38
39Where `Cx_y` is the location of the LED in the matrix defined by [the datasheet](http://www.issi.com/WW/pdf/31FL3731.pdf). The `driver` is the index of the driver you defined in your `config.h` (`0` or `1` right now).
40
41 const rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = {
42 /* {row | col << 4}
43 * | {x=0..224, y=0..64}
44 * | | modifier
45 * | | | */
46 {{0|(0<<4)}, {20.36*0, 21.33*0}, 1},
47 {{0|(1<<4)}, {20.36*1, 21.33*0}, 1},
48 ....
49 }
50
51The format for the matrix position used in this array is `{row | (col << 4)}`. The `x` is between (inclusive) 0-224, and `y` is between (inclusive) 0-64. The easiest way to calculate these positions is:
52
53 x = 224 / ( NUMBER_OF_ROWS - 1 ) * ROW_POSITION
54 y = 64 / (NUMBER_OF_COLS - 1 ) * COL_POSITION
55
56Where all variables are decimels/floats.
57
58`modifier` is a boolean, whether or not a certain key is considered a modifier (used in some effects).
59
60## Keycodes
61
62All RGB keycodes are currently shared with the RGBLIGHT system:
63
64 * `RGB_TOG` - toggle
65 * `RGB_MOD` - cycle through modes
66 * `RGB_HUI` - increase hue
67 * `RGB_HUD` - decrease hue
68 * `RGB_SAI` - increase saturation
69 * `RGB_SAD` - decrease saturation
70 * `RGB_VAI` - increase value
71 * `RGB_VAD` - decrease value
72
73
74 * `RGB_MODE_*` keycodes will generally work, but are not currently mapped to the correct effects for the RGB Matrix system
75
76## RGB Matrix Effects
77
78These are the effects that are currently available:
79
80 enum rgb_matrix_effects {
81 RGB_MATRIX_SOLID_COLOR = 1,
82 RGB_MATRIX_SOLID_REACTIVE,
83 RGB_MATRIX_ALPHAS_MODS,
84 RGB_MATRIX_DUAL_BEACON,
85 RGB_MATRIX_GRADIENT_UP_DOWN,
86 RGB_MATRIX_RAINDROPS,
87 RGB_MATRIX_CYCLE_ALL,
88 RGB_MATRIX_CYCLE_LEFT_RIGHT,
89 RGB_MATRIX_CYCLE_UP_DOWN,
90 RGB_MATRIX_RAINBOW_BEACON,
91 RGB_MATRIX_RAINBOW_PINWHEELS,
92 RGB_MATRIX_RAINBOW_MOVING_CHEVRON,
93 RGB_MATRIX_JELLYBEAN_RAINDROPS,
94 #ifdef RGB_MATRIX_KEYPRESSES
95 RGB_MATRIX_SPLASH,
96 RGB_MATRIX_MULTISPLASH,
97 RGB_MATRIX_SOLID_SPLASH,
98 RGB_MATRIX_SOLID_MULTISPLASH,
99 #endif
100 RGB_MATRIX_EFFECT_MAX
101 };
102
103## Custom layer effects
104
105Custom layer effects can be done by defining this in your `<keyboard>.c`:
106
107 void rgb_matrix_indicators_kb(void) {
108 // rgb_matrix_set_color(index, red, green, blue);
109 }
110
111A similar function works in the keymap as `rgb_matrix_indicators_user`.
112
113## Additional `config.h` Options
114
115 #define RGB_MATRIX_KEYPRESSES // reacts to keypresses (will slow down matrix scan by a lot)
116 #define RGB_MATRIX_KEYRELEASES // reacts to keyreleases (not recommened)
117 #define RGB_DISABLE_AFTER_TIMEOUT 0 // number of ticks to wait until disabling effects
118 #define RGB_DISABLE_WHEN_USB_SUSPENDED false // turn off effects when suspended
119 #define RGB_MATRIX_SKIP_FRAMES 1 // number of frames to skip when displaying animations (0 is full effect)
120
121## EEPROM storage
122
123The EEPROM for it is currently shared with the RGBLIGHT system (it's generally assumed only one RGB would be used at a time), but could be configured to use its own 32bit address with:
124
125 #define EECONFIG_RGB_MATRIX (uint32_t *)16
126
127Where `16` is an unused index from `eeconfig.h`.
128
129## Suspended state
130
131To use the suspend feature, add this to your `<keyboard>.c`:
132
133 void suspend_power_down_kb(void)
134 {
135 rgb_matrix_set_suspend_state(true);
136 }
137
138 void suspend_wakeup_init_kb(void)
139 {
140 rgb_matrix_set_suspend_state(false);
141 }
diff --git a/drivers/avr/TWIlib.c b/drivers/avr/TWIlib.c
new file mode 100644
index 000000000..b39e3054a
--- /dev/null
+++ b/drivers/avr/TWIlib.c
@@ -0,0 +1,232 @@
1/*
2 * TWIlib.c
3 *
4 * Created: 6/01/2014 10:41:33 PM
5 * Author: Chris Herring
6 * http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/
7 */
8
9#include <avr/io.h>
10#include <avr/interrupt.h>
11#include "TWIlib.h"
12#include "util/delay.h"
13
14void TWIInit()
15{
16 TWIInfo.mode = Ready;
17 TWIInfo.errorCode = 0xFF;
18 TWIInfo.repStart = 0;
19 // Set pre-scalers (no pre-scaling)
20 TWSR = 0;
21 // Set bit rate
22 TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
23 // Enable TWI and interrupt
24 TWCR = (1 << TWIE) | (1 << TWEN);
25}
26
27uint8_t isTWIReady()
28{
29 if ( (TWIInfo.mode == Ready) | (TWIInfo.mode == RepeatedStartSent) )
30 {
31 return 1;
32 }
33 else
34 {
35 return 0;
36 }
37}
38
39uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart)
40{
41 if (dataLen <= TXMAXBUFLEN)
42 {
43 // Wait until ready
44 while (!isTWIReady()) {_delay_us(1);}
45 // Set repeated start mode
46 TWIInfo.repStart = repStart;
47 // Copy data into the transmit buffer
48 uint8_t *data = (uint8_t *)TXdata;
49 for (int i = 0; i < dataLen; i++)
50 {
51 TWITransmitBuffer[i] = data[i];
52 }
53 // Copy transmit info to global variables
54 TXBuffLen = dataLen;
55 TXBuffIndex = 0;
56
57 // If a repeated start has been sent, then devices are already listening for an address
58 // and another start does not need to be sent.
59 if (TWIInfo.mode == RepeatedStartSent)
60 {
61 TWIInfo.mode = Initializing;
62 TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
63 TWISendTransmit(); // Send the data
64 }
65 else // Otherwise, just send the normal start signal to begin transmission.
66 {
67 TWIInfo.mode = Initializing;
68 TWISendStart();
69 }
70
71 }
72 else
73 {
74 return 1; // return an error if data length is longer than buffer
75 }
76 return 0;
77}
78
79uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart)
80{
81 // Check if number of bytes to read can fit in the RXbuffer
82 if (bytesToRead < RXMAXBUFLEN)
83 {
84 // Reset buffer index and set RXBuffLen to the number of bytes to read
85 RXBuffIndex = 0;
86 RXBuffLen = bytesToRead;
87 // Create the one value array for the address to be transmitted
88 uint8_t TXdata[1];
89 // Shift the address and AND a 1 into the read write bit (set to write mode)
90 TXdata[0] = (TWIaddr << 1) | 0x01;
91 // Use the TWITransmitData function to initialize the transfer and address the slave
92 TWITransmitData(TXdata, 1, repStart);
93 }
94 else
95 {
96 return 0;
97 }
98 return 1;
99}
100
101ISR (TWI_vect)
102{
103 switch (TWI_STATUS)
104 {
105 // ----\/ ---- MASTER TRANSMITTER OR WRITING ADDRESS ----\/ ---- //
106 case TWI_MT_SLAW_ACK: // SLA+W transmitted and ACK received
107 // Set mode to Master Transmitter
108 TWIInfo.mode = MasterTransmitter;
109 case TWI_START_SENT: // Start condition has been transmitted
110 case TWI_MT_DATA_ACK: // Data byte has been transmitted, ACK received
111 if (TXBuffIndex < TXBuffLen) // If there is more data to send
112 {
113 TWDR = TWITransmitBuffer[TXBuffIndex++]; // Load data to transmit buffer
114 TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
115 TWISendTransmit(); // Send the data
116 }
117 // This transmission is complete however do not release bus yet
118 else if (TWIInfo.repStart)
119 {
120 TWIInfo.errorCode = 0xFF;
121 TWISendStart();
122 }
123 // All transmissions are complete, exit
124 else
125 {
126 TWIInfo.mode = Ready;
127 TWIInfo.errorCode = 0xFF;
128 TWISendStop();
129 }
130 break;
131
132 // ----\/ ---- MASTER RECEIVER ----\/ ---- //
133
134 case TWI_MR_SLAR_ACK: // SLA+R has been transmitted, ACK has been received
135 // Switch to Master Receiver mode
136 TWIInfo.mode = MasterReceiver;
137 // If there is more than one byte to be read, receive data byte and return an ACK
138 if (RXBuffIndex < RXBuffLen-1)
139 {
140 TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
141 TWISendACK();
142 }
143 // Otherwise when a data byte (the only data byte) is received, return NACK
144 else
145 {
146 TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
147 TWISendNACK();
148 }
149 break;
150
151 case TWI_MR_DATA_ACK: // Data has been received, ACK has been transmitted.
152
153 /// -- HANDLE DATA BYTE --- ///
154 TWIReceiveBuffer[RXBuffIndex++] = TWDR;
155 // If there is more than one byte to be read, receive data byte and return an ACK
156 if (RXBuffIndex < RXBuffLen-1)
157 {
158 TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
159 TWISendACK();
160 }
161 // Otherwise when a data byte (the only data byte) is received, return NACK
162 else
163 {
164 TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
165 TWISendNACK();
166 }
167 break;
168
169 case TWI_MR_DATA_NACK: // Data byte has been received, NACK has been transmitted. End of transmission.
170
171 /// -- HANDLE DATA BYTE --- ///
172 TWIReceiveBuffer[RXBuffIndex++] = TWDR;
173 // This transmission is complete however do not release bus yet
174 if (TWIInfo.repStart)
175 {
176 TWIInfo.errorCode = 0xFF;
177 TWISendStart();
178 }
179 // All transmissions are complete, exit
180 else
181 {
182 TWIInfo.mode = Ready;
183 TWIInfo.errorCode = 0xFF;
184 TWISendStop();
185 }
186 break;
187
188 // ----\/ ---- MT and MR common ----\/ ---- //
189
190 case TWI_MR_SLAR_NACK: // SLA+R transmitted, NACK received
191 case TWI_MT_SLAW_NACK: // SLA+W transmitted, NACK received
192 case TWI_MT_DATA_NACK: // Data byte has been transmitted, NACK received
193 case TWI_LOST_ARBIT: // Arbitration has been lost
194 // Return error and send stop and set mode to ready
195 if (TWIInfo.repStart)
196 {
197 TWIInfo.errorCode = TWI_STATUS;
198 TWISendStart();
199 }
200 // All transmissions are complete, exit
201 else
202 {
203 TWIInfo.mode = Ready;
204 TWIInfo.errorCode = TWI_STATUS;
205 TWISendStop();
206 }
207 break;
208 case TWI_REP_START_SENT: // Repeated start has been transmitted
209 // Set the mode but DO NOT clear TWINT as the next data is not yet ready
210 TWIInfo.mode = RepeatedStartSent;
211 break;
212
213 // ----\/ ---- SLAVE RECEIVER ----\/ ---- //
214
215 // TODO IMPLEMENT SLAVE RECEIVER FUNCTIONALITY
216
217 // ----\/ ---- SLAVE TRANSMITTER ----\/ ---- //
218
219 // TODO IMPLEMENT SLAVE TRANSMITTER FUNCTIONALITY
220
221 // ----\/ ---- MISCELLANEOUS STATES ----\/ ---- //
222 case TWI_NO_RELEVANT_INFO: // It is not really possible to get into this ISR on this condition
223 // Rather, it is there to be manually set between operations
224 break;
225 case TWI_ILLEGAL_START_STOP: // Illegal START/STOP, abort and return error
226 TWIInfo.errorCode = TWI_ILLEGAL_START_STOP;
227 TWIInfo.mode = Ready;
228 TWISendStop();
229 break;
230 }
231
232}
diff --git a/drivers/avr/TWIlib.h b/drivers/avr/TWIlib.h
new file mode 100644
index 000000000..23fd1f09a
--- /dev/null
+++ b/drivers/avr/TWIlib.h
@@ -0,0 +1,82 @@
1/*
2 * TWIlib.h
3 *
4 * Created: 6/01/2014 10:38:42 PM
5 * Author: Chris Herring
6 * http://www.chrisherring.net/all/tutorial-interrupt-driven-twi-interface-for-avr-part1/
7 */
8
9
10#ifndef TWILIB_H_
11#define TWILIB_H_
12// TWI bit rate (was 100000)
13#define TWI_FREQ 400000
14// Get TWI status
15#define TWI_STATUS (TWSR & 0xF8)
16// Transmit buffer length
17#define TXMAXBUFLEN 20
18// Receive buffer length
19#define RXMAXBUFLEN 20
20// Global transmit buffer
21uint8_t TWITransmitBuffer[TXMAXBUFLEN];
22// Global receive buffer
23volatile uint8_t TWIReceiveBuffer[RXMAXBUFLEN];
24// Buffer indexes
25volatile int TXBuffIndex; // Index of the transmit buffer. Is volatile, can change at any time.
26int RXBuffIndex; // Current index in the receive buffer
27// Buffer lengths
28int TXBuffLen; // The total length of the transmit buffer
29int RXBuffLen; // The total number of bytes to read (should be less than RXMAXBUFFLEN)
30
31typedef enum {
32 Ready,
33 Initializing,
34 RepeatedStartSent,
35 MasterTransmitter,
36 MasterReceiver,
37 SlaceTransmitter,
38 SlaveReciever
39 } TWIMode;
40
41 typedef struct TWIInfoStruct{
42 TWIMode mode;
43 uint8_t errorCode;
44 uint8_t repStart;
45 }TWIInfoStruct;
46TWIInfoStruct TWIInfo;
47
48
49// TWI Status Codes
50#define TWI_START_SENT 0x08 // Start sent
51#define TWI_REP_START_SENT 0x10 // Repeated Start sent
52// Master Transmitter Mode
53#define TWI_MT_SLAW_ACK 0x18 // SLA+W sent and ACK received
54#define TWI_MT_SLAW_NACK 0x20 // SLA+W sent and NACK received
55#define TWI_MT_DATA_ACK 0x28 // DATA sent and ACK received
56#define TWI_MT_DATA_NACK 0x30 // DATA sent and NACK received
57// Master Receiver Mode
58#define TWI_MR_SLAR_ACK 0x40 // SLA+R sent, ACK received
59#define TWI_MR_SLAR_NACK 0x48 // SLA+R sent, NACK received
60#define TWI_MR_DATA_ACK 0x50 // Data received, ACK returned
61#define TWI_MR_DATA_NACK 0x58 // Data received, NACK returned
62
63// Miscellaneous States
64#define TWI_LOST_ARBIT 0x38 // Arbitration has been lost
65#define TWI_NO_RELEVANT_INFO 0xF8 // No relevant information available
66#define TWI_ILLEGAL_START_STOP 0x00 // Illegal START or STOP condition has been detected
67#define TWI_SUCCESS 0xFF // Successful transfer, this state is impossible from TWSR as bit2 is 0 and read only
68
69
70#define TWISendStart() (TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN)|(1<<TWIE)) // Send the START signal, enable interrupts and TWI, clear TWINT flag to resume transfer.
71#define TWISendStop() (TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN)|(1<<TWIE)) // Send the STOP signal, enable interrupts and TWI, clear TWINT flag.
72#define TWISendTransmit() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // Used to resume a transfer, clear TWINT and ensure that TWI and interrupts are enabled.
73#define TWISendACK() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)|(1<<TWEA)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled and respond with an ACK if the device is addressed as a slave or after it receives a byte.
74#define TWISendNACK() (TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWIE)) // FOR MR mode. Resume a transfer, ensure that TWI and interrupts are enabled but DO NOT respond with an ACK if the device is addressed as a slave or after it receives a byte.
75
76// Function declarations
77uint8_t TWITransmitData(void *const TXdata, uint8_t dataLen, uint8_t repStart);
78void TWIInit(void);
79uint8_t TWIReadData(uint8_t TWIaddr, uint8_t bytesToRead, uint8_t repStart);
80uint8_t isTWIReady(void);
81
82#endif // TWICOMMS_H_ \ No newline at end of file
diff --git a/drivers/avr/is31fl3731.c b/drivers/avr/is31fl3731.c
new file mode 100644
index 000000000..e5941cf41
--- /dev/null
+++ b/drivers/avr/is31fl3731.c
@@ -0,0 +1,258 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "is31fl3731.h"
19#include <avr/interrupt.h>
20#include <avr/io.h>
21#include <util/delay.h>
22#include <string.h>
23#include "TWIlib.h"
24#include "progmem.h"
25
26// This is a 7-bit address, that gets left-shifted and bit 0
27// set to 0 for write, 1 for read (as per I2C protocol)
28// The address will vary depending on your wiring:
29// 0b1110100 AD <-> GND
30// 0b1110111 AD <-> VCC
31// 0b1110101 AD <-> SCL
32// 0b1110110 AD <-> SDA
33#define ISSI_ADDR_DEFAULT 0x74
34
35#define ISSI_REG_CONFIG 0x00
36#define ISSI_REG_CONFIG_PICTUREMODE 0x00
37#define ISSI_REG_CONFIG_AUTOPLAYMODE 0x08
38#define ISSI_REG_CONFIG_AUDIOPLAYMODE 0x18
39
40#define ISSI_CONF_PICTUREMODE 0x00
41#define ISSI_CONF_AUTOFRAMEMODE 0x04
42#define ISSI_CONF_AUDIOMODE 0x08
43
44#define ISSI_REG_PICTUREFRAME 0x01
45
46#define ISSI_REG_SHUTDOWN 0x0A
47#define ISSI_REG_AUDIOSYNC 0x06
48
49#define ISSI_COMMANDREGISTER 0xFD
50#define ISSI_BANK_FUNCTIONREG 0x0B // helpfully called 'page nine'
51
52// Transfer buffer for TWITransmitData()
53uint8_t g_twi_transfer_buffer[TXMAXBUFLEN];
54
55// These buffers match the IS31FL3731 PWM registers 0x24-0xB3.
56// Storing them like this is optimal for I2C transfers to the registers.
57// We could optimize this and take out the unused registers from these
58// buffers and the transfers in IS31FL3731_write_pwm_buffer() but it's
59// probably not worth the extra complexity.
60uint8_t g_pwm_buffer[DRIVER_COUNT][144];
61bool g_pwm_buffer_update_required = false;
62
63uint8_t g_led_control_registers[DRIVER_COUNT][18] = { { 0 }, { 0 } };
64bool g_led_control_registers_update_required = false;
65
66// This is the bit pattern in the LED control registers
67// (for matrix A, add one to register for matrix B)
68//
69// reg - b7 b6 b5 b4 b3 b2 b1 b0
70// 0x00 - R08,R07,R06,R05,R04,R03,R02,R01
71// 0x02 - G08,G07,G06,G05,G04,G03,G02,R00
72// 0x04 - B08,B07,B06,B05,B04,B03,G01,G00
73// 0x06 - - , - , - , - , - ,B02,B01,B00
74// 0x08 - - , - , - , - , - , - , - , -
75// 0x0A - B17,B16,B15, - , - , - , - , -
76// 0x0C - G17,G16,B14,B13,B12,B11,B10,B09
77// 0x0E - R17,G15,G14,G13,G12,G11,G10,G09
78// 0x10 - R16,R15,R14,R13,R12,R11,R10,R09
79
80
81void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data )
82{
83 g_twi_transfer_buffer[0] = (addr << 1) | 0x00;
84 g_twi_transfer_buffer[1] = reg;
85 g_twi_transfer_buffer[2] = data;
86
87 // Set the error code to have no relevant information
88 TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
89 // Continuously attempt to transmit data until a successful transmission occurs
90 //while ( TWIInfo.errorCode != 0xFF )
91 //{
92 TWITransmitData( g_twi_transfer_buffer, 3, 0 );
93 //}
94}
95
96void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer )
97{
98 // assumes bank is already selected
99
100 // transmit PWM registers in 9 transfers of 16 bytes
101 // g_twi_transfer_buffer[] is 20 bytes
102
103 // set the I2C address
104 g_twi_transfer_buffer[0] = (addr << 1) | 0x00;
105
106 // iterate over the pwm_buffer contents at 16 byte intervals
107 for ( int i = 0; i < 144; i += 16 )
108 {
109 // set the first register, e.g. 0x24, 0x34, 0x44, etc.
110 g_twi_transfer_buffer[1] = 0x24 + i;
111 // copy the data from i to i+15
112 // device will auto-increment register for data after the first byte
113 // thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
114 for ( int j = 0; j < 16; j++ )
115 {
116 g_twi_transfer_buffer[2 + j] = pwm_buffer[i + j];
117 }
118
119 // Set the error code to have no relevant information
120 TWIInfo.errorCode = TWI_NO_RELEVANT_INFO;
121 // Continuously attempt to transmit data until a successful transmission occurs
122 while ( TWIInfo.errorCode != 0xFF )
123 {
124 TWITransmitData( g_twi_transfer_buffer, 16 + 2, 0 );
125 }
126 }
127}
128
129void IS31FL3731_init( uint8_t addr )
130{
131 // In order to avoid the LEDs being driven with garbage data
132 // in the LED driver's PWM registers, first enable software shutdown,
133 // then set up the mode and other settings, clear the PWM registers,
134 // then disable software shutdown.
135
136 // select "function register" bank
137 IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
138
139 // enable software shutdown
140 IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x00 );
141 // this delay was copied from other drivers, might not be needed
142 _delay_ms( 10 );
143
144 // picture mode
145 IS31FL3731_write_register( addr, ISSI_REG_CONFIG, ISSI_REG_CONFIG_PICTUREMODE );
146 // display frame 0
147 IS31FL3731_write_register( addr, ISSI_REG_PICTUREFRAME, 0x00 );
148 // audio sync off
149 IS31FL3731_write_register( addr, ISSI_REG_AUDIOSYNC, 0x00 );
150
151 // select bank 0
152 IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
153
154 // turn off all LEDs in the LED control register
155 for ( int i = 0x00; i <= 0x11; i++ )
156 {
157 IS31FL3731_write_register( addr, i, 0x00 );
158 }
159
160 // turn off all LEDs in the blink control register (not really needed)
161 for ( int i = 0x12; i <= 0x23; i++ )
162 {
163 IS31FL3731_write_register( addr, i, 0x00 );
164 }
165
166 // set PWM on all LEDs to 0
167 for ( int i = 0x24; i <= 0xB3; i++ )
168 {
169 IS31FL3731_write_register( addr, i, 0x00 );
170 }
171
172 // select "function register" bank
173 IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, ISSI_BANK_FUNCTIONREG );
174
175 // disable software shutdown
176 IS31FL3731_write_register( addr, ISSI_REG_SHUTDOWN, 0x01 );
177
178 // select bank 0 and leave it selected.
179 // most usage after initialization is just writing PWM buffers in bank 0
180 // as there's not much point in double-buffering
181 IS31FL3731_write_register( addr, ISSI_COMMANDREGISTER, 0 );
182}
183
184void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue )
185{
186 if ( index >= 0 && index < DRIVER_LED_TOTAL ) {
187 is31_led led = g_is31_leds[index];
188
189 // Subtract 0x24 to get the second index of g_pwm_buffer
190 g_pwm_buffer[led.driver][led.r - 0x24] = red;
191 g_pwm_buffer[led.driver][led.g - 0x24] = green;
192 g_pwm_buffer[led.driver][led.b - 0x24] = blue;
193 g_pwm_buffer_update_required = true;
194 }
195}
196
197void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue )
198{
199 for ( int i = 0; i < DRIVER_LED_TOTAL; i++ )
200 {
201 IS31FL3731_set_color( i, red, green, blue );
202 }
203}
204
205void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue )
206{
207 is31_led led = g_is31_leds[index];
208
209 uint8_t control_register_r = (led.r - 0x24) / 8;
210 uint8_t control_register_g = (led.g - 0x24) / 8;
211 uint8_t control_register_b = (led.b - 0x24) / 8;
212 uint8_t bit_r = (led.r - 0x24) % 8;
213 uint8_t bit_g = (led.g - 0x24) % 8;
214 uint8_t bit_b = (led.b - 0x24) % 8;
215
216 if ( red ) {
217 g_led_control_registers[led.driver][control_register_r] |= (1 << bit_r);
218 } else {
219 g_led_control_registers[led.driver][control_register_r] &= ~(1 << bit_r);
220 }
221 if ( green ) {
222 g_led_control_registers[led.driver][control_register_g] |= (1 << bit_g);
223 } else {
224 g_led_control_registers[led.driver][control_register_g] &= ~(1 << bit_g);
225 }
226 if ( blue ) {
227 g_led_control_registers[led.driver][control_register_b] |= (1 << bit_b);
228 } else {
229 g_led_control_registers[led.driver][control_register_b] &= ~(1 << bit_b);
230 }
231
232 g_led_control_registers_update_required = true;
233
234
235}
236
237void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 )
238{
239 if ( g_pwm_buffer_update_required )
240 {
241 IS31FL3731_write_pwm_buffer( addr1, g_pwm_buffer[0] );
242 IS31FL3731_write_pwm_buffer( addr2, g_pwm_buffer[1] );
243 }
244 g_pwm_buffer_update_required = false;
245}
246
247void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 )
248{
249 if ( g_led_control_registers_update_required )
250 {
251 for ( int i=0; i<18; i++ )
252 {
253 IS31FL3731_write_register(addr1, i, g_led_control_registers[0][i] );
254 IS31FL3731_write_register(addr2, i, g_led_control_registers[1][i] );
255 }
256 }
257}
258
diff --git a/drivers/avr/is31fl3731.h b/drivers/avr/is31fl3731.h
new file mode 100644
index 000000000..3d30fc67b
--- /dev/null
+++ b/drivers/avr/is31fl3731.h
@@ -0,0 +1,214 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2018 Jack Humbert
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19#ifndef IS31FL3731_DRIVER_H
20#define IS31FL3731_DRIVER_H
21
22#include <stdint.h>
23#include <stdbool.h>
24
25typedef struct is31_led {
26 uint8_t driver:2;
27 uint8_t r;
28 uint8_t g;
29 uint8_t b;
30} __attribute__((packed)) is31_led;
31
32extern const is31_led g_is31_leds[DRIVER_LED_TOTAL];
33
34void IS31FL3731_init( uint8_t addr );
35void IS31FL3731_write_register( uint8_t addr, uint8_t reg, uint8_t data );
36void IS31FL3731_write_pwm_buffer( uint8_t addr, uint8_t *pwm_buffer );
37
38void IS31FL3731_set_color( int index, uint8_t red, uint8_t green, uint8_t blue );
39void IS31FL3731_set_color_all( uint8_t red, uint8_t green, uint8_t blue );
40
41void IS31FL3731_set_led_control_register( uint8_t index, bool red, bool green, bool blue );
42
43// This should not be called from an interrupt
44// (eg. from a timer interrupt).
45// Call this while idle (in between matrix scans).
46// If the buffer is dirty, it will update the driver with the buffer.
47void IS31FL3731_update_pwm_buffers( uint8_t addr1, uint8_t addr2 );
48void IS31FL3731_update_led_control_registers( uint8_t addr1, uint8_t addr2 );
49
50#define C1_1 0x24
51#define C1_2 0x25
52#define C1_3 0x26
53#define C1_4 0x27
54#define C1_5 0x28
55#define C1_6 0x29
56#define C1_7 0x2A
57#define C1_8 0x2B
58
59#define C1_9 0x2C
60#define C1_10 0x2D
61#define C1_11 0x2E
62#define C1_12 0x2F
63#define C1_13 0x30
64#define C1_14 0x31
65#define C1_15 0x32
66#define C1_16 0x33
67
68#define C2_1 0x34
69#define C2_2 0x35
70#define C2_3 0x36
71#define C2_4 0x37
72#define C2_5 0x38
73#define C2_6 0x39
74#define C2_7 0x3A
75#define C2_8 0x3B
76
77#define C2_9 0x3C
78#define C2_10 0x3D
79#define C2_11 0x3E
80#define C2_12 0x3F
81#define C2_13 0x40
82#define C2_14 0x41
83#define C2_15 0x42
84#define C2_16 0x43
85
86#define C3_1 0x44
87#define C3_2 0x45
88#define C3_3 0x46
89#define C3_4 0x47
90#define C3_5 0x48
91#define C3_6 0x49
92#define C3_7 0x4A
93#define C3_8 0x4B
94
95#define C3_9 0x4C
96#define C3_10 0x4D
97#define C3_11 0x4E
98#define C3_12 0x4F
99#define C3_13 0x50
100#define C3_14 0x51
101#define C3_15 0x52
102#define C3_16 0x53
103
104#define C4_1 0x54
105#define C4_2 0x55
106#define C4_3 0x56
107#define C4_4 0x57
108#define C4_5 0x58
109#define C4_6 0x59
110#define C4_7 0x5A
111#define C4_8 0x5B
112
113#define C4_9 0x5C
114#define C4_10 0x5D
115#define C4_11 0x5E
116#define C4_12 0x5F
117#define C4_13 0x60
118#define C4_14 0x61
119#define C4_15 0x62
120#define C4_16 0x63
121
122#define C5_1 0x64
123#define C5_2 0x65
124#define C5_3 0x66
125#define C5_4 0x67
126#define C5_5 0x68
127#define C5_6 0x69
128#define C5_7 0x6A
129#define C5_8 0x6B
130
131#define C5_9 0x6C
132#define C5_10 0x6D
133#define C5_11 0x6E
134#define C5_12 0x6F
135#define C5_13 0x70
136#define C5_14 0x71
137#define C5_15 0x72
138#define C5_16 0x73
139
140#define C6_1 0x74
141#define C6_2 0x75
142#define C6_3 0x76
143#define C6_4 0x77
144#define C6_5 0x78
145#define C6_6 0x79
146#define C6_7 0x7A
147#define C6_8 0x7B
148
149#define C6_9 0x7C
150#define C6_10 0x7D
151#define C6_11 0x7E
152#define C6_12 0x7F
153#define C6_13 0x80
154#define C6_14 0x81
155#define C6_15 0x82
156#define C6_16 0x83
157
158#define C7_1 0x84
159#define C7_2 0x85
160#define C7_3 0x86
161#define C7_4 0x87
162#define C7_5 0x88
163#define C7_6 0x89
164#define C7_7 0x8A
165#define C7_8 0x8B
166
167#define C7_9 0x8C
168#define C7_10 0x8D
169#define C7_11 0x8E
170#define C7_12 0x8F
171#define C7_13 0x90
172#define C7_14 0x91
173#define C7_15 0x92
174#define C7_16 0x93
175
176#define C8_1 0x94
177#define C8_2 0x95
178#define C8_3 0x96
179#define C8_4 0x97
180#define C8_5 0x98
181#define C8_6 0x99
182#define C8_7 0x9A
183#define C8_8 0x9B
184
185#define C8_9 0x9C
186#define C8_10 0x9D
187#define C8_11 0x9E
188#define C8_12 0x9F
189#define C8_13 0xA0
190#define C8_14 0xA1
191#define C8_15 0xA2
192#define C8_16 0xA3
193
194#define C9_1 0xA4
195#define C9_2 0xA5
196#define C9_3 0xA6
197#define C9_4 0xA7
198#define C9_5 0xA8
199#define C9_6 0xA9
200#define C9_7 0xAA
201#define C9_8 0xAB
202
203#define C9_9 0xAC
204#define C9_10 0xAD
205#define C9_11 0xAE
206#define C9_12 0xAF
207#define C9_13 0xB0
208#define C9_14 0xB1
209#define C9_15 0xB2
210#define C9_16 0xB3
211
212
213
214#endif // IS31FL3731_DRIVER_H
diff --git a/keyboards/planck/light/config.h b/keyboards/planck/light/config.h
index 71c924904..17c015ed0 100644
--- a/keyboards/planck/light/config.h
+++ b/keyboards/planck/light/config.h
@@ -24,5 +24,22 @@
24 24
25#define NO_USB_STARTUP_CHECK 25#define NO_USB_STARTUP_CHECK
26 26
27#define PLANCK_MIT_LAYOUT
27 28
28#endif \ No newline at end of file 29// This is a 7-bit address, that gets left-shifted and bit 0
30// set to 0 for write, 1 for read (as per I2C protocol)
31// The address will vary depending on your wiring:
32// 0b1110100 AD <-> GND
33// 0b1110111 AD <-> VCC
34// 0b1110101 AD <-> SCL
35// 0b1110110 AD <-> SDA
36#define DRIVER_ADDR_1 0b1110100
37#define DRIVER_ADDR_2 0b1110110
38
39#define DRIVER_COUNT 2
40#define DRIVER_1_LED_TOTAL 25
41#define DRIVER_2_LED_TOTAL 24
42#define DRIVER_LED_TOTAL DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL
43
44
45#endif
diff --git a/keyboards/planck/light/light.c b/keyboards/planck/light/light.c
index 96261616c..cef57c5e6 100644
--- a/keyboards/planck/light/light.c
+++ b/keyboards/planck/light/light.c
@@ -1,5 +1,4 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jack Humbert
2 * Copyright 2017 Jack Humbert
3 * 2 *
4 * This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
@@ -17,6 +16,127 @@
17 16
18#include "light.h" 17#include "light.h"
19 18
19const is31_led g_is31_leds[DRIVER_LED_TOTAL] = {
20/* Refer to IS31 manual for these locations
21 * driver
22 * | R location
23 * | | G location
24 * | | | B location
25 * | | | | */
26 {0, C1_3, C2_3, C3_3},
27 {0, C1_4, C2_4, C3_4},
28 {0, C1_5, C2_5, C3_5},
29 {0, C1_11, C2_11, C3_11},
30 {0, C1_12, C2_12, C3_12},
31 {0, C1_13, C2_13, C3_13},
32 {1, C1_3, C2_3, C3_3},
33 {1, C1_4, C2_4, C3_4},
34 {1, C1_5, C2_5, C3_5},
35 {1, C1_11, C2_11, C3_11},
36 {1, C1_12, C2_12, C3_12},
37 {1, C1_13, C2_13, C3_13},
38
39 {0, C1_6, C2_6, C3_6},
40 {0, C1_7, C2_7, C3_7},
41 {0, C1_8, C2_8, C3_8},
42 {0, C1_14, C2_14, C3_14},
43 {0, C1_15, C2_15, C3_15},
44 {0, C1_16, C2_16, C3_16},
45 {1, C1_6, C2_6, C3_6},
46 {1, C1_7, C2_7, C3_7},
47 {1, C1_8, C2_8, C3_8},
48 {1, C1_14, C2_14, C3_14},
49 {1, C1_15, C2_15, C3_15},
50 {1, C1_16, C2_16, C3_16},
51
52 {0, C9_1, C8_1, C7_1},
53 {0, C9_2, C8_2, C7_2},
54 {0, C9_3, C8_3, C7_3},
55 {0, C9_9, C8_9, C7_9},
56 {0, C9_10, C8_10, C7_10},
57 {0, C9_11, C8_11, C7_11},
58 {1, C9_1, C8_1, C7_1},
59 {1, C9_2, C8_2, C7_2},
60 {1, C9_3, C8_3, C7_3},
61 {1, C9_9, C8_9, C7_9},
62 {1, C9_10, C8_10, C7_10},
63 {1, C9_11, C8_11, C7_11},
64
65 {0, C9_4, C8_4, C7_4},
66 {0, C9_5, C8_5, C7_5},
67 {0, C9_6, C8_6, C7_6},
68 {0, C9_12, C8_12, C7_12},
69 {0, C9_13, C8_13, C7_13},
70 {0, C9_14, C8_14, C7_14},
71 {0, C9_15, C8_15, C6_14}, // middle 2u switch
72 {1, C9_4, C8_4, C7_4},
73 {1, C9_5, C8_5, C7_5},
74 {1, C9_6, C8_6, C7_6},
75 {1, C9_12, C8_12, C7_12},
76 {1, C9_13, C8_13, C7_13},
77 {1, C9_14, C8_14, C7_14}
78};
79
80const rgb_led g_rgb_leds[DRIVER_LED_TOTAL] = {
81
82 /*{row | col << 4}
83 | {x=0..224, y=0..64}
84 | | modifier
85 | | | */
86 {{0|(0<<4)}, {20.36*0, 21.33*0}, 1},
87 {{0|(1<<4)}, {20.36*1, 21.33*0}, 0},
88 {{0|(2<<4)}, {20.36*2, 21.33*0}, 0},
89 {{0|(3<<4)}, {20.36*3, 21.33*0}, 0},
90 {{0|(4<<4)}, {20.36*4, 21.33*0}, 0},
91 {{0|(5<<4)}, {20.36*5, 21.33*0}, 0},
92 {{0|(6<<4)}, {20.36*6, 21.33*0}, 0},
93 {{0|(7<<4)}, {20.36*7, 21.33*0}, 0},
94 {{0|(8<<4)}, {20.36*8, 21.33*0}, 0},
95 {{0|(9<<4)}, {20.36*9, 21.33*0}, 0},
96 {{0|(10<<4)}, {20.36*10,21.33*0}, 0},
97 {{0|(11<<4)}, {20.36*11,21.33*0}, 1},
98
99 {{1|(0<<4)}, {20.36*0, 21.33*1}, 1},
100 {{1|(1<<4)}, {20.36*1, 21.33*1}, 0},
101 {{1|(2<<4)}, {20.36*2, 21.33*1}, 0},
102 {{1|(3<<4)}, {20.36*3, 21.33*1}, 0},
103 {{1|(4<<4)}, {20.36*4, 21.33*1}, 0},
104 {{1|(5<<4)}, {20.36*5, 21.33*1}, 0},
105 {{1|(6<<4)}, {20.36*6, 21.33*1}, 0},
106 {{1|(7<<4)}, {20.36*7, 21.33*1}, 0},
107 {{1|(8<<4)}, {20.36*8, 21.33*1}, 0},
108 {{1|(9<<4)}, {20.36*9, 21.33*1}, 0},
109 {{1|(10<<4)}, {20.36*10,21.33*1}, 0},
110 {{1|(11<<4)}, {20.36*11,21.33*1}, 1},
111
112 {{2|(0<<4)}, {20.36*0, 21.33*2}, 1},
113 {{2|(1<<4)}, {20.36*1, 21.33*2}, 0},
114 {{2|(2<<4)}, {20.36*2, 21.33*2}, 0},
115 {{2|(3<<4)}, {20.36*3, 21.33*2}, 0},
116 {{2|(4<<4)}, {20.36*4, 21.33*2}, 0},
117 {{2|(5<<4)}, {20.36*5, 21.33*2}, 0},
118 {{2|(6<<4)}, {20.36*6, 21.33*2}, 0},
119 {{2|(7<<4)}, {20.36*7, 21.33*2}, 0},
120 {{2|(8<<4)}, {20.36*8, 21.33*2}, 0},
121 {{2|(9<<4)}, {20.36*9, 21.33*2}, 0},
122 {{2|(10<<4)}, {20.36*10,21.33*2}, 0},
123 {{2|(11<<4)}, {20.36*11,21.33*2}, 1},
124
125 {{3|(0<<4)}, {20.36*0, 21.33*3}, 1},
126 {{3|(1<<4)}, {20.36*1, 21.33*3}, 1},
127 {{3|(2<<4)}, {20.36*2, 21.33*3}, 1},
128 {{3|(3<<4)}, {20.36*3, 21.33*3}, 1},
129 {{3|(4<<4)}, {20.36*4, 21.33*3}, 1},
130 {{3|(5<<4)}, {20.36*5, 21.33*3}, 0},
131 {{3|(5<<4)}, {20.36*5.5,21.33*3}, 0},
132 {{3|(6<<4)}, {20.36*6, 21.33*3}, 0},
133 {{3|(7<<4)}, {20.36*7, 21.33*3}, 1},
134 {{3|(8<<4)}, {20.36*8, 21.33*3}, 1},
135 {{3|(9<<4)}, {20.36*9, 21.33*3}, 1},
136 {{3|(10<<4)}, {20.36*10,21.33*3}, 1},
137 {{3|(11<<4)}, {20.36*11,21.33*3}, 1}
138};
139
20void matrix_init_kb(void) { 140void matrix_init_kb(void) {
21 141
22 // Turn status LED on 142 // Turn status LED on
@@ -27,13 +147,22 @@ void matrix_init_kb(void) {
27} 147}
28 148
29bool process_record_kb(uint16_t keycode, keyrecord_t *record) 149bool process_record_kb(uint16_t keycode, keyrecord_t *record)
30{ 150{
31 return process_record_user(keycode, record); 151 return process_record_user(keycode, record);
32} 152}
33 153
34uint16_t backlight_task_counter = 0;
35
36void matrix_scan_kb(void) 154void matrix_scan_kb(void)
37{ 155{
38 matrix_scan_user(); 156 matrix_scan_user();
39} \ No newline at end of file 157}
158
159void suspend_power_down_kb(void)
160{
161 rgb_matrix_set_suspend_state(true);
162}
163
164void suspend_wakeup_init_kb(void)
165{
166 rgb_matrix_set_suspend_state(false);
167}
168
diff --git a/keyboards/planck/light/light.h b/keyboards/planck/light/light.h
index 111f19865..a395f30e8 100644
--- a/keyboards/planck/light/light.h
+++ b/keyboards/planck/light/light.h
@@ -1,5 +1,4 @@
1/* Copyright 2017 Jason Williams 1/* Copyright 2017 Jack Humbert
2 * Copyright 2017 Jack Humbert
3 * 2 *
4 * This program is free software: you can redistribute it and/or modify 3 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 4 * it under the terms of the GNU General Public License as published by
@@ -19,5 +18,6 @@
19#define LIGHT_H 18#define LIGHT_H
20 19
21#include "planck.h" 20#include "planck.h"
21#include "rgb_matrix.h"
22 22
23#endif \ No newline at end of file 23#endif \ No newline at end of file
diff --git a/keyboards/planck/light/rules.mk b/keyboards/planck/light/rules.mk
index 3d7006b52..c10b8fd1d 100644
--- a/keyboards/planck/light/rules.mk
+++ b/keyboards/planck/light/rules.mk
@@ -1,7 +1,5 @@
1MIDI_ENABLE = yes 1MIDI_ENABLE = yes
2AUDIO_ENABLE = yes # Audio output on port C6 2AUDIO_ENABLE = yes # Audio output on port C6
3MOUSEKEY_ENABLE = no # Mouse keys(+4700) 3RGB_MATRIX_ENABLE = yes
4NKRO_ENABLE = yes # Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
5BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
6 4
7MCU = at90usb1286 \ No newline at end of file 5MCU = at90usb1286 \ No newline at end of file
diff --git a/keyboards/planck/rules.mk b/keyboards/planck/rules.mk
index 511c06d70..e194dcd51 100644
--- a/keyboards/planck/rules.mk
+++ b/keyboards/planck/rules.mk
@@ -48,7 +48,7 @@ ifeq ($(strip $(KEYBOARD)), planck/rev5)
48 BOOTLOADER = qmk-dfu 48 BOOTLOADER = qmk-dfu
49endif 49endif
50ifeq ($(strip $(KEYBOARD)), planck/light) 50ifeq ($(strip $(KEYBOARD)), planck/light)
51 BOOTLOADER = qmk-dfu 51 BOOTLOADER = atmel-dfu
52endif 52endif
53 53
54# Interrupt driven control endpoint task(+60) 54# Interrupt driven control endpoint task(+60)
diff --git a/quantum/color.c b/quantum/color.c
new file mode 100644
index 000000000..8ede053e7
--- /dev/null
+++ b/quantum/color.c
@@ -0,0 +1,87 @@
1/* Copyright 2017 Jason Williams
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
18#include "color.h"
19#include "led_tables.h"
20#include "progmem.h"
21
22RGB hsv_to_rgb( HSV hsv )
23{
24 RGB rgb;
25 uint8_t region, p, q, t;
26 uint16_t h, s, v, remainder;
27
28 if ( hsv.s == 0 )
29 {
30 rgb.r = hsv.v;
31 rgb.g = hsv.v;
32 rgb.b = hsv.v;
33 return rgb;
34 }
35
36 h = hsv.h;
37 s = hsv.s;
38 v = hsv.v;
39
40 region = h / 43;
41 remainder = (h - (region * 43)) * 6;
42
43 p = (v * (255 - s)) >> 8;
44 q = (v * (255 - ((s * remainder) >> 8))) >> 8;
45 t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
46
47 switch ( region )
48 {
49 case 0:
50 rgb.r = v;
51 rgb.g = t;
52 rgb.b = p;
53 break;
54 case 1:
55 rgb.r = q;
56 rgb.g = v;
57 rgb.b = p;
58 break;
59 case 2:
60 rgb.r = p;
61 rgb.g = v;
62 rgb.b = t;
63 break;
64 case 3:
65 rgb.r = p;
66 rgb.g = q;
67 rgb.b = v;
68 break;
69 case 4:
70 rgb.r = t;
71 rgb.g = p;
72 rgb.b = v;
73 break;
74 default:
75 rgb.r = v;
76 rgb.g = p;
77 rgb.b = q;
78 break;
79 }
80
81 rgb.r = pgm_read_byte( &CIE1931_CURVE[rgb.r] );
82 rgb.g = pgm_read_byte( &CIE1931_CURVE[rgb.g] );
83 rgb.b = pgm_read_byte( &CIE1931_CURVE[rgb.b] );
84
85 return rgb;
86}
87
diff --git a/quantum/color.h b/quantum/color.h
new file mode 100644
index 000000000..9d51d45ad
--- /dev/null
+++ b/quantum/color.h
@@ -0,0 +1,55 @@
1/* Copyright 2017 Jason Williams
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
18#ifndef COLOR_H
19#define COLOR_H
20
21#include <stdint.h>
22#include <stdbool.h>
23
24
25#if defined(__GNUC__)
26#define PACKED __attribute__ ((__packed__))
27#else
28#define PACKED
29#endif
30
31#if defined(_MSC_VER)
32#pragma pack( push, 1 )
33#endif
34
35typedef struct PACKED
36{
37 uint8_t r;
38 uint8_t g;
39 uint8_t b;
40} RGB;
41
42typedef struct PACKED
43{
44 uint8_t h;
45 uint8_t s;
46 uint8_t v;
47} HSV;
48
49#if defined(_MSC_VER)
50#pragma pack( pop )
51#endif
52
53RGB hsv_to_rgb( HSV hsv );
54
55#endif // COLOR_H
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 2662e5ef1..e1bc8b242 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -230,6 +230,9 @@ bool process_record_quantum(keyrecord_t *record) {
230 process_clicky(keycode, record) && 230 process_clicky(keycode, record) &&
231 #endif //AUDIO_CLICKY 231 #endif //AUDIO_CLICKY
232 process_record_kb(keycode, record) && 232 process_record_kb(keycode, record) &&
233 #if defined(RGB_MATRIX_ENABLE) && defined(RGB_MATRIX_KEYPRESSES)
234 process_rgb_matrix(keycode, record) &&
235 #endif
233 #if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED) 236 #if defined(MIDI_ENABLE) && defined(MIDI_ADVANCED)
234 process_midi(keycode, record) && 237 process_midi(keycode, record) &&
235 #endif 238 #endif
@@ -307,7 +310,7 @@ bool process_record_quantum(keyrecord_t *record) {
307 } 310 }
308 return false; 311 return false;
309 #endif 312 #endif
310 #ifdef RGBLIGHT_ENABLE 313 #if defined(RGBLIGHT_ENABLE) || defined(RGB_MATRIX_ENABLE)
311 case RGB_TOG: 314 case RGB_TOG:
312 if (record->event.pressed) { 315 if (record->event.pressed) {
313 rgblight_toggle(); 316 rgblight_toggle();
@@ -835,9 +838,18 @@ void matrix_init_quantum() {
835 #ifdef AUDIO_ENABLE 838 #ifdef AUDIO_ENABLE
836 audio_init(); 839 audio_init();
837 #endif 840 #endif
841 #ifdef RGB_MATRIX_ENABLE
842 rgb_matrix_init_drivers();
843 #endif
838 matrix_init_kb(); 844 matrix_init_kb();
839} 845}
840 846
847uint8_t rgb_matrix_task_counter = 0;
848
849#ifndef RGB_MATRIX_SKIP_FRAMES
850 #define RGB_MATRIX_SKIP_FRAMES 1
851#endif
852
841void matrix_scan_quantum() { 853void matrix_scan_quantum() {
842 #if defined(AUDIO_ENABLE) 854 #if defined(AUDIO_ENABLE)
843 matrix_scan_music(); 855 matrix_scan_music();
@@ -855,9 +867,16 @@ void matrix_scan_quantum() {
855 backlight_task(); 867 backlight_task();
856 #endif 868 #endif
857 869
870 #ifdef RGB_MATRIX_ENABLE
871 rgb_matrix_task();
872 if (rgb_matrix_task_counter == 0) {
873 rgb_matrix_update_pwm_buffers();
874 }
875 rgb_matrix_task_counter = ((rgb_matrix_task_counter + 1) % (RGB_MATRIX_SKIP_FRAMES + 1));
876 #endif
877
858 matrix_scan_kb(); 878 matrix_scan_kb();
859} 879}
860
861#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN) 880#if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
862 881
863static const uint8_t backlight_pin = BACKLIGHT_PIN; 882static const uint8_t backlight_pin = BACKLIGHT_PIN;
diff --git a/quantum/quantum.h b/quantum/quantum.h
index 195f578de..2958a0abd 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -27,9 +27,15 @@
27#ifdef BACKLIGHT_ENABLE 27#ifdef BACKLIGHT_ENABLE
28 #include "backlight.h" 28 #include "backlight.h"
29#endif 29#endif
30#if !defined(RGBLIGHT_ENABLE) && !defined(RGB_MATRIX_ENABLE)
31 #include "rgb.h"
32#endif
30#ifdef RGBLIGHT_ENABLE 33#ifdef RGBLIGHT_ENABLE
31 #include "rgblight.h" 34 #include "rgblight.h"
32#endif 35#endif
36#ifdef RGB_MATRIX_ENABLE
37 #include "rgb_matrix.h"
38#endif
33#include "action_layer.h" 39#include "action_layer.h"
34#include "eeconfig.h" 40#include "eeconfig.h"
35#include <stddef.h> 41#include <stddef.h>
diff --git a/quantum/rgb.h b/quantum/rgb.h
new file mode 100644
index 000000000..fbdda293f
--- /dev/null
+++ b/quantum/rgb.h
@@ -0,0 +1,47 @@
1/* Copyright 2017 Jack Humbert
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#ifndef RGB_H
18#define RGB_H
19
20__attribute__((weak))
21void rgblight_toggle(void) {};
22
23__attribute__((weak))
24void rgblight_step(void) {};
25
26__attribute__((weak))
27void rgblight_step_reverse(void) {};
28
29__attribute__((weak))
30void rgblight_increase_hue(void) {};
31
32__attribute__((weak))
33void rgblight_decrease_hue(void) {};
34
35__attribute__((weak))
36void rgblight_increase_sat(void) {};
37
38__attribute__((weak))
39void rgblight_decrease_sat(void) {};
40
41__attribute__((weak))
42void rgblight_increase_val(void) {};
43
44__attribute__((weak))
45void rgblight_decrease_val(void) {};
46
47#endif \ No newline at end of file
diff --git a/quantum/rgb_matrix.c b/quantum/rgb_matrix.c
new file mode 100644
index 000000000..6cb0478f7
--- /dev/null
+++ b/quantum/rgb_matrix.c
@@ -0,0 +1,873 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2017 Jack Humbert
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19#include "rgb_matrix.h"
20#include <avr/io.h>
21#include "TWIlib.h"
22#include <util/delay.h>
23#include <avr/interrupt.h>
24#include "progmem.h"
25#include "config.h"
26#include "eeprom.h"
27#include "lufa.h"
28#include <math.h>
29
30rgb_config_t rgb_matrix_config;
31
32#ifndef RGB_DISABLE_AFTER_TIMEOUT
33 #define RGB_DISABLE_AFTER_TIMEOUT 0
34#endif
35
36#ifndef RGB_DISABLE_WHEN_USB_SUSPENDED
37 #define RGB_DISABLE_WHEN_USB_SUSPENDED false
38#endif
39
40#ifndef EECONFIG_RGB_MATRIX
41 #define EECONFIG_RGB_MATRIX EECONFIG_RGBLIGHT
42#endif
43
44bool g_suspend_state = false;
45
46// Global tick at 20 Hz
47uint32_t g_tick = 0;
48
49// Ticks since this key was last hit.
50uint8_t g_key_hit[DRIVER_LED_TOTAL];
51
52// Ticks since any key was last hit.
53uint32_t g_any_key_hit = 0;
54
55#ifndef PI
56#define PI 3.14159265
57#endif
58
59uint32_t eeconfig_read_rgb_matrix(void) {
60 return eeprom_read_dword(EECONFIG_RGB_MATRIX);
61}
62void eeconfig_update_rgb_matrix(uint32_t val) {
63 eeprom_update_dword(EECONFIG_RGB_MATRIX, val);
64}
65void eeconfig_update_rgb_matrix_default(void) {
66 dprintf("eeconfig_update_rgb_matrix_default\n");
67 rgb_matrix_config.enable = 1;
68 rgb_matrix_config.mode = RGB_MATRIX_CYCLE_LEFT_RIGHT;
69 rgb_matrix_config.hue = 0;
70 rgb_matrix_config.sat = 255;
71 rgb_matrix_config.val = 255;
72 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
73}
74void eeconfig_debug_rgb_matrix(void) {
75 dprintf("rgb_matrix_config eprom\n");
76 dprintf("rgb_matrix_config.enable = %d\n", rgb_matrix_config.enable);
77 dprintf("rgb_matrix_config.mode = %d\n", rgb_matrix_config.mode);
78 dprintf("rgb_matrix_config.hue = %d\n", rgb_matrix_config.hue);
79 dprintf("rgb_matrix_config.sat = %d\n", rgb_matrix_config.sat);
80 dprintf("rgb_matrix_config.val = %d\n", rgb_matrix_config.val);
81}
82
83// Last led hit
84#define LED_HITS_TO_REMEMBER 8
85uint8_t g_last_led_hit[LED_HITS_TO_REMEMBER] = {255};
86uint8_t g_last_led_count = 0;
87
88void map_row_column_to_led( uint8_t row, uint8_t column, uint8_t *led_i, uint8_t *led_count) {
89 rgb_led led;
90 *led_count = 0;
91
92 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
93 // map_index_to_led(i, &led);
94 led = g_rgb_leds[i];
95 if (row == led.matrix_co.row && column == led.matrix_co.col) {
96 led_i[*led_count] = i;
97 (*led_count)++;
98 }
99 }
100}
101
102
103void rgb_matrix_update_pwm_buffers(void) {
104 IS31FL3731_update_pwm_buffers( DRIVER_ADDR_1, DRIVER_ADDR_2 );
105 IS31FL3731_update_led_control_registers( DRIVER_ADDR_1, DRIVER_ADDR_2 );
106}
107
108void rgb_matrix_set_color( int index, uint8_t red, uint8_t green, uint8_t blue ) {
109 IS31FL3731_set_color( index, red, green, blue );
110}
111
112void rgb_matrix_set_color_all( uint8_t red, uint8_t green, uint8_t blue ) {
113 IS31FL3731_set_color_all( red, green, blue );
114}
115
116
117bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record) {
118 if ( record->event.pressed ) {
119 uint8_t led[8], led_count;
120 map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
121 if (led_count > 0) {
122 for (uint8_t i = LED_HITS_TO_REMEMBER; i > 1; i--) {
123 g_last_led_hit[i - 1] = g_last_led_hit[i - 2];
124 }
125 g_last_led_hit[0] = led[0];
126 g_last_led_count = MIN(LED_HITS_TO_REMEMBER, g_last_led_count + 1);
127 }
128 for(uint8_t i = 0; i < led_count; i++)
129 g_key_hit[led[i]] = 0;
130 g_any_key_hit = 0;
131 } else {
132 #ifdef RGB_MATRIX_KEYRELEASES
133 uint8_t led[8], led_count;
134 map_row_column_to_led(record->event.key.row, record->event.key.col, led, &led_count);
135 for(uint8_t i = 0; i < led_count; i++)
136 g_key_hit[led[i]] = 255;
137
138 g_any_key_hit = 255;
139 #endif
140 }
141 return true;
142}
143
144void rgb_matrix_set_suspend_state(bool state) {
145 g_suspend_state = state;
146}
147
148void rgb_matrix_test(void) {
149 // Mask out bits 4 and 5
150 // This 2-bit value will stay the same for 16 ticks.
151 switch ( (g_tick & 0x30) >> 4 )
152 {
153 case 0:
154 {
155 rgb_matrix_set_color_all( 20, 0, 0 );
156 break;
157 }
158 case 1:
159 {
160 rgb_matrix_set_color_all( 0, 20, 0 );
161 break;
162 }
163 case 2:
164 {
165 rgb_matrix_set_color_all( 0, 0, 20 );
166 break;
167 }
168 case 3:
169 {
170 rgb_matrix_set_color_all( 20, 20, 20 );
171 break;
172 }
173 }
174}
175
176// This tests the LEDs
177// Note that it will change the LED control registers
178// in the LED drivers, and leave them in an invalid
179// state for other backlight effects.
180// ONLY USE THIS FOR TESTING LEDS!
181void rgb_matrix_single_LED_test(void) {
182 static uint8_t color = 0; // 0,1,2 for R,G,B
183 static uint8_t row = 0;
184 static uint8_t column = 0;
185
186 static uint8_t tick = 0;
187 tick++;
188
189 if ( tick > 2 )
190 {
191 tick = 0;
192 column++;
193 }
194 if ( column > MATRIX_COLS )
195 {
196 column = 0;
197 row++;
198 }
199 if ( row > MATRIX_ROWS )
200 {
201 row = 0;
202 color++;
203 }
204 if ( color > 2 )
205 {
206 color = 0;
207 }
208
209 uint8_t led[8], led_count;
210 map_row_column_to_led(row,column,led,&led_count);
211 for(uint8_t i = 0; i < led_count; i++) {
212 rgb_matrix_set_color_all( 40, 40, 40 );
213 rgb_matrix_test_led( led[i], color==0, color==1, color==2 );
214 }
215}
216
217// All LEDs off
218void rgb_matrix_all_off(void) {
219 rgb_matrix_set_color_all( 0, 0, 0 );
220}
221
222// Solid color
223void rgb_matrix_solid_color(void) {
224 HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
225 RGB rgb = hsv_to_rgb( hsv );
226 rgb_matrix_set_color_all( rgb.r, rgb.g, rgb.b );
227}
228
229void rgb_matrix_solid_reactive(void) {
230 // Relies on hue being 8-bit and wrapping
231 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
232 {
233 uint16_t offset2 = g_key_hit[i]<<2;
234 offset2 = (offset2<=130) ? (130-offset2) : 0;
235
236 HSV hsv = { .h = rgb_matrix_config.hue+offset2, .s = 255, .v = rgb_matrix_config.val };
237 RGB rgb = hsv_to_rgb( hsv );
238 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
239 }
240}
241
242// alphas = color1, mods = color2
243void rgb_matrix_alphas_mods(void) {
244
245 RGB rgb1 = hsv_to_rgb( (HSV){ .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val } );
246 RGB rgb2 = hsv_to_rgb( (HSV){ .h = (rgb_matrix_config.hue + 180) % 360, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val } );
247
248 rgb_led led;
249 for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
250 led = g_rgb_leds[i];
251 if ( led.matrix_co.raw < 0xFF ) {
252 if ( led.modifier )
253 {
254 rgb_matrix_set_color( i, rgb2.r, rgb2.g, rgb2.b );
255 }
256 else
257 {
258 rgb_matrix_set_color( i, rgb1.r, rgb1.g, rgb1.b );
259 }
260 }
261 }
262}
263
264void rgb_matrix_gradient_up_down(void) {
265 int16_t h1 = rgb_matrix_config.hue;
266 int16_t h2 = (rgb_matrix_config.hue + 180) % 360;
267 int16_t deltaH = h2 - h1;
268
269 // Take the shortest path between hues
270 if ( deltaH > 127 )
271 {
272 deltaH -= 256;
273 }
274 else if ( deltaH < -127 )
275 {
276 deltaH += 256;
277 }
278 // Divide delta by 4, this gives the delta per row
279 deltaH /= 4;
280
281 int16_t s1 = rgb_matrix_config.sat;
282 int16_t s2 = rgb_matrix_config.hue;
283 int16_t deltaS = ( s2 - s1 ) / 4;
284
285 HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
286 RGB rgb;
287 Point point;
288 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
289 {
290 // map_led_to_point( i, &point );
291 point = g_rgb_leds[i].point;
292 // The y range will be 0..64, map this to 0..4
293 uint8_t y = (point.y>>4);
294 // Relies on hue being 8-bit and wrapping
295 hsv.h = rgb_matrix_config.hue + ( deltaH * y );
296 hsv.s = rgb_matrix_config.sat + ( deltaS * y );
297 rgb = hsv_to_rgb( hsv );
298 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
299 }
300}
301
302void rgb_matrix_raindrops(bool initialize) {
303 int16_t h1 = rgb_matrix_config.hue;
304 int16_t h2 = (rgb_matrix_config.hue + 180) % 360;
305 int16_t deltaH = h2 - h1;
306 deltaH /= 4;
307
308 // Take the shortest path between hues
309 if ( deltaH > 127 )
310 {
311 deltaH -= 256;
312 }
313 else if ( deltaH < -127 )
314 {
315 deltaH += 256;
316 }
317
318 int16_t s1 = rgb_matrix_config.sat;
319 int16_t s2 = rgb_matrix_config.sat;
320 int16_t deltaS = ( s2 - s1 ) / 4;
321
322 HSV hsv;
323 RGB rgb;
324
325 // Change one LED every tick
326 uint8_t led_to_change = ( g_tick & 0x000 ) == 0 ? rand() % DRIVER_LED_TOTAL : 255;
327
328 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
329 {
330 // If initialize, all get set to random colors
331 // If not, all but one will stay the same as before.
332 if ( initialize || i == led_to_change )
333 {
334 hsv.h = h1 + ( deltaH * ( rand() & 0x03 ) );
335 hsv.s = s1 + ( deltaS * ( rand() & 0x03 ) );
336 // Override brightness with global brightness control
337 hsv.v = rgb_matrix_config.val;
338
339 rgb = hsv_to_rgb( hsv );
340 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
341 }
342 }
343}
344
345void rgb_matrix_cycle_all(void) {
346 uint8_t offset = g_tick & 0xFF;
347
348 rgb_led led;
349
350 // Relies on hue being 8-bit and wrapping
351 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
352 {
353 // map_index_to_led(i, &led);
354 led = g_rgb_leds[i];
355 if (led.matrix_co.raw < 0xFF) {
356 uint16_t offset2 = g_key_hit[i]<<2;
357 offset2 = (offset2<=63) ? (63-offset2) : 0;
358
359 HSV hsv = { .h = offset+offset2, .s = 255, .v = rgb_matrix_config.val };
360 RGB rgb = hsv_to_rgb( hsv );
361 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
362 }
363 }
364}
365
366void rgb_matrix_cycle_left_right(void) {
367 uint8_t offset = g_tick & 0xFF;
368 HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
369 RGB rgb;
370 Point point;
371 rgb_led led;
372 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
373 {
374 // map_index_to_led(i, &led);
375 led = g_rgb_leds[i];
376 if (led.matrix_co.raw < 0xFF) {
377 uint16_t offset2 = g_key_hit[i]<<2;
378 offset2 = (offset2<=63) ? (63-offset2) : 0;
379
380 // map_led_to_point( i, &point );
381 point = g_rgb_leds[i].point;
382 // Relies on hue being 8-bit and wrapping
383 hsv.h = point.x + offset + offset2;
384 rgb = hsv_to_rgb( hsv );
385 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
386 }
387 }
388}
389
390void rgb_matrix_cycle_up_down(void) {
391 uint8_t offset = g_tick & 0xFF;
392 HSV hsv = { .h = 0, .s = 255, .v = rgb_matrix_config.val };
393 RGB rgb;
394 Point point;
395 rgb_led led;
396 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
397 {
398 // map_index_to_led(i, &led);
399 led = g_rgb_leds[i];
400 if (led.matrix_co.raw < 0xFF) {
401 uint16_t offset2 = g_key_hit[i]<<2;
402 offset2 = (offset2<=63) ? (63-offset2) : 0;
403
404 // map_led_to_point( i, &point );
405 point = g_rgb_leds[i].point;
406 // Relies on hue being 8-bit and wrapping
407 hsv.h = point.y + offset + offset2;
408 rgb = hsv_to_rgb( hsv );
409 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
410 }
411 }
412}
413
414
415void rgb_matrix_dual_beacon(void) {
416 HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
417 RGB rgb;
418 rgb_led led;
419 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
420 led = g_rgb_leds[i];
421 hsv.h = ((led.point.y - 32.0)* cos(g_tick * PI / 128) / 32 + (led.point.x - 112.0) * sin(g_tick * PI / 128) / (112)) * (180) + rgb_matrix_config.hue;
422 rgb = hsv_to_rgb( hsv );
423 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
424 }
425}
426
427void rgb_matrix_rainbow_beacon(void) {
428 HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
429 RGB rgb;
430 rgb_led led;
431 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
432 led = g_rgb_leds[i];
433 hsv.h = 1.5 * (led.point.y - 32.0)* cos(g_tick * PI / 128) + 1.5 * (led.point.x - 112.0) * sin(g_tick * PI / 128) + rgb_matrix_config.hue;
434 rgb = hsv_to_rgb( hsv );
435 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
436 }
437}
438
439void rgb_matrix_rainbow_pinwheels(void) {
440 HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
441 RGB rgb;
442 rgb_led led;
443 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
444 led = g_rgb_leds[i];
445 hsv.h = 2 * (led.point.y - 32.0)* cos(g_tick * PI / 128) + 2 * (66 - abs(led.point.x - 112.0)) * sin(g_tick * PI / 128) + rgb_matrix_config.hue;
446 rgb = hsv_to_rgb( hsv );
447 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
448 }
449}
450
451void rgb_matrix_rainbow_moving_chevron(void) {
452 HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
453 RGB rgb;
454 rgb_led led;
455 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
456 led = g_rgb_leds[i];
457 // uint8_t r = g_tick;
458 uint8_t r = 32;
459 hsv.h = 1.5 * abs(led.point.y - 32.0)* sin(r * PI / 128) + 1.5 * (led.point.x - (g_tick / 256.0 * 224)) * cos(r * PI / 128) + rgb_matrix_config.hue;
460 rgb = hsv_to_rgb( hsv );
461 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
462 }
463}
464
465
466void rgb_matrix_jellybean_raindrops( bool initialize ) {
467 HSV hsv;
468 RGB rgb;
469
470 // Change one LED every tick
471 uint8_t led_to_change = ( g_tick & 0x000 ) == 0 ? rand() % DRIVER_LED_TOTAL : 255;
472
473 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
474 {
475 // If initialize, all get set to random colors
476 // If not, all but one will stay the same as before.
477 if ( initialize || i == led_to_change )
478 {
479 hsv.h = rand() & 0xFF;
480 hsv.s = rand() & 0xFF;
481 // Override brightness with global brightness control
482 hsv.v = rgb_matrix_config.val;
483
484 rgb = hsv_to_rgb( hsv );
485 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
486 }
487 }
488}
489
490void rgb_matrix_multisplash(void) {
491 // if (g_any_key_hit < 0xFF) {
492 HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
493 RGB rgb;
494 rgb_led led;
495 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
496 led = g_rgb_leds[i];
497 uint16_t c = 0, d = 0;
498 rgb_led last_led;
499 // if (g_last_led_count) {
500 for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
501 last_led = g_rgb_leds[g_last_led_hit[last_i]];
502 uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
503 uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
504 c += MIN(MAX(effect, 0), 255);
505 d += 255 - MIN(MAX(effect, 0), 255);
506 }
507 // } else {
508 // d = 255;
509 // }
510 hsv.h = (rgb_matrix_config.hue + c) % 256;
511 hsv.v = MAX(MIN(d, 255), 0);
512 rgb = hsv_to_rgb( hsv );
513 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
514 }
515 // } else {
516 // rgb_matrix_set_color_all( 0, 0, 0 );
517 // }
518}
519
520
521void rgb_matrix_splash(void) {
522 g_last_led_count = MIN(g_last_led_count, 1);
523 rgb_matrix_multisplash();
524}
525
526
527void rgb_matrix_solid_multisplash(void) {
528 // if (g_any_key_hit < 0xFF) {
529 HSV hsv = { .h = rgb_matrix_config.hue, .s = rgb_matrix_config.sat, .v = rgb_matrix_config.val };
530 RGB rgb;
531 rgb_led led;
532 for (uint8_t i = 0; i < DRIVER_LED_TOTAL; i++) {
533 led = g_rgb_leds[i];
534 uint16_t d = 0;
535 rgb_led last_led;
536 // if (g_last_led_count) {
537 for (uint8_t last_i = 0; last_i < g_last_led_count; last_i++) {
538 last_led = g_rgb_leds[g_last_led_hit[last_i]];
539 uint16_t dist = (uint16_t)sqrt(pow(led.point.x - last_led.point.x, 2) + pow(led.point.y - last_led.point.y, 2));
540 uint16_t effect = (g_key_hit[g_last_led_hit[last_i]] << 2) - dist;
541 d += 255 - MIN(MAX(effect, 0), 255);
542 }
543 // } else {
544 // d = 255;
545 // }
546 hsv.v = MAX(MIN(d, 255), 0);
547 rgb = hsv_to_rgb( hsv );
548 rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
549 }
550 // } else {
551 // rgb_matrix_set_color_all( 0, 0, 0 );
552 // }
553}
554
555
556void rgb_matrix_solid_splash(void) {
557 g_last_led_count = MIN(g_last_led_count, 1);
558 rgb_matrix_solid_multisplash();
559}
560
561
562// Needs eeprom access that we don't have setup currently
563
564void rgb_matrix_custom(void) {
565// HSV hsv;
566// RGB rgb;
567// for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
568// {
569// backlight_get_key_color(i, &hsv);
570// // Override brightness with global brightness control
571// hsv.v = rgb_matrix_config.val;
572// rgb = hsv_to_rgb( hsv );
573// rgb_matrix_set_color( i, rgb.r, rgb.g, rgb.b );
574// }
575}
576
577void rgb_matrix_task(void) {
578 if (!rgb_matrix_config.enable) {
579 rgb_matrix_all_off();
580 return;
581 }
582 // delay 1 second before driving LEDs or doing anything else
583 static uint8_t startup_tick = 0;
584 if ( startup_tick < 20 ) {
585 startup_tick++;
586 return;
587 }
588
589 g_tick++;
590
591 if ( g_any_key_hit < 0xFFFFFFFF ) {
592 g_any_key_hit++;
593 }
594
595 for ( int led = 0; led < DRIVER_LED_TOTAL; led++ ) {
596 if ( g_key_hit[led] < 255 ) {
597 if (g_key_hit[led] == 254)
598 g_last_led_count = MAX(g_last_led_count - 1, 0);
599 g_key_hit[led]++;
600 }
601 }
602
603 // Factory default magic value
604 if ( rgb_matrix_config.mode == 255 ) {
605 rgb_matrix_test();
606 return;
607 }
608
609 // Ideally we would also stop sending zeros to the LED driver PWM buffers
610 // while suspended and just do a software shutdown. This is a cheap hack for now.
611 bool suspend_backlight = ((g_suspend_state && RGB_DISABLE_WHEN_USB_SUSPENDED) ||
612 (RGB_DISABLE_AFTER_TIMEOUT > 0 && g_any_key_hit > RGB_DISABLE_AFTER_TIMEOUT * 60 * 20));
613 uint8_t effect = suspend_backlight ? 0 : rgb_matrix_config.mode;
614
615 // Keep track of the effect used last time,
616 // detect change in effect, so each effect can
617 // have an optional initialization.
618 static uint8_t effect_last = 255;
619 bool initialize = effect != effect_last;
620 effect_last = effect;
621
622 // this gets ticked at 20 Hz.
623 // each effect can opt to do calculations
624 // and/or request PWM buffer updates.
625 switch ( effect ) {
626 case RGB_MATRIX_SOLID_COLOR:
627 rgb_matrix_solid_color();
628 break;
629 case RGB_MATRIX_SOLID_REACTIVE:
630 rgb_matrix_solid_reactive();
631 break;
632 case RGB_MATRIX_ALPHAS_MODS:
633 rgb_matrix_alphas_mods();
634 break;
635 case RGB_MATRIX_DUAL_BEACON:
636 rgb_matrix_dual_beacon();
637 break;
638 case RGB_MATRIX_GRADIENT_UP_DOWN:
639 rgb_matrix_gradient_up_down();
640 break;
641 case RGB_MATRIX_RAINDROPS:
642 rgb_matrix_raindrops( initialize );
643 break;
644 case RGB_MATRIX_CYCLE_ALL:
645 rgb_matrix_cycle_all();
646 break;
647 case RGB_MATRIX_CYCLE_LEFT_RIGHT:
648 rgb_matrix_cycle_left_right();
649 break;
650 case RGB_MATRIX_CYCLE_UP_DOWN:
651 rgb_matrix_cycle_up_down();
652 break;
653 case RGB_MATRIX_RAINBOW_BEACON:
654 rgb_matrix_rainbow_beacon();
655 break;
656 case RGB_MATRIX_RAINBOW_PINWHEELS:
657 rgb_matrix_rainbow_pinwheels();
658 break;
659 case RGB_MATRIX_RAINBOW_MOVING_CHEVRON:
660 rgb_matrix_rainbow_moving_chevron();
661 break;
662 case RGB_MATRIX_JELLYBEAN_RAINDROPS:
663 rgb_matrix_jellybean_raindrops( initialize );
664 break;
665 #ifdef RGB_MATRIX_KEYPRESSES
666 case RGB_MATRIX_SPLASH:
667 rgb_matrix_splash();
668 break;
669 case RGB_MATRIX_MULTISPLASH:
670 rgb_matrix_multisplash();
671 break;
672 case RGB_MATRIX_SOLID_SPLASH:
673 rgb_matrix_solid_splash();
674 break;
675 case RGB_MATRIX_SOLID_MULTISPLASH:
676 rgb_matrix_solid_multisplash();
677 break;
678 #endif
679 default:
680 rgb_matrix_custom();
681 break;
682 }
683
684 if ( ! suspend_backlight ) {
685 rgb_matrix_indicators();
686 }
687
688}
689
690void rgb_matrix_indicators(void) {
691 rgb_matrix_indicators_kb();
692 rgb_matrix_indicators_user();
693}
694
695__attribute__((weak))
696void rgb_matrix_indicators_kb(void) {}
697
698__attribute__((weak))
699void rgb_matrix_indicators_user(void) {}
700
701
702// void rgb_matrix_set_indicator_index( uint8_t *index, uint8_t row, uint8_t column )
703// {
704// if ( row >= MATRIX_ROWS )
705// {
706// // Special value, 255=none, 254=all
707// *index = row;
708// }
709// else
710// {
711// // This needs updated to something like
712// // uint8_t led[8], led_count;
713// // map_row_column_to_led(row,column,led,&led_count);
714// // for(uint8_t i = 0; i < led_count; i++)
715// map_row_column_to_led( row, column, index );
716// }
717// }
718
719void rgb_matrix_init_drivers(void) {
720 //sei();
721
722 // Initialize TWI
723 TWIInit();
724 IS31FL3731_init( DRIVER_ADDR_1 );
725 IS31FL3731_init( DRIVER_ADDR_2 );
726
727 for ( int index = 0; index < DRIVER_LED_TOTAL; index++ ) {
728 bool enabled = true;
729 // This only caches it for later
730 IS31FL3731_set_led_control_register( index, enabled, enabled, enabled );
731 }
732 // This actually updates the LED drivers
733 IS31FL3731_update_led_control_registers( DRIVER_ADDR_1, DRIVER_ADDR_2 );
734
735 // TODO: put the 1 second startup delay here?
736
737 // clear the key hits
738 for ( int led=0; led<DRIVER_LED_TOTAL; led++ ) {
739 g_key_hit[led] = 255;
740 }
741
742
743 if (!eeconfig_is_enabled()) {
744 dprintf("rgb_matrix_init_drivers eeconfig is not enabled.\n");
745 eeconfig_init();
746 eeconfig_update_rgb_matrix_default();
747 }
748 rgb_matrix_config.raw = eeconfig_read_rgb_matrix();
749 if (!rgb_matrix_config.mode) {
750 dprintf("rgb_matrix_init_drivers rgb_matrix_config.mode = 0. Write default values to EEPROM.\n");
751 eeconfig_update_rgb_matrix_default();
752 rgb_matrix_config.raw = eeconfig_read_rgb_matrix();
753 }
754 eeconfig_debug_rgb_matrix(); // display current eeprom values
755}
756
757// Deals with the messy details of incrementing an integer
758uint8_t increment( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
759 int16_t new_value = value;
760 new_value += step;
761 return MIN( MAX( new_value, min ), max );
762}
763
764uint8_t decrement( uint8_t value, uint8_t step, uint8_t min, uint8_t max ) {
765 int16_t new_value = value;
766 new_value -= step;
767 return MIN( MAX( new_value, min ), max );
768}
769
770// void *backlight_get_custom_key_color_eeprom_address( uint8_t led )
771// {
772// // 3 bytes per color
773// return EECONFIG_RGB_MATRIX + ( led * 3 );
774// }
775
776// void backlight_get_key_color( uint8_t led, HSV *hsv )
777// {
778// void *address = backlight_get_custom_key_color_eeprom_address( led );
779// hsv->h = eeprom_read_byte(address);
780// hsv->s = eeprom_read_byte(address+1);
781// hsv->v = eeprom_read_byte(address+2);
782// }
783
784// void backlight_set_key_color( uint8_t row, uint8_t column, HSV hsv )
785// {
786// uint8_t led[8], led_count;
787// map_row_column_to_led(row,column,led,&led_count);
788// for(uint8_t i = 0; i < led_count; i++) {
789// if ( led[i] < DRIVER_LED_TOTAL )
790// {
791// void *address = backlight_get_custom_key_color_eeprom_address(led[i]);
792// eeprom_update_byte(address, hsv.h);
793// eeprom_update_byte(address+1, hsv.s);
794// eeprom_update_byte(address+2, hsv.v);
795// }
796// }
797// }
798
799void rgb_matrix_test_led( uint8_t index, bool red, bool green, bool blue ) {
800 for ( int i=0; i<DRIVER_LED_TOTAL; i++ )
801 {
802 if ( i == index )
803 {
804 IS31FL3731_set_led_control_register( i, red, green, blue );
805 }
806 else
807 {
808 IS31FL3731_set_led_control_register( i, false, false, false );
809 }
810 }
811}
812
813uint32_t rgb_matrix_get_tick(void) {
814 return g_tick;
815}
816
817void rgblight_toggle(void) {
818 rgb_matrix_config.enable ^= 1;
819 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
820}
821
822void rgblight_step(void) {
823 rgb_matrix_config.mode++;
824 if (rgb_matrix_config.mode >= RGB_MATRIX_EFFECT_MAX)
825 rgb_matrix_config.mode = 1;
826 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
827}
828
829void rgblight_step_reverse(void) {
830 rgb_matrix_config.mode--;
831 if (rgb_matrix_config.mode <= 1)
832 rgb_matrix_config.mode = (RGB_MATRIX_EFFECT_MAX - 1);
833 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
834}
835
836void rgblight_increase_hue(void) {
837 rgb_matrix_config.hue = increment( rgb_matrix_config.hue, 8, 0, 255 );
838 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
839}
840
841void rgblight_decrease_hue(void) {
842 rgb_matrix_config.hue = decrement( rgb_matrix_config.hue, 8, 0, 255 );
843 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
844}
845
846void rgblight_increase_sat(void) {
847 rgb_matrix_config.sat = increment( rgb_matrix_config.sat, 8, 0, 255 );
848 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
849}
850
851void rgblight_decrease_sat(void) {
852 rgb_matrix_config.sat = decrement( rgb_matrix_config.sat, 8, 0, 255 );
853 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
854}
855
856void rgblight_increase_val(void) {
857 rgb_matrix_config.val = increment( rgb_matrix_config.val, 8, 0, 255 );
858 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
859}
860
861void rgblight_decrease_val(void) {
862 rgb_matrix_config.val = decrement( rgb_matrix_config.val, 8, 0, 255 );
863 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
864}
865
866void rgblight_mode(uint8_t mode) {
867 rgb_matrix_config.mode = mode;
868 eeconfig_update_rgb_matrix(rgb_matrix_config.raw);
869}
870
871uint32_t rgblight_get_mode(void) {
872 return rgb_matrix_config.mode;
873}
diff --git a/quantum/rgb_matrix.h b/quantum/rgb_matrix.h
new file mode 100644
index 000000000..ef93c6d5c
--- /dev/null
+++ b/quantum/rgb_matrix.h
@@ -0,0 +1,135 @@
1/* Copyright 2017 Jason Williams
2 * Copyright 2017 Jack Humbert
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef RGB_MATRIX_H
19#define RGB_MATRIX_H
20
21#include <stdint.h>
22#include <stdbool.h>
23#include "color.h"
24#include "is31fl3731.h"
25#include "quantum.h"
26
27typedef struct Point {
28 uint8_t x;
29 uint8_t y;
30} __attribute__((packed)) Point;
31
32typedef struct rgb_led {
33 union {
34 uint8_t raw;
35 struct {
36 uint8_t row:4; // 16 max
37 uint8_t col:4; // 16 max
38 };
39 } matrix_co;
40 Point point;
41 uint8_t modifier:1;
42} __attribute__((packed)) rgb_led;
43
44
45extern const rgb_led g_rgb_leds[DRIVER_LED_TOTAL];
46
47typedef struct
48{
49 HSV color;
50 uint8_t index;
51} rgb_indicator;
52
53typedef union {
54 uint32_t raw;
55 struct {
56 bool enable :1;
57 uint8_t mode :6;
58 uint16_t hue :9;
59 uint8_t sat :8;
60 uint8_t val :8;
61 };
62} rgb_config_t;
63
64enum rgb_matrix_effects {
65 RGB_MATRIX_SOLID_COLOR = 1,
66 RGB_MATRIX_SOLID_REACTIVE,
67 RGB_MATRIX_ALPHAS_MODS,
68 RGB_MATRIX_DUAL_BEACON,
69 RGB_MATRIX_GRADIENT_UP_DOWN,
70 RGB_MATRIX_RAINDROPS,
71 RGB_MATRIX_CYCLE_ALL,
72 RGB_MATRIX_CYCLE_LEFT_RIGHT,
73 RGB_MATRIX_CYCLE_UP_DOWN,
74 RGB_MATRIX_RAINBOW_BEACON,
75 RGB_MATRIX_RAINBOW_PINWHEELS,
76 RGB_MATRIX_RAINBOW_MOVING_CHEVRON,
77 RGB_MATRIX_JELLYBEAN_RAINDROPS,
78#ifdef RGB_MATRIX_KEYPRESSES
79 RGB_MATRIX_SPLASH,
80 RGB_MATRIX_MULTISPLASH,
81 RGB_MATRIX_SOLID_SPLASH,
82 RGB_MATRIX_SOLID_MULTISPLASH,
83#endif
84 RGB_MATRIX_EFFECT_MAX
85};
86
87void rgb_matrix_set_color( int index, uint8_t red, uint8_t green, uint8_t blue );
88
89// This runs after another backlight effect and replaces
90// colors already set
91void rgb_matrix_indicators(void);
92void rgb_matrix_indicators_kb(void);
93void rgb_matrix_indicators_user(void);
94
95void rgb_matrix_single_LED_test(void);
96
97void rgb_matrix_init_drivers(void);
98
99void rgb_matrix_set_suspend_state(bool state);
100void rgb_matrix_set_indicator_state(uint8_t state);
101
102
103void rgb_matrix_task(void);
104
105// This should not be called from an interrupt
106// (eg. from a timer interrupt).
107// Call this while idle (in between matrix scans).
108// If the buffer is dirty, it will update the driver with the buffer.
109void rgb_matrix_update_pwm_buffers(void);
110
111bool process_rgb_matrix(uint16_t keycode, keyrecord_t *record);
112
113void rgb_matrix_increase(void);
114void rgb_matrix_decrease(void);
115
116// void *backlight_get_key_color_eeprom_address(uint8_t led);
117// void backlight_get_key_color( uint8_t led, HSV *hsv );
118// void backlight_set_key_color( uint8_t row, uint8_t column, HSV hsv );
119
120void rgb_matrix_test_led( uint8_t index, bool red, bool green, bool blue );
121uint32_t rgb_matrix_get_tick(void);
122
123void rgblight_toggle(void);
124void rgblight_step(void);
125void rgblight_step_reverse(void);
126void rgblight_increase_hue(void);
127void rgblight_decrease_hue(void);
128void rgblight_increase_sat(void);
129void rgblight_decrease_sat(void);
130void rgblight_increase_val(void);
131void rgblight_decrease_val(void);
132void rgblight_mode(uint8_t mode);
133uint32_t rgblight_get_mode(void);
134
135#endif