]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/infinity60/led_controller.c
CLeaned out debug code
[qmk_firmware.git] / keyboards / infinity60 / led_controller.c
1 /*
2 Copyright 2016 flabbergast <s3+flabbergast@sdfeu.org>
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  * LED controller code
20  * IS31FL3731C matrix LED driver from ISSI
21  * datasheet: http://www.issi.com/WW/pdf/31FL3731C.pdf
22  */
23
24 #include "ch.h"
25 #include "hal.h"
26 #include "print.h"
27 #include "led.h"
28 #include "action_layer.h"
29 #include "host.h"
30
31 #include "led_controller.h"
32
33 #include "suspend.h"
34
35 #include "usb_main.h"
36
37 /* Infinity60 LED MAP
38     - digits mean "row" and "col", i.e. 45 means C4-5 in the IS31 datasheet, matrix A
39
40   11 12 13 14 15 16 17 18 21 22 23 24 25  26 27*
41    28 31 32 33 34 35 36 37 38 41 42 43 44 45
42    46 47 48 51 52 53 54 55 56 57 58 61    62
43     63 64 65 66 67 68 71 72 73 74 75      76 77*
44   78  81  82       83         84  85  86  87
45
46 *Unused in Alphabet Layout
47 */
48
49 /*
50   each page has 0xB4 bytes
51   0 - 0x11: LED control (on/off):
52     order: CA1, CB1, CA2, CB2, .... (CA - matrix A, CB - matrix B)
53       CAn controls Cn-8 .. Cn-1 (LSbit)
54   0x12 - 0x23: blink control (like "LED control")
55   0x24 - 0xB3: PWM control: byte per LED, 0xFF max on
56     order same as above (CA 1st row (8bytes), CB 1st row (8bytes), ...)
57 */
58
59 // Which LED should be used for CAPS LOCK indicator
60 #if !defined(CAPS_LOCK_LED_ADDRESS)
61 #define CAPS_LOCK_LED_ADDRESS 46
62 #endif
63
64 #if !defined(NUM_LOCK_LED_ADDRESS)
65 #define NUM_LOCK_LED_ADDRESS 85
66 #endif
67
68 /* Which LED should breathe during sleep */
69 #if !defined(BREATHE_LED_ADDRESS)
70 #define BREATHE_LED_ADDRESS CAPS_LOCK_LED_ADDRESS
71 #endif
72
73 /* =================
74  * ChibiOS I2C setup
75  * ================= */
76 static const I2CConfig i2ccfg = {
77   400000 // clock speed (Hz); 400kHz max for IS31
78 };
79
80 /* ==============
81  *   variables
82  * ============== */
83 // internal communication buffers
84 uint8_t tx[2] __attribute__((aligned(2)));
85 uint8_t rx[1] __attribute__((aligned(2)));
86
87 // buffer for sending the whole page at once (used also as a temp buffer)
88 uint8_t full_page[0xB4+1] = {0};
89
90 // LED mask (which LEDs are present, selected by bits)
91 // IC60 pcb uses only CA matrix.
92 // Each byte is a control pin for 8 leds ordered 8-1
93 const uint8_t all_on_leds_mask[0x12] = {
94   0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
95   0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x00
96 };
97
98 // array to hold brightness pwm steps
99 const uint8_t pwm_levels[5] = {
100     0x00, 0x16, 0x4E, 0xA1, 0xFF
101 };
102
103 // array to write to pwm register
104 uint8_t pwm_register_array[9] = {0};
105
106
107 /* ============================
108  *   communication functions
109  * ============================ */
110 msg_t is31_select_page(uint8_t page) {
111   tx[0] = IS31_COMMANDREGISTER;
112   tx[1] = page;
113   return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, US2ST(IS31_TIMEOUT));
114 }
115
116 msg_t is31_write_data(uint8_t page, uint8_t *buffer, uint8_t size) {
117   is31_select_page(page);
118   return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, buffer, size, NULL, 0, US2ST(IS31_TIMEOUT));
119 }
120
121 msg_t is31_write_register(uint8_t page, uint8_t reg, uint8_t data) {
122   is31_select_page(page);
123   tx[0] = reg;
124   tx[1] = data;
125   return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, US2ST(IS31_TIMEOUT));
126 }
127
128 msg_t is31_read_register(uint8_t page, uint8_t reg, uint8_t *result) {
129   is31_select_page(page);
130
131   tx[0] = reg;
132   return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 1, result, 1, US2ST(IS31_TIMEOUT));
133 }
134
135 /* ========================
136  * initialise the IS31 chip
137  * ======================== */
138 void is31_init(void) {
139   // just to be sure that it's all zeroes
140   __builtin_memset(full_page,0,0xB4+1);
141   // zero function page, all registers (assuming full_page is all zeroes)
142   is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1);
143   palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL);
144   palSetPad(GPIOB, 16);
145   chThdSleepMilliseconds(10);
146   // software shutdown
147   is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, 0);
148   chThdSleepMilliseconds(10);
149   // software shutdown disable (i.e. turn stuff on)
150   is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
151   chThdSleepMilliseconds(10);
152   // zero all LED registers on all 8 pages
153   uint8_t i;
154   for(i=0; i<8; i++) {
155     is31_write_data(i, full_page, 0xB4 + 1);
156     chThdSleepMilliseconds(1);
157   }
158 }
159
160 /* ==================
161  * LED control thread
162  * ================== */
163 #define LED_MAILBOX_NUM_MSGS 5
164 static msg_t led_mailbox_queue[LED_MAILBOX_NUM_MSGS];
165 mailbox_t led_mailbox;
166 static THD_WORKING_AREA(waLEDthread, 256);
167 static THD_FUNCTION(LEDthread, arg) {
168   (void)arg;
169   chRegSetThreadName("LEDthread");
170
171   uint8_t i;
172   uint8_t control_register_word[2] = {0};//2 bytes: register address, byte to write
173   uint8_t led_control_reg[0x13] = {0};//led control register start address + 0x12 bytes
174
175   //persistent status variables
176   uint8_t pwm_step_status, page_status;
177
178   //mailbox variables
179   uint8_t temp, msg_type, msg_pin, msg_col, msg_led;
180   msg_t msg;
181
182 // initialize persistent variables
183 pwm_step_status = 4; //full brightness
184 page_status = 0; //start frame 0 (all off/on)
185
186   while(true) {
187     // wait for a message (asynchronous)
188     // (messages are queued (up to LED_MAILBOX_NUM_MSGS) if they can't
189     //  be processed right away)
190     chMBFetch(&led_mailbox, &msg, TIME_INFINITE);
191     msg_col = (msg >> 24) & 0xFF;//if needed
192     msg_pin = (msg >> 16) & 0XFF;//if needed (e.g. SET_FULL_ROW)
193     msg_type = (msg >> 8) & 0xFF; //second byte is msg type
194     msg_led = (msg) & 0xFF; //first byte is action information
195
196     switch (msg_type){
197       case SET_FULL_ROW:
198       //write full byte to pin address, msg_pin = pin #, msg_led = byte to write
199       //writes only to current page
200         write_led_byte(page_status,msg_pin,msg_led);
201       break;
202
203       case OFF_LED:      
204       //on/off/toggle single led, msg_led = row/col of led
205         set_led_bit(7, control_register_word, msg_led, 0);
206         is31_write_data (7, control_register_word, 0x02);
207         break;
208       case ON_LED:      
209         set_led_bit(7, control_register_word, msg_led, 1);
210         is31_write_data (7, control_register_word, 0x02);
211         break;
212       case TOGGLE_LED:      
213         set_led_bit(7, control_register_word, msg_led, 2);
214         is31_write_data (7, control_register_word, 0x02);
215         break;
216
217       case BLINK_OFF_LED:      
218       //on/off/toggle single led, msg_led = row/col of led
219         set_led_bit(7, control_register_word, msg_led, 4);
220         is31_write_data (7, control_register_word, 0x02);
221         break;
222       case BLINK_ON_LED:      
223         set_led_bit(7, control_register_word, msg_led, 5);
224         is31_write_data (7, control_register_word, 0x02);
225         break;
226       case BLINK_TOGGLE_LED:      
227         set_led_bit(7, control_register_word, msg_led, 6);
228         is31_write_data (7, control_register_word, 0x02);
229         break;
230
231       case TOGGLE_ALL:
232         //msg_led = unused
233         is31_read_register(0, 0x00, &temp);
234         led_control_reg[0] = 0;
235
236         //if first byte is on, then toggle frame 0 off
237         if (temp==0 || page_status > 0) {
238           __builtin_memcpy(led_control_reg+1, all_on_leds_mask, 0x12);
239         } else {
240           __builtin_memset(led_control_reg+1, 0, 0x12);
241         }
242         is31_write_data(0, led_control_reg, 0x13);
243
244         if (page_status > 0) {
245           is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 0);
246
247           page_status=0;
248
249           //maintain lock leds
250           led_set(host_keyboard_leds());
251         }
252         break;
253
254       case TOGGLE_BACKLIGHT:
255         //msg_led = on/off
256
257         //populate the 9 byte rows to be written to each pin, first byte is register (pin) address
258         if (msg_led == 1) {
259           __builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8);
260         } else {
261           __builtin_memset(pwm_register_array+1, 0, 8);
262         }
263
264         for(i=0; i<8; i++) {
265         //first byte is register address, every 0x10 9 bytes is A-register pwm pins
266           pwm_register_array[0] = 0x24 + (i * 0x10);
267           is31_write_data(0,pwm_register_array,9);
268         }
269         break;
270
271       case DISPLAY_PAGE:
272       //msg_led = page to toggle on
273         if (page_status != msg_led) {
274           is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, msg_led);
275           page_status = msg_led;
276
277           //maintain lock leds
278           led_set(host_keyboard_leds());
279         }
280         break;
281
282       case RESET_PAGE:
283       //led_msg = page to reset
284         led_control_reg[0] = 0;
285         __builtin_memset(led_control_reg+1, 0, 0x12);
286         is31_write_data(msg_led, led_control_reg, 0x13);
287         break;
288         
289       case TOGGLE_NUM_LOCK:
290       //msg_led = 0 or 1, off/on
291         set_lock_leds(NUM_LOCK_LED_ADDRESS, msg_led, page_status);
292         break;
293       case TOGGLE_CAPS_LOCK:
294       //msg_led = 0 or 1, off/on
295         set_lock_leds(CAPS_LOCK_LED_ADDRESS, msg_led, page_status);
296         break;
297
298       case STEP_BRIGHTNESS:
299       //led_msg = step pwm up or down
300         switch (msg_led) {
301           case 0:
302             if (pwm_step_status == 0) {
303               pwm_step_status = 4;
304             } else {
305               pwm_step_status--;
306             }
307             break;
308           
309           case 1:
310             if (pwm_step_status == 4) {
311               pwm_step_status = 0;
312             } else {
313               pwm_step_status++;
314             }
315             break;
316         }
317
318         //populate 8 byte rows to write on each pin
319         //first byte is register address, every 0x10 9 bytes are A-register pwm pins
320         __builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8);
321
322         for(i=0; i<8; i++) {
323           pwm_register_array[0] = 0x24 + (i * 0x10);
324           is31_write_data(0,pwm_register_array,9);
325         }
326         break;
327     }
328   }
329 }
330
331 /* ==============================
332  *    led processing functions
333  * ============================== */
334
335 void set_led_bit (uint8_t page, uint8_t *led_control_reg, uint8_t led_addr, uint8_t action) {
336   //returns 2 bytes: led control register address and byte to write
337   //0 - bit off, 1 - bit on, 2 - toggle bit
338
339   uint8_t control_reg_addr, column_bit, column_byte, bit_temp, blink_on;
340
341   //check for valid led address
342   if (led_addr < 0 || led_addr > 87 || led_addr % 10 > 8) {
343     return;
344   }
345
346   //check for blink bit
347   blink_on = action>>2;
348   action &= ~(1<<2); //strip blink bit
349
350   //first byte is led control register address 0x00
351   //msg_led tens column is pin#, ones column is bit position in 8-bit mask
352   control_reg_addr = ((led_addr / 10) % 10 - 1 ) * 0x02;// A-register is every other byte
353   control_reg_addr += blink_on == 1 ? 0x12 : 0x00;//shift 12 bytes to blink register
354
355   is31_read_register(page, control_reg_addr, &bit_temp);//maintain status of leds on this byte
356   column_bit = 1<<(led_addr % 10 - 1);
357   column_byte = bit_temp;
358
359   switch(action) {
360     case 0:
361       column_byte &= ~column_bit;
362       break;
363     case 1:
364       column_byte |= column_bit;
365       break;
366     case 2:
367       column_byte ^= column_bit;
368       break;
369   }
370
371   //return word to be written in register
372   led_control_reg[0] = control_reg_addr;
373   led_control_reg[1] = column_byte;
374 }
375
376 void write_led_byte (uint8_t page, uint8_t row, uint8_t led_byte) {
377   uint8_t led_control_word[2] = {0};//register address and on/off byte
378
379   led_control_word[0] = (row - 1 ) * 0x02;// A-register is every other byte
380   led_control_word[1] = led_byte;
381   is31_write_data(page, led_control_word, 0x02);
382 }
383
384 void write_led_page (uint8_t page, uint8_t *user_led_array, uint8_t led_count) {
385   uint8_t i;
386   uint8_t pin, col;
387   uint8_t led_control_register[0x13] = {0};
388
389   __builtin_memset(led_control_register,0,13);
390
391   for(i=0;i<led_count;i++){
392     // 1 byte shift for led register 0x00 address
393     pin = ((user_led_array[i] / 10) % 10 - 1 ) * 2 + 1;
394     col = user_led_array[i] % 10 - 1;
395     led_control_register[pin] |= 1<<(col);
396   }
397
398   is31_write_data(page, led_control_register, 0x13);
399 }
400
401 void set_lock_leds(uint8_t led_addr, uint8_t led_action, uint8_t page) {
402   uint8_t lock_temp;
403   uint8_t led_control_word[2] = {0};
404
405   //blink if all leds are on
406   if (page == 0) {
407     is31_read_register(0, 0x00, &lock_temp);
408     if (lock_temp == 0xFF) {
409       led_action |= (1<<2); //set blink bit
410     }
411   }
412
413   set_led_bit(page,led_control_word,led_addr,led_action);
414   is31_write_data(page, led_control_word, 0x02);
415 }
416
417 /* =====================
418  * hook into user keymap
419  * ===================== */
420 void led_controller_init(void) {
421   uint8_t i;
422
423   /* initialise I2C */
424   /* I2C pins */
425   palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL
426   palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATIVE_2); // PTB1/I2C0/SDA
427   /* start I2C */
428   i2cStart(&I2CD1, &i2ccfg);
429   // try high drive (from kiibohd)
430   I2CD1.i2c->C2 |= I2Cx_C2_HDRS;
431   // try glitch fixing (from kiibohd)
432   I2CD1.i2c->FLT = 4;
433
434   chThdSleepMilliseconds(10);
435
436   /* initialise IS31 chip */
437   is31_init();
438
439   //set Display Option Register so all pwm intensity is controlled from page 0
440   //enable blink and set blink period to 0.27s x rate
441   is31_write_register(IS31_FUNCTIONREG, IS31_REG_DISPLAYOPT, IS31_REG_DISPLAYOPT_INTENSITY_SAME + IS31_REG_DISPLAYOPT_BLINK_ENABLE + 4);
442
443   /* set full pwm on page 1 */
444   pwm_register_array[0] = 0;
445   __builtin_memset(pwm_register_array+1, 0xFF, 8);
446   for(i=0; i<8; i++) {
447     pwm_register_array[0] = 0x24 + (i * 0x10);//first byte of 9 bytes must be register address
448     is31_write_data(0, pwm_register_array, 9);
449     chThdSleepMilliseconds(5);
450   }
451
452   /* enable breathing when the displayed page changes */
453   // Fade-in Fade-out, time = 26ms * 2^N, N=3
454   is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, (3<<4)|3);
455   is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, IS31_REG_BREATHCTRL2_ENABLE|3);
456
457   /* more time consuming LED processing should be offloaded into
458    * a thread, with asynchronous messaging. */
459   chMBObjectInit(&led_mailbox, led_mailbox_queue, LED_MAILBOX_NUM_MSGS);
460   chThdCreateStatic(waLEDthread, sizeof(waLEDthread), LOWPRIO, LEDthread, NULL);
461 }