1
0
Fork 0

Merge branch 'user_led_configuration' into infinity60

Conflicts:
	keyboards/infinity60/keymaps/jpetermans/keymap.c
This commit is contained in:
jpetermans 2017-05-24 12:07:18 -07:00
commit e6c9b07e1c
7 changed files with 600 additions and 621 deletions

View file

@ -1,385 +0,0 @@
flabbergast's TMK/ChibiOS port
==============================
2015/10/16
Build
-----
$ git clone -b chibios https://github.com/flabbergast/tmk_keyboard.git
$ cd tmk_keyboard
$ git submodule add -f -b kinetis https://github.com/flabbergast/ChibiOS.git tmk_core/tool/chibios/chibios
or
$ cd tmk_keyboard/tmk_core/tool/chibios
$ git clone -b kinetis https://github.com/flabbergast/ChibiOS.git tmk_core/tool/chibios/chibios
$ cd tmk_keyboard/keyboard/infinity_chibios
$ make
Chibios Configuration
---------------------
halconf.h: for HAL configuration
placed in project directory
read in chibios/os/hal/hal.mk
included in chibios/os/hal/include/hal.h
mcuconf.h: for MCU configuration
placed in project directory
included in halconf.h
Chibios Term
------------
PAL = Port Abstraction Layer
palWritePad
palReadPad
palSetPad
chibios/os/hal/include/pal.h
LLD = Low Level Driver
Makefile
--------
# <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
MCU_FAMILY = KINETIS
MCU_SERIES = KL2x
# - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
# or <this_dir>/ld/
MCU_LDSCRIPT = MKL26Z64
# - it should exist in <chibios>/os/common/ports/ARMCMx/compilers/GCC/mk/
MCU_STARTUP = kl2x
# Board: it should exist either in <chibios>/os/hal/boards/
# or <this_dir>/boards
BOARD = PJRC_TEENSY_LC
MCU = cortex-m0
# ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
ARMV = 6
halconf.h
---------
mcuconf.h
---------
chconf.h
--------
ld script
---------
--- ../../tmk_core/tool/chibios/chibios/os/common/ports/ARMCMx/compilers/GCC/ld/MKL26Z64.ld 2015-10-15 09:08:58.732904304 +0900
+++ ld/MKL26Z64.ld 2015-10-15 08:48:06.430215496 +0900
@@ -27,7 +27,8 @@
{
flash0 : org = 0x00000000, len = 0xc0
flashcfg : org = 0x00000400, len = 0x10
- flash : org = 0x00000410, len = 64k - 0x410
+ flash : org = 0x00000410, len = 62k - 0x410
+ eeprom_emu : org = 0x0000F800, len = 2k
ram : org = 0x1FFFF800, len = 8k
}
@@ -35,6 +36,10 @@
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
+__eeprom_workarea_start__ = ORIGIN(eeprom_emu);
+__eeprom_workarea_size__ = LENGTH(eeprom_emu);
+__eeprom_workarea_end__ = __eeprom_workarea_start__ + __eeprom_workarea_size__;
+
SECTIONS
{
. = 0;
Configuration/Startup for Infinity 60%
--------------------------------------
Configuration:
Clock:
Inifinity
FEI(FLL Engaged Internal) mode with core clock:48MHz, bus clock:48MHz, flash clock:24MHz
Clock dividor:
SIM_CLKDIV1[OUTDIV1] = 0 divide-by-1 for core clock
SIM_CLKDIV1[OUTDIV2] = 0 divide-by-1 for bus clock
SIM_CLKDIV1[OUTDIV4] = 1 divide-by-2 for flash clock
Internal reference clock:
MCG_C1[IREFS] = 1 Internal Reference Select for clock source for FLL
MCG_C1[IRCLKEN] = 1 Internal Reference Clock Enable
FLL multipilication:
MCG_C4[DMX32] = 1
MCG_C4[DRST_DRS] = 01 FLL factor 1464 * 32.768kHz = 48MHz
chibios/os/hal/ports/KINETIS/K20x/hal_lld.c
k20x_clock_init(): called in __early_init() defined in board.c
disable watchdog and configure clock
configurable macros:
KINETIS_NO_INIT: whether init or not
KINETIS_MCG_MODE: clock mode
KINETIS_MCG_MODE_FEI
KINETIS_MCG_MODE_PEE
hal/ports/KINETIS/K20x/hal_lld.h
chibios/os/hal/boards/FREESCALE_FREEDOM_K20D50M/board.h
PALConfig pal_default_config
boardInit()
__early_init()
macro definitions for board infos, freq and mcu type
chibios/os/hal/boards/FREESCALE_FREEDOM_K20D50M/board.c
USB
Startup
-------
common/ports/ARMCMx/GCC/crt0_v[67]m.s
Reset_Handler: startup code
common/ports/ARMCMx/GCC/crt1.c
__core_init(): weak
__early_init(): weak
__late_init(): weak
__default_exit(): weak
called from Reset_Handler of crt0
common/ports/ARMCMx/GCC/vector.c
common/ports/ARMCMx/GCC/ld/*.ld
chibios/os/common/ports/ARMCMx/compilers/GCC/
├── crt0_v6m.s
├── crt0_v7m.s
├── crt1.c
├── ld
│   ├── MK20DX128BLDR3.ld
│   ├── MK20DX128BLDR4.ld
│   ├── MK20DX128.ld
│   ├── MK20DX256.ld
│   ├── MKL25Z128.ld
│   ├── MKL26Z128.ld
│   ├── MKL26Z64.ld
│   └── STM32L476xG.ld
├── mk
│   ├── startup_k20x5.mk
│   ├── startup_k20x7.mk
│   ├── startup_k20x.mk
│   ├── startup_kl2x.mk
│   └── startup_stm32l4xx.mk
├── rules.ld
├── rules.mk
└── vectors.c
chibios/os/hal/
├── boards
│   ├── FREESCALE_FREEDOM_K20D50M
│   │   ├── board.c
│   │   ├── board.h
│   │   └── board.mk
│   ├── MCHCK_K20
│   │   ├── board.c
│   │   ├── board.h
│   │   └── board.mk
│   ├── PJRC_TEENSY_3
│   │   ├── board.c
│   │   ├── board.h
│   │   └── board.mk
│   ├── PJRC_TEENSY_3_1
│   │   ├── board.c
│   │   ├── board.h
│   │   └── board.mk
│   ├── PJRC_TEENSY_LC
│   │   ├── board.c
│   │   ├── board.h
│   │   └── board.mk
│   ├── readme.txt
│   ├── simulator
│   │   ├── board.c
│   │   ├── board.h
│   │   └── board.mk
│   ├── ST_NUCLEO_F030R8
│   │   ├── board.c
│   │   ├── board.h
│   │   ├── board.mk
│   │   └── cfg
│   │   └── board.chcfg
├── hal.mk
├── include
│   ├── adc.h
│   ├── can.h
│   ├── dac.h
│   ├── ext.h
│   ├── gpt.h
│   ├── hal_channels.h
│   ├── hal_files.h
│   ├── hal.h
│   ├── hal_ioblock.h
│   ├── hal_mmcsd.h
│   ├── hal_queues.h
│   ├── hal_streams.h
│   ├── i2c.h
│   ├── i2s.h
│   ├── icu.h
│   ├── mac.h
│   ├── mii.h
│   ├── mmc_spi.h
│   ├── pal.h
│   ├── pwm.h
│   ├── rtc.h
│   ├── sdc.h
│   ├── serial.h
│   ├── serial_usb.h
│   ├── spi.h
│   ├── st.h
│   ├── uart.h
│   └── usb.h
├── lib
│   └── streams
│   ├── chprintf.c
│   ├── chprintf.h
│   ├── memstreams.c
│   ├── memstreams.h
│   ├── nullstreams.c
│   └── nullstreams.h
├── osal
│   ├── nil
│   │   ├── osal.c
│   │   ├── osal.h
│   │   └── osal.mk
│   ├── os-less
│   │   └── ARMCMx
│   │   ├── osal.c
│   │   ├── osal.h
│   │   └── osal.mk
│   └── rt
│   ├── osal.c
│   ├── osal.h
│   └── osal.mk
├── ports
│   ├── AVR
│   ├── common
│   │   └── ARMCMx
│   │   ├── mpu.h
│   │   ├── nvic.c
│   │   └── nvic.h
│   ├── KINETIS
│   │   ├── K20x
│   │   │   ├── hal_lld.c
│   │   │   ├── hal_lld.h
│   │   │   ├── kinetis_registry.h
│   │   │   ├── platform.dox
│   │   │   ├── platform.mk
│   │   │   ├── pwm_lld.c
│   │   │   ├── pwm_lld.h
│   │   │   ├── spi_lld.c
│   │   │   └── spi_lld.h
│   │   ├── KL2x
│   │   │   ├── hal_lld.c
│   │   │   ├── hal_lld.h
│   │   │   ├── kinetis_registry.h
│   │   │   ├── platform.mk
│   │   │   ├── pwm_lld.c
│   │   │   └── pwm_lld.h
│   │   ├── LLD
│   │   │   ├── adc_lld.c
│   │   │   ├── adc_lld.h
│   │   │   ├── ext_lld.c
│   │   │   ├── ext_lld.h
│   │   │   ├── gpt_lld.c
│   │   │   ├── gpt_lld.h
│   │   │   ├── i2c_lld.c
│   │   │   ├── i2c_lld.h
│   │   │   ├── pal_lld.c
│   │   │   ├── pal_lld.h
│   │   │   ├── serial_lld.c
│   │   │   ├── serial_lld.h
│   │   │   ├── st_lld.c
│   │   │   ├── st_lld.h
│   │   │   ├── usb_lld.c
│   │   │   └── usb_lld.h
│   │   └── README.md
│   ├── LPC
│   ├── simulator
│   └── STM32
├── src
│   ├── adc.c
│   ├── can.c
│   ├── dac.c
│   ├── ext.c
│   ├── gpt.c
│   ├── hal.c
│   ├── hal_mmcsd.c
│   ├── hal_queues.c
│   ├── i2c.c
│   ├── i2s.c
│   ├── icu.c
│   ├── mac.c
│   ├── mmc_spi.c
│   ├── pal.c
│   ├── pwm.c
│   ├── rtc.c
│   ├── sdc.c
│   ├── serial.c
│   ├── serial_usb.c
│   ├── spi.c
│   ├── st.c
│   ├── uart.c
│   └── usb.c
└── templates
├── adc_lld.c
├── adc_lld.h
├── can_lld.c
├── can_lld.h
├── dac_lld.c
├── dac_lld.h
├── ext_lld.c
├── ext_lld.h
├── gpt_lld.c
├── gpt_lld.h
├── halconf.h
├── hal_lld.c
├── hal_lld.h
├── i2c_lld.c
├── i2c_lld.h
├── i2s_lld.c
├── i2s_lld.h
├── icu_lld.c
├── icu_lld.h
├── mac_lld.c
├── mac_lld.h
├── mcuconf.h
├── osal
│   ├── osal.c
│   ├── osal.h
│   └── osal.mk
├── pal_lld.c
├── pal_lld.h
├── platform.mk
├── pwm_lld.c
├── pwm_lld.h
├── rtc_lld.c
├── rtc_lld.h
├── sdc_lld.c
├── sdc_lld.h
├── serial_lld.c
├── serial_lld.h
├── spi_lld.c
├── spi_lld.h
├── st_lld.c
├── st_lld.h
├── uart_lld.c
├── uart_lld.h
├── usb_lld.c
└── usb_lld.h

View file

@ -1,5 +1,3 @@
#BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
#BOOTMAGIC_ENABLE = yes
ifndef QUANTUM_DIR ifndef QUANTUM_DIR
include ../../../../Makefile include ../../../../Makefile

View file

@ -11,6 +11,34 @@
#define _MEDIA 3 #define _MEDIA 3
#define _TILDE 4 #define _TILDE 4
//IS31 chip has 8 available led pages, using 0 for all leds and 7 for single toggles
#define max_pages 6
enum ic60_keycodes {
NUMPAD,
FNAV,
MEDIA,
TILDE,
CTLALTDEL,
BACKLIGHT,
BRIGHT,
DIM,
ALL,
GAME,
MODE_SINGLE,
MODE_PAGE,
MODE_FLASH
};
uint8_t current_layer_global = 0;
uint8_t led_mode_global = MODE_SINGLE;
uint8_t backlight_status_global = 1; //init on/off state of backlight
uint32_t led_layer_state = 0;
/* ==================================
* KEYMAPS
* ==================================*/
const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = { const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Layer 0: Default Layer /* Layer 0: Default Layer
* ,-----------------------------------------------------------. * ,-----------------------------------------------------------.
@ -30,17 +58,8 @@ const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,KC_EQL, KC_BSLS,KC_NO,\ KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,KC_EQL, KC_BSLS,KC_NO,\
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,KC_RBRC,KC_BSPC, \ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,KC_RBRC,KC_BSPC, \
TT(_FNAV), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT,KC_ENT, \ TT(_FNAV), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT,KC_ENT, \
F(1), KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH,KC_RSFT,KC_NO, \ KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH,F(TILDE),KC_NO, \
KC_LCTL, KC_LGUI,KC_LALT, KC_SPC, KC_RALT,TG(_NUMPAD),MO(_MEDIA), KC_RCTL \ KC_LCTL, KC_LGUI,KC_LALT, LT(_FNAV, KC_SPC), KC_RALT,TG(_NUMPAD),MO(_MEDIA), KC_RCTL \
),
/* F-, arrow, and media keys */
[_FNAV] = KEYMAP( \
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______,KC_NO,\
KC_CAPS,_______,_______,_______,_______,_______,_______,KC_PGUP,KC_UP,KC_PGDN,KC_PSCR,_______,_______,KC_DEL, \
_______,M(0),KC_BTN2,_______,_______,_______,KC_HOME,KC_LEFT,KC_DOWN,KC_RGHT,KC_INS,_______,_______, \
_______,KC_APP,KC_BTN1,KC_CALC,_______,_______,KC_END,_______,_______,_______,_______,_______,KC_NO, \
_______,_______,_______, _______, F(0),KC_NLCK,_______,_______ \
), ),
/* numpad */ /* numpad */
@ -49,15 +68,24 @@ const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
_______,_______,_______,_______,_______,_______,_______, KC_P4, KC_P5, KC_P6, KC_PAST, _______,_______,_______, \ _______,_______,_______,_______,_______,_______,_______, KC_P4, KC_P5, KC_P6, KC_PAST, _______,_______,_______, \
MO(_FNAV),_______,_______,_______,_______,_______,_______, KC_P1, KC_P2, KC_P3, KC_PMNS, _______,_______, \ MO(_FNAV),_______,_______,_______,_______,_______,_______, KC_P1, KC_P2, KC_P3, KC_PMNS, _______,_______, \
_______,_______,_______,_______,_______,_______,_______, KC_P0,KC_COMM,KC_PDOT,KC_PPLS, _______,KC_NO, \ _______,_______,_______,_______,_______,_______,_______, KC_P0,KC_COMM,KC_PDOT,KC_PPLS, _______,KC_NO, \
_______,_______,_______, MO(_BASE), _______,_______,_______,_______ \ _______,_______,_______, TO(_BASE), _______,_______,_______,_______ \
),
/* F-, arrow, and media keys */
[_FNAV] = KEYMAP( \
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______,KC_NO,\
KC_CAPS,_______,_______,_______,_______,_______,_______,KC_PGUP,KC_UP,KC_PGDN,KC_PSCR,_______,_______,KC_DEL, \
_______,_______,KC_BTN2,_______,_______,_______,KC_HOME,KC_LEFT,KC_DOWN,KC_RGHT,KC_INS,_______,_______, \
_______,KC_APP,KC_BTN1,KC_CALC,_______,_______,KC_END,_______,_______,_______,_______,_______,KC_NO, \
_______,_______,_______, _______, F(CTLALTDEL),KC_NLCK,_______,_______ \
), ),
/* media */ /* media */
[_MEDIA] = KEYMAP( \ [_MEDIA] = KEYMAP( \
_______,_______,_______,_______,_______,_______,_______, _______, _______, _______,KC_MUTE, KC_VOLD, KC_VOLU,_______,KC_NO,\ _______,F(MODE_SINGLE),F(MODE_PAGE),F(MODE_FLASH),_______,_______,_______, _______, _______, _______,KC_MUTE, KC_VOLD, KC_VOLU,_______,KC_NO,\
_______,_______,_______,_______,_______,_______,_______, _______, KC_UP, _______,_______, _______,_______,_______,\ _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______,_______,\
_______,_______,_______,_______,_______,_______,_______, KC_LEFT, KC_DOWN, KC_RGHT,_______, _______,_______, \ _______,_______,_______,_______,_______,F(GAME),_______, _______, _______, _______,_______, _______,_______, \
_______,_______,F(2),F(3),_______,_______,_______, _______, KC_MPRV, KC_MNXT,KC_MSTP, _______,KC_NO, \ _______,_______,F(ALL) ,F(BRIGHT),F(DIM),F(BACKLIGHT),_______, _______, KC_MPRV, KC_MNXT,KC_MSTP, _______,KC_NO, \
_______,_______,_______, KC_MPLY, _______,_______, _______,_______ \ _______,_______,_______, KC_MPLY, _______,_______, _______,_______ \
), ),
/* ~ */ /* ~ */
@ -85,58 +113,193 @@ enum function_id {
enum macro_id { enum macro_id {
ACTION_LEDS_ALL, ACTION_LEDS_ALL,
ACTION_LEDS_GAME ACTION_LEDS_GAME,
ACTION_LEDS_BACKLIGHT,
ACTION_LEDS_BRIGHT,
ACTION_LEDS_DIM,
ACTION_LEDS_SINGLE,
ACTION_LEDS_PAGE,
ACTION_LEDS_FLASH
}; };
/* ==================================
* LED MAPPING
* ==================================*/
/*
Infinity60 LED MAP
11 12 13 14 15 16 17 18 21 22 23 24 25 26 27*
28 31 32 33 34 35 36 37 38 41 42 43 44 45
46 47 48 51 52 53 54 55 56 57 58 61 62
63 64 65 66 67 68 71 72 73 74 75 76 77*
78 81 82 83 84 85 86 87
*Unused in Alphabet Layout
*/
//======== full page arrays =========
//any change in array size needs to be mirrored in matrix_init_user
uint8_t led_numpad[16] = {
18,21,22,23,
37,38,41,42,
55,56,57,58,
72,73,74,75
};
//LED Page 2 - _Nav
uint8_t led_nav[12] = {
38,
47,48, 55,56,57,
64,65,66
};
//LED Page 3 - _Media
uint8_t led_media[15] = {
12,13,14, 23,24,25,
65,66,67,68, 73,74,75,
83, 86
};
//LED Page 4 - _Game "WASD"
uint8_t led_game[5] = {
11,
32,
47,48,51
};
//======== qmk functions =========
const uint16_t fn_actions[] = { const uint16_t fn_actions[] = {
[0] = ACTION_KEY(LALT(LCTL(KC_DEL))), [CTLALTDEL] = ACTION_KEY(LALT(LCTL(KC_DEL))),
[1] = ACTION_LAYER_MODS(_TILDE, MOD_LSFT), [TILDE] = ACTION_LAYER_MODS(_TILDE, MOD_LSFT),
[2] = ACTION_FUNCTION(ACTION_LEDS_ALL), [ALL] = ACTION_FUNCTION(ACTION_LEDS_ALL),
[3] = ACTION_FUNCTION(ACTION_LEDS_GAME) [GAME] = ACTION_FUNCTION(ACTION_LEDS_GAME),
[BACKLIGHT] = ACTION_FUNCTION(ACTION_LEDS_BACKLIGHT),
[BRIGHT] = ACTION_FUNCTION(ACTION_LEDS_BRIGHT),
[DIM] = ACTION_FUNCTION(ACTION_LEDS_DIM),
[MODE_SINGLE] = ACTION_FUNCTION(ACTION_LEDS_SINGLE),
[MODE_PAGE] = ACTION_FUNCTION(ACTION_LEDS_PAGE),
[MODE_FLASH] = ACTION_FUNCTION(ACTION_LEDS_FLASH),
}; };
/* custom action function */ /* custom action function */
void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) { void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) {
(void)opt; msg_t msg;
switch(id) { switch(id) {
case ACTION_LEDS_ALL: case ACTION_LEDS_ALL:
if(record->event.pressed) { if(record->event.pressed) {
// signal the LED controller thread led_mode_global = led_mode_global == ALL ? MODE_SINGLE : ALL;
chMBPost(&led_mailbox, LED_MSG_GAME_TOGGLE, TIME_IMMEDIATE); msg=TOGGLE_ALL;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
} }
break; break;
case ACTION_LEDS_BACKLIGHT:
if(record->event.pressed) {
backlight_status_global ^= 1;
msg=(backlight_status_global << 8) | TOGGLE_BACKLIGHT;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
}
break;
case ACTION_LEDS_GAME: case ACTION_LEDS_GAME:
if(record->event.pressed) { if(record->event.pressed) {
// signal the LED controller thread led_mode_global = led_mode_global == GAME ? MODE_SINGLE : GAME;
chMBPost(&led_mailbox, LED_MSG_ALL_TOGGLE, TIME_IMMEDIATE);
msg=(4 << 8) | DISPLAY_PAGE;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
} }
break; break;
case ACTION_LEDS_BRIGHT:
if(record->event.pressed) {
msg=(1 << 8) | STEP_BRIGHTNESS;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
}
break;
case ACTION_LEDS_DIM:
if(record->event.pressed) {
msg=(0 << 8) | STEP_BRIGHTNESS;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
}
break;
//set led_mode for matrix_scan to toggle leds
case ACTION_LEDS_SINGLE:
led_mode_global = MODE_SINGLE;
break;
case ACTION_LEDS_PAGE:
led_mode_global = MODE_PAGE;
break;
case ACTION_LEDS_FLASH:
led_mode_global = MODE_FLASH;
break;
} }
} }
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
{ {
switch(id) {
case 0:
if (record->event.pressed) {
}
break;
case 1:
if (record->event.pressed) {
}
break;
}
return MACRO_NONE; return MACRO_NONE;
}; };
bool process_record_user (uint16_t keycode, keyrecord_t *record) {
return true;
}
// Runs just one time when the keyboard initializes. // Runs just one time when the keyboard initializes.
void matrix_init_user(void) { void matrix_init_user(void) {
xprintf("init start");
led_controller_init(); led_controller_init();
// Write predefined led pages.
write_led_page(_NUMPAD, led_numpad, 16);
chThdSleepMilliseconds(10);
write_led_page(_FNAV, led_nav, 12);
chThdSleepMilliseconds(10);
write_led_page(_MEDIA, led_media, 15);
chThdSleepMilliseconds(10);
write_led_page(4, led_game, 5);
chThdSleepMilliseconds(1000);
}; };
// Runs constantly in the background, in a loop. // Loops constantly in the background.
void matrix_scan_user(void) { void matrix_scan_user(void) {
uint8_t page;
uint8_t led_pin_byte;
msg_t msg;
}; if (backlight_status_global == 0) {//backlight is off, skip the rest
return;
}
if (led_layer_state != layer_state && led_mode_global != GAME && led_mode_global != ALL) {
//check mode
//Turn on layer indicator or page depending on mode
switch(led_mode_global) {
case MODE_FLASH: //flash preset page leds then single indicator
page = biton32(layer_state) > max_pages ? 7 : biton32(layer_state);
msg=(page << 8) | DISPLAY_PAGE;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
chThdSleepMilliseconds(500);
//flow to display single layer leds
case MODE_SINGLE: //light layer indicators for all active layers
led_pin_byte = layer_state & 0xFF;
msg=(7 << 8) | DISPLAY_PAGE;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
msg=(1 << 16) | (led_pin_byte << 8) | SET_FULL_ROW;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
break;
case MODE_PAGE: //display pre-defined led page
page = biton32(layer_state) > max_pages ? 7 : biton32(layer_state);
msg=(page << 8) | DISPLAY_PAGE;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
break;
}
led_layer_state = layer_state;
}
}

View file

@ -0,0 +1,87 @@
Backlight for Infinity60
========================
## Led Controller Specs
The Infinity60 (revision 1.1a) pcb uses the IS31FL3731C matrix LED driver from ISSI [(datasheet)](http://www.issi.com/WW/pdf/31FL3731C.pdf). The IS31 has the ability to control two led matrices (A & B), each matrix controlling 9 pins, each pin controlling 8 leds. The Infinity only utilizes matrix A.
Infinity60 LED Map:
digits mean "row" and "col", i.e. 45 means pin 4, column 5 in the IS31 datasheet
```c
11 12 13 14 15 16 17 18 21 22 23 24 25 26 27*
28 31 32 33 34 35 36 37 38 41 42 43 44 45
46 47 48 51 52 53 54 55 56 57 58 61 62
63 64 65 66 67 68 71 72 73 74 75 76 77*
78 81 82 83 84 85 86 87
```
*Unused in Alphabet Layout
The IS31 includes 8 led pages (or frames) 0-7 than can be displayed, and each page consists of 144 bytes.
- **bytes 0 - 17** - LED control (on/off).
* 18 pins which alternate between A and B matrices (A1, B1, A2, B2, ..).
* Each byte controls the 8 leds on that pin with bits (8 to 1).
- **bytes 8 - 35** - Blink control.
* Same as LED control above, but sets blink on/off.
- **bytes 36 - 143** - PWM control.
* One byte per LED, sets PWM from 0 to 255.
* Same as above, the register alternates, every 8 *bytes* (not bits) between the A & B matrices.
## Led Controller Code
In the Infinity60 project folder, led_controller.c sets up ability to write led layers at startup or control leds on demand as part of fn_actions. By default led_controller.c assumes page 0 will be used for full on/off. The remaining 7 pages (1-7) are free for preset led maps or single led actions at init or on demand. Communication with the IS31 is primarily done through the led_mailbox using chMBPost described further below under "Sending messages in Keymap.c". This code is based on work matt3o and flabbergast did for tmk firmware on the [whitefox](https://github.com/tmk/whitefox).
One function is available to directly set leds without the mailbox:
```
write_led_page(page#, array of leds by address, # of addresses in array)
```
This function saves a full page to the controller using a supplied array of led locations such as:
```c
uint8_t led_numpad[16] = {
18,21,22,23,
37,38,41,42,
55,56,57,58,
72,73,74,75
}
write_led_page(5, led_numpad, 16);
```
Remaining led control is done through the led mailbox using these message types:
- **SET_FULL_ROW** (3 bytes) - message type, 8-bit mask, and row#. Sets all leds on one pin per the bit mask.
- **OFF_LED, ON_LED, TOGGLE_LED** (3 bytes) - message type, led address, and page#. Off/on/toggle specific led.
- **BLINK_OFF_LED, BLINK_ON_LED, BLINK_OFF_LED** (3 bytes) - message type, led address, and page#. Set blink Off/on/toggle for specific led.
- **TOGGLE_ALL** (1 byte) - Turn on/off full backlight.
- **TOGGLE_BACKLIGHT** (2 bytes) - message type, on/off. Sets backlight completely off, no leds will display.
- **DISPLAY_PAGE** (2 bytes) - message type, page to display. Switch to specific pre-set page.
- **RESET_PAGE** (2 bytes) - message type, page to reset. Reset/erase specific page.
- **TOGGLE_NUM_LOCK** (2 bytes) - message type, on/off (NUM_LOCK_LED_ADDRESS). Toggle numlock on/off. Usually run with the `set_leds` function to check state of numlock or capslock. If all leds are on (e.i. TOGGLE_ALL) then this sets numlock to blink instead (this is still a little buggy if toggling on/off quickly).
- **TOGGLE_CAPS_LOCK** (2 bytes) - message type, on/off (CAPS_LOCK_LED_ADDRESS). Same as numlock.
- **STEP_BRIGHTNESS** (2 bytes) - message type, and step up (1) or step down (0). Increase or decrease led brightness.
## Sending messages in Keymap.c
Sending an action to the led mailbox is done using chMBPost:
```
chMBPost(&led_mailbox, message, timeout);
```
- &led_mailbox - pointer to led mailbox
- message - up to 4 bytes but most messages use only 2. First byte (LSB) is the message type, the remaining three bytes are the message to process.
- timeout is TIME_IMMEDIATE
An example:
```c
//set the message to be sent. First byte (LSB) is the led address, and second is the message type
msg=(42 << 8) | ON_LED;
//send msg to the led mailbox
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
```
Another:
```c
msg=(46 << 8) | BLINK_TOGGLE_LED;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
```
Finally, SET_FULL_ROW requires an extra byte with row information in the message so sending this message looks like:
```c
msg=(row<<16) | (led_pin_byte << 8) | SET_FULL_ROW;
chMBPost(&led_mailbox, msg, TIME_IMMEDIATE);
```

View file

@ -26,25 +26,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
* In particular, I2C functions (interrupt-driven) should NOT be called from here. * In particular, I2C functions (interrupt-driven) should NOT be called from here.
*/ */
void led_set(uint8_t usb_led) { void led_set(uint8_t usb_led) {
/* msg_t msg;
// PTA5: LED (1:on/0:off)
GPIOA->PDDR |= (1<<1); if (usb_led & (1<<USB_LED_NUM_LOCK)) {
PORTA->PCR[5] |= PORTx_PCRn_DSE | PORTx_PCRn_MUX(1);
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
GPIOA->PSOR |= (1<<5);
} else {
GPIOA->PCOR |= (1<<5);
}
*/
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
// signal the LED control thread
chSysUnconditionalLock(); chSysUnconditionalLock();
chMBPostI(&led_mailbox, LED_MSG_CAPS_ON); msg=(1 << 8) | TOGGLE_NUM_LOCK;
chMBPostI(&led_mailbox, msg);
chSysUnconditionalUnlock(); chSysUnconditionalUnlock();
} else { } else {
// signal the LED control thread
chSysUnconditionalLock(); chSysUnconditionalLock();
chMBPostI(&led_mailbox, LED_MSG_CAPS_OFF); msg=(0 << 8) | TOGGLE_NUM_LOCK;
chMBPostI(&led_mailbox, msg);
chSysUnconditionalUnlock();
}
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
chSysUnconditionalLock();
msg=(1 << 8) | TOGGLE_CAPS_LOCK;
chMBPostI(&led_mailbox, msg);
chSysUnconditionalUnlock();
} else {
chSysUnconditionalLock();
msg=(0 << 8) | TOGGLE_CAPS_LOCK;
chMBPostI(&led_mailbox, msg);
chSysUnconditionalUnlock(); chSysUnconditionalUnlock();
} }
} }

View file

@ -17,13 +17,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
/* /*
* LED controller code * LED controller code
* WF uses IS31FL3731C matrix LED driver from ISSI * IS31FL3731C matrix LED driver from ISSI
* datasheet: http://www.issi.com/WW/pdf/31FL3731C.pdf * datasheet: http://www.issi.com/WW/pdf/31FL3731C.pdf
*/ */
#include "ch.h" #include "ch.h"
#include "hal.h" #include "hal.h"
#include "print.h" #include "print.h"
#include "led.h"
#include "host.h"
#include "led_controller.h" #include "led_controller.h"
@ -53,11 +55,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
order same as above (CA 1st row (8bytes), CB 1st row (8bytes), ...) order same as above (CA 1st row (8bytes), CB 1st row (8bytes), ...)
*/ */
/* Which LED should be used for CAPS LOCK indicator // Which LED should be used for CAPS LOCK indicator
* The usual Caps Lock position is C4-6, so the address is
* 0x24 + (4-1)*0x10 + (8-1) = 0x59 */
#if !defined(CAPS_LOCK_LED_ADDRESS) #if !defined(CAPS_LOCK_LED_ADDRESS)
#define CAPS_LOCK_LED_ADDRESS 0x59 #define CAPS_LOCK_LED_ADDRESS 46
#endif
#if !defined(NUM_LOCK_LED_ADDRESS)
#define NUM_LOCK_LED_ADDRESS 85
#endif #endif
/* Which LED should breathe during sleep */ /* Which LED should breathe during sleep */
@ -83,14 +87,22 @@ uint8_t rx[1] __attribute__((aligned(2)));
uint8_t full_page[0xB4+1] = {0}; uint8_t full_page[0xB4+1] = {0};
// LED mask (which LEDs are present, selected by bits) // LED mask (which LEDs are present, selected by bits)
// See page comment above, control alternates CA matrix/CB matrix
// IC60 pcb uses only CA matrix. // IC60 pcb uses only CA matrix.
// Each byte is a control pin for 8 leds 8-1 // Each byte is a control pin for 8 leds ordered 8-1
const uint8_t is31_ic60_leds_mask[0x12] = { const uint8_t all_on_leds_mask[0x12] = {
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x00 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x00
}; };
// array to hold brightness pwm steps
const uint8_t pwm_levels[5] = {
0x00, 0x16, 0x4E, 0xA1, 0xFF
};
// array to write to pwm register
uint8_t pwm_register_array[9] = {0};
/* ============================ /* ============================
* communication functions * communication functions
* ============================ */ * ============================ */
@ -112,8 +124,8 @@ msg_t is31_write_register(uint8_t page, uint8_t reg, uint8_t data) {
return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, US2ST(IS31_TIMEOUT)); return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, US2ST(IS31_TIMEOUT));
} }
msg_t is31_read_register(uint8_t b, uint8_t reg, uint8_t *result) { msg_t is31_read_register(uint8_t page, uint8_t reg, uint8_t *result) {
is31_select_page(b); is31_select_page(page);
tx[0] = reg; tx[0] = reg;
return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 1, result, 1, US2ST(IS31_TIMEOUT)); return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 1, result, 1, US2ST(IS31_TIMEOUT));
@ -127,16 +139,9 @@ void is31_init(void) {
__builtin_memset(full_page,0,0xB4+1); __builtin_memset(full_page,0,0xB4+1);
// zero function page, all registers (assuming full_page is all zeroes) // zero function page, all registers (assuming full_page is all zeroes)
is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1); is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1);
// disable hardware shutdown
palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL); palSetPadMode(GPIOB, 16, PAL_MODE_OUTPUT_PUSHPULL);
palSetPad(GPIOB, 16); palSetPad(GPIOB, 16);
chThdSleepMilliseconds(10); chThdSleepMilliseconds(10);
// software shutdown
is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, 0);
chThdSleepMilliseconds(10);
// zero function page, all registers
is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1);
chThdSleepMilliseconds(10);
// software shutdown disable (i.e. turn stuff on) // software shutdown disable (i.e. turn stuff on)
is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON); is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON);
chThdSleepMilliseconds(10); chThdSleepMilliseconds(10);
@ -144,7 +149,7 @@ void is31_init(void) {
uint8_t i; uint8_t i;
for(i=0; i<8; i++) { for(i=0; i<8; i++) {
is31_write_data(i, full_page, 0xB4 + 1); is31_write_data(i, full_page, 0xB4 + 1);
chThdSleepMilliseconds(1); chThdSleepMilliseconds(5);
} }
} }
@ -159,134 +164,257 @@ static THD_FUNCTION(LEDthread, arg) {
(void)arg; (void)arg;
chRegSetThreadName("LEDthread"); chRegSetThreadName("LEDthread");
uint8_t temp; uint8_t i;
uint8_t save_page, save_breath1, save_breath2; uint8_t control_register_word[2] = {0};//2 bytes: register address, byte to write
msg_t msg, retval; uint8_t led_control_reg[0x13] = {0};//led control register start address + 0x12 bytes
//persistent status variables
uint8_t pwm_step_status, page_status;
//mailbox variables
uint8_t temp, msg_type;
uint8_t msg_args[3];
msg_t msg;
// initialize persistent variables
pwm_step_status = 4; //full brightness
page_status = 0; //start frame 0 (all off/on)
while(true) { while(true) {
// wait for a message (asynchronous) // wait for a message (asynchronous)
// (messages are queued (up to LED_MAILBOX_NUM_MSGS) if they can't // (messages are queued (up to LED_MAILBOX_NUM_MSGS) if they can't
// be processed right away) // be processed right away
chMBFetch(&led_mailbox, &msg, TIME_INFINITE); chMBFetch(&led_mailbox, &msg, TIME_INFINITE);
msg_type = msg & 0xFF; //first byte is action information
msg_args[0] = (msg >> 8) & 0xFF;
msg_args[1] = (msg >> 16) & 0XFF;
msg_args[2] = (msg >> 24) & 0xFF;
// process 'msg' here switch (msg_type){
switch(msg) { case SET_FULL_ROW:
case LED_MSG_CAPS_ON: //write full byte to pin address, msg_args[1] = pin #, msg_args[0] = 8 bits to write
// turn caps on on pages 1 and 2 //writes only to currently displayed page
is31_write_register(0, CAPS_LOCK_LED_ADDRESS, 0xFF); write_led_byte(page_status, msg_args[1], msg_args[0]);
is31_write_register(1, CAPS_LOCK_LED_ADDRESS, 0xFF);
is31_write_register(2, CAPS_LOCK_LED_ADDRESS, 0xFF);
break; break;
case LED_MSG_CAPS_OFF:
// turn caps off on pages 1 and 2 case OFF_LED:
is31_write_register(0, CAPS_LOCK_LED_ADDRESS, 0); //on/off/toggle single led, msg_args[0] = row/col of led, msg_args[1] = page
is31_write_register(1, CAPS_LOCK_LED_ADDRESS, 0); set_led_bit(msg_args[1], control_register_word, msg_args[0], 0);
is31_write_register(2, CAPS_LOCK_LED_ADDRESS, 0);
break; break;
case LED_MSG_SLEEP_LED_ON: case ON_LED:
// save current settings set_led_bit(msg_args[1], control_register_word, msg_args[0], 1);
is31_read_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, &save_page);
is31_read_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, &save_breath1);
is31_read_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, &save_breath2);
// use pages 7 and 8 for (hardware) breathing (assuming they're empty)
is31_write_register(6, BREATHE_LED_ADDRESS, 0xFF);
is31_write_register(7, BREATHE_LED_ADDRESS, 0x00);
is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, (6<<4)|6);
is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, IS31_REG_BREATHCTRL2_ENABLE|3);
retval = MSG_TIMEOUT;
temp = 6;
while(retval == MSG_TIMEOUT) {
// switch to the other page
is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, temp);
temp = (temp == 6 ? 7 : 6);
// the times should be sufficiently long for IS31 to finish switching pages
retval = chMBFetch(&led_mailbox, &msg, MS2ST(temp == 6 ? 4000 : 6000));
}
// received a message (should be a wakeup), so restore previous state
chThdSleepMilliseconds(3000); // need to wait until the page change finishes
// note: any other messages are queued
is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, save_breath1);
is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, save_breath2);
is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, save_page);
break; break;
case LED_MSG_SLEEP_LED_OFF: case TOGGLE_LED:
// should not get here; wakeup should be received in the branch above set_led_bit(msg_args[1], control_register_word, msg_args[0], 2);
break; break;
case LED_MSG_ALL_TOGGLE:
// read current page into 'temp' case BLINK_OFF_LED:
is31_read_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, &temp); //on/off/toggle single led, msg_args[0] = row/col of led
chThdSleepMilliseconds(1); set_led_bit(msg_args[1], control_register_word, msg_args[0], 4);
// switch to 'the other' page break;
if(temp==2) { case BLINK_ON_LED:
is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 0); set_led_bit(msg_args[1], control_register_word, msg_args[0], 5);
break;
case BLINK_TOGGLE_LED:
set_led_bit(msg_args[1], control_register_word, msg_args[0], 6);
break;
case TOGGLE_ALL:
//turn on/off all leds, msg_args = unused
is31_read_register(0, 0x00, &temp);
led_control_reg[0] = 0;
//if first leds are already on, toggle frame 0 off
if (temp==0 || page_status > 0) {
__builtin_memcpy(led_control_reg+1, all_on_leds_mask, 0x12);
} else { } else {
is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 2); __builtin_memset(led_control_reg+1, 0, 0x12);
} }
break; is31_write_data(0, led_control_reg, 0x13);
case LED_MSG_GAME_TOGGLE:
// read current page into 'temp' if (page_status > 0) {
is31_read_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, &temp);
chThdSleepMilliseconds(1);
// switch to 'the other' page
if(temp==1) {
is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 0); is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 0);
page_status=0;
//maintain lock leds
led_set(host_keyboard_leds());
}
break;
case TOGGLE_BACKLIGHT:
//msg_args[0] = on/off
//populate 9 byte rows to be written to each pin, first byte is register (pin) address
if (msg_args[0] == 1) {
__builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8);
} else { } else {
is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 1); __builtin_memset(pwm_register_array+1, 0, 8);
}
for(i=0; i<8; i++) {
//first byte is register address, every 0x10 9 bytes is A-matrix pwm pins
pwm_register_array[0] = 0x24 + (i * 0x10);
is31_write_data(0,pwm_register_array,9);
}
break;
case DISPLAY_PAGE:
//msg_args[0] = page to toggle on
if (page_status != msg_args[0]) {
is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, msg_args[0]);
page_status = msg_args[0];
//maintain lock leds
led_set(host_keyboard_leds());
}
break;
case RESET_PAGE:
//led_args[0] = page to reset
led_control_reg[0] = 0;
__builtin_memset(led_control_reg+1, 0, 0x12);
is31_write_data(msg_args[0], led_control_reg, 0x13);
//repeat for blink register
led_control_reg[0] = 0x12;
is31_write_data(msg_args[0], led_control_reg, 0x13);
break;
case TOGGLE_NUM_LOCK:
//msg_args[0] = 0 or 1, off/on
set_lock_leds(NUM_LOCK_LED_ADDRESS, msg_args[0], page_status);
break;
case TOGGLE_CAPS_LOCK:
//msg_args[0] = 0 or 1, off/on
set_lock_leds(CAPS_LOCK_LED_ADDRESS, msg_args[0], page_status);
break;
case STEP_BRIGHTNESS:
//led_args[0] = step up (1) or down (0)
switch (msg_args[0]) {
case 0:
if (pwm_step_status == 0) {
pwm_step_status = 4;
} else {
pwm_step_status--;
}
break;
case 1:
if (pwm_step_status == 4) {
pwm_step_status = 0;
} else {
pwm_step_status++;
}
break;
}
//populate 8 byte arrays to write on each pin
//first byte is register address, every 0x10 9 bytes are A-matrix pwm pins
__builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8);
for(i=0; i<8; i++) {
pwm_register_array[0] = 0x24 + (i * 0x10);
is31_write_data(0,pwm_register_array,9);
} }
break; break;
} }
} }
} }
//These relate to the LED map above, row and column /* ==============================
//0x24 = first byte (CA1) of PWM page, 0x34 is 17th byte (CA2) * led processing functions
/* LED game mode */ * ============================== */
const uint8_t led_game[72] = {
0x24,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x34,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44,
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x54,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
0x64,
0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x74,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x84,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x94,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
/* ALL LEDs */ void set_led_bit (uint8_t page, uint8_t *led_control_word, uint8_t led_addr, uint8_t action) {
const uint8_t led_all[72] = { //returns 2 bytes: led control register address and byte to write
0x24, //action: 0 - off, 1 - on, 2 - toggle, 4 - blink on, 5 - blink off, 6 - toggle blink
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x34,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x44,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x54,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x64,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x74,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x84,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x94,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
/* ============= uint8_t control_reg_addr, column_bit, column_byte, temp, blink_bit;
* hook into TMK
* ============= */ //check for valid led address
if (led_addr < 0 || led_addr > 87 || led_addr % 10 > 8) {
return;
}
blink_bit = action>>2;//check for blink bit
action &= ~(1<<2); //strip blink bit
//led_addr tens column is pin#, ones column is bit position in 8-bit mask
control_reg_addr = ((led_addr / 10) % 10 - 1 ) * 0x02;// A-matrix is every other byte
control_reg_addr += blink_bit == 1 ? 0x12 : 0x00;//if blink_bit, shift 12 bytes to blink register
is31_read_register(page, control_reg_addr, &temp);//maintain status of leds on this byte
column_bit = 1<<(led_addr % 10 - 1);
column_byte = temp;
switch(action) {
case 0:
column_byte &= ~column_bit;
break;
case 1:
column_byte |= column_bit;
break;
case 2:
column_byte ^= column_bit;
break;
}
//return word to be written in register
led_control_word[0] = control_reg_addr;
led_control_word[1] = column_byte;
is31_write_data (page, led_control_word, 0x02);
}
void write_led_byte (uint8_t page, uint8_t row, uint8_t led_byte) {
uint8_t led_control_word[2] = {0};//register address and on/off byte
led_control_word[0] = (row - 1 ) * 0x02;// A-matrix is every other byte
led_control_word[1] = led_byte;
is31_write_data(page, led_control_word, 0x02);
}
void write_led_page (uint8_t page, uint8_t *user_led_array, uint8_t led_count) {
uint8_t i;
uint8_t pin, col;
uint8_t led_control_register[0x13] = {0};
__builtin_memset(led_control_register,0,13);
for(i=0;i<led_count;i++){
//shift pin by 1 for led register 0x00 address
pin = ((user_led_array[i] / 10) % 10 - 1 ) * 2 + 1;
col = user_led_array[i] % 10 - 1;
led_control_register[pin] |= 1<<(col);
}
is31_write_data(page, led_control_register, 0x13);
}
void set_lock_leds(uint8_t led_addr, uint8_t led_action, uint8_t page) {
uint8_t temp;
uint8_t led_control_word[2] = {0};
//blink if all leds are on
if (page == 0) {
is31_read_register(0, 0x00, &temp);
chThdSleepMilliseconds(10);
if (temp == 0xFF) {
led_action |= (1<<2); //set blink bit
}
}
set_led_bit(page,led_control_word,led_addr,led_action);
}
/* =====================
* hook into user keymap
* ===================== */
void led_controller_init(void) { void led_controller_init(void) {
uint8_t i; uint8_t i;
xprintf("led_controller_init");
/* initialise I2C */ /* initialise I2C */
/* I2C pins */ /* I2C pins */
palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL
@ -303,11 +431,17 @@ void led_controller_init(void) {
/* initialise IS31 chip */ /* initialise IS31 chip */
is31_init(); is31_init();
/* enable LEDs on all pages */ //set Display Option Register so all pwm intensity is controlled from page 0
full_page[0] = 0; //enable blink and set blink period to 0.27s x rate
__builtin_memcpy(full_page+1, is31_ic60_leds_mask, 0x12); is31_write_register(IS31_FUNCTIONREG, IS31_REG_DISPLAYOPT, IS31_REG_DISPLAYOPT_INTENSITY_SAME + IS31_REG_DISPLAYOPT_BLINK_ENABLE + 4);
/* set full pwm on page 1 */
pwm_register_array[0] = 0;
__builtin_memset(pwm_register_array+1, 0xFF, 8);
for(i=0; i<8; i++) { for(i=0; i<8; i++) {
is31_write_data(i, full_page, 1+0x12); pwm_register_array[0] = 0x24 + (i * 0x10);//first byte of 9 bytes must be register address
is31_write_data(0, pwm_register_array, 9);
chThdSleepMilliseconds(5);
} }
/* enable breathing when the displayed page changes */ /* enable breathing when the displayed page changes */
@ -315,47 +449,8 @@ void led_controller_init(void) {
is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, (3<<4)|3); is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, (3<<4)|3);
is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, IS31_REG_BREATHCTRL2_ENABLE|3); is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, IS31_REG_BREATHCTRL2_ENABLE|3);
/* Write pages */
for(i=0; i<8; i++) {
is31_write_data(1,(uint8_t *)(led_game+(9*i)),9);
chThdSleepMilliseconds(5);
is31_write_data(2,(uint8_t *)(led_all+(9*i)),9);
chThdSleepMilliseconds(5);
}
// clean up the capslock LED
is31_write_register(1, CAPS_LOCK_LED_ADDRESS, 0);
is31_write_register(2, CAPS_LOCK_LED_ADDRESS, 0);
/* more time consuming LED processing should be offloaded into /* more time consuming LED processing should be offloaded into
* a thread, with asynchronous messaging. */ * a thread, with asynchronous messaging. */
chMBObjectInit(&led_mailbox, led_mailbox_queue, LED_MAILBOX_NUM_MSGS); chMBObjectInit(&led_mailbox, led_mailbox_queue, LED_MAILBOX_NUM_MSGS);
chThdCreateStatic(waLEDthread, sizeof(waLEDthread), LOWPRIO, LEDthread, NULL); chThdCreateStatic(waLEDthread, sizeof(waLEDthread), LOWPRIO, LEDthread, NULL);
} }
//TODO: Don't know equivalent QMK hooks for these
//
//void hook_usb_suspend_entry(void) {
//#ifdef SLEEP_LED_ENABLE
// chSysLockFromISR();
// chMBPostI(&led_mailbox, LED_MSG_SLEEP_LED_ON);
// chSysUnlockFromISR();
//#endif /* SLEEP_LED_ENABLE */
//}
//
//void hook_usb_suspend_loop(void) {
// chThdSleepMilliseconds(100);
// /* Remote wakeup */
// if((USB_DRIVER.status & 2) && suspend_wakeup_condition()) {
// send_remote_wakeup(&USB_DRIVER);
// }
//}
//
//void hook_usb_wakeup(void) {
//#ifdef SLEEP_LED_ENABLE
// chSysLockFromISR();
// chMBPostI(&led_mailbox, LED_MSG_SLEEP_LED_OFF);
// chSysUnlockFromISR();
//#endif /* SLEEP_LED_ENABLE */
//}
//*/

View file

@ -26,12 +26,15 @@ msg_t is31_write_data(uint8_t page, uint8_t *buffer, uint8_t size);
msg_t is31_write_register(uint8_t page, uint8_t reg, uint8_t data); msg_t is31_write_register(uint8_t page, uint8_t reg, uint8_t data);
msg_t is31_read_register(uint8_t page, uint8_t reg, uint8_t *result); msg_t is31_read_register(uint8_t page, uint8_t reg, uint8_t *result);
/* ========================= /* ============================
* init functions * init functions/definitions
* ========================= */ * ============================*/
void led_controller_init(void); void led_controller_init(void);
#define CAPS_LOCK_LED_ADDRESS 46 //pin matrix location
#define NUM_LOCK_LED_ADDRESS 85
/* ============================= /* =============================
* IS31 chip related definitions * IS31 chip related definitions
* ============================= */ * ============================= */
@ -55,7 +58,7 @@ void led_controller_init(void);
#define IS31_REG_DISPLAYOPT 0x05 #define IS31_REG_DISPLAYOPT 0x05
#define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames #define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames
#define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x8 #define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x08
// D2:D0 bits blink period time (*0.27s) // D2:D0 bits blink period time (*0.27s)
#define IS31_REG_AUDIOSYNC 0x06 #define IS31_REG_AUDIOSYNC 0x06
@ -82,20 +85,35 @@ void led_controller_init(void);
#define IS31_TIMEOUT 10000 // needs to be long enough to write a whole page #define IS31_TIMEOUT 10000 // needs to be long enough to write a whole page
/* ============================== /* ========================================
* LED Thread related definitions * LED Thread related items
* ============================== */ * ========================================*/
extern mailbox_t led_mailbox; extern mailbox_t led_mailbox;
void set_led_bit (uint8_t page, uint8_t *led_control_reg, uint8_t led_addr, uint8_t action);
void set_lock_leds (uint8_t led_addr, uint8_t led_action, uint8_t page);
void write_led_byte (uint8_t page, uint8_t row, uint8_t led_byte);
void write_led_page (uint8_t page, uint8_t *led_array, uint8_t led_count);
// constants for signaling the LED controller thread // constants for signaling the LED controller thread
enum led_msg_t { enum led_msg_t {
LED_MSG_CAPS_ON, KEY_LIGHT,
LED_MSG_CAPS_OFF, SET_FULL_ROW,
LED_MSG_SLEEP_LED_ON, OFF_LED,
LED_MSG_SLEEP_LED_OFF, ON_LED,
LED_MSG_ALL_TOGGLE, TOGGLE_LED,
LED_MSG_GAME_TOGGLE BLINK_OFF_LED,
BLINK_ON_LED,
BLINK_TOGGLE_LED,
TOGGLE_ALL,
TOGGLE_BACKLIGHT,
DISPLAY_PAGE,
RESET_PAGE,
TOGGLE_NUM_LOCK,
TOGGLE_CAPS_LOCK,
TOGGLE_BREATH,
STEP_BRIGHTNESS
}; };
#endif /* _LED_CONTROLLER_H_ */ #endif /* _LED_CONTROLLER_H_ */