diff options
| author | Jack Humbert <jack.humb@gmail.com> | 2017-06-18 12:38:38 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2017-06-18 12:38:38 -0400 |
| commit | 517f75d893253e448105401ac638257841ad9e97 (patch) | |
| tree | d06edd04812ad134aae6d470725fbac5205499b4 | |
| parent | dd73e14c9b4d74473434fee78a9b1eb84491b1a8 (diff) | |
| parent | 9af272e4bb685faabd1d879231f2718f0c00b32d (diff) | |
| download | qmk_firmware-517f75d893253e448105401ac638257841ad9e97.tar.gz qmk_firmware-517f75d893253e448105401ac638257841ad9e97.zip | |
Merge pull request #1349 from jpetermans/infinity60
Infinity60 backlight support
| -rw-r--r-- | keyboards/infinity60/config.h | 2 | ||||
| -rw-r--r-- | keyboards/infinity60/halconf.h | 4 | ||||
| -rw-r--r-- | keyboards/infinity60/keymaps/jpetermans/Makefile | 4 | ||||
| -rw-r--r-- | keyboards/infinity60/keymaps/jpetermans/config.h | 11 | ||||
| -rw-r--r-- | keyboards/infinity60/keymaps/jpetermans/keymap.c | 304 | ||||
| -rw-r--r-- | keyboards/infinity60/keymaps/jpetermans/readme.md | 87 | ||||
| -rw-r--r-- | keyboards/infinity60/led.c | 31 | ||||
| -rw-r--r-- | keyboards/infinity60/led_controller.c | 486 | ||||
| -rw-r--r-- | keyboards/infinity60/led_controller.h | 120 | ||||
| -rw-r--r-- | keyboards/infinity60/mcuconf.h | 11 | ||||
| -rw-r--r-- | keyboards/infinity60/rules.mk | 7 |
11 files changed, 1056 insertions, 11 deletions
diff --git a/keyboards/infinity60/config.h b/keyboards/infinity60/config.h index f8346fe16..83930901c 100644 --- a/keyboards/infinity60/config.h +++ b/keyboards/infinity60/config.h | |||
| @@ -54,7 +54,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 54 | //#define INFINITY_PROTOTYPE | 54 | //#define INFINITY_PROTOTYPE |
| 55 | 55 | ||
| 56 | /* Keymap for Infinity 1.1a (first revision with LED support) */ | 56 | /* Keymap for Infinity 1.1a (first revision with LED support) */ |
| 57 | //#define INFINITY_LED | 57 | #define INFINITY_LED |
| 58 | 58 | ||
| 59 | /* | 59 | /* |
| 60 | * Feature disable options | 60 | * Feature disable options |
diff --git a/keyboards/infinity60/halconf.h b/keyboards/infinity60/halconf.h index 46b37a4f4..f89dfc2e1 100644 --- a/keyboards/infinity60/halconf.h +++ b/keyboards/infinity60/halconf.h | |||
| @@ -76,7 +76,7 @@ | |||
| 76 | * @brief Enables the I2C subsystem. | 76 | * @brief Enables the I2C subsystem. |
| 77 | */ | 77 | */ |
| 78 | #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) | 78 | #if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) |
| 79 | #define HAL_USE_I2C FALSE | 79 | #define HAL_USE_I2C TRUE |
| 80 | #endif | 80 | #endif |
| 81 | 81 | ||
| 82 | /** | 82 | /** |
| @@ -139,7 +139,7 @@ | |||
| 139 | * @brief Enables the SERIAL over USB subsystem. | 139 | * @brief Enables the SERIAL over USB subsystem. |
| 140 | */ | 140 | */ |
| 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) | 141 | #if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) |
| 142 | #define HAL_USE_SERIAL_USB TRUE | 142 | #define HAL_USE_SERIAL_USB FALSE |
| 143 | #endif | 143 | #endif |
| 144 | 144 | ||
| 145 | /** | 145 | /** |
diff --git a/keyboards/infinity60/keymaps/jpetermans/Makefile b/keyboards/infinity60/keymaps/jpetermans/Makefile new file mode 100644 index 000000000..df3d1e952 --- /dev/null +++ b/keyboards/infinity60/keymaps/jpetermans/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | |||
| 2 | ifndef QUANTUM_DIR | ||
| 3 | include ../../../../Makefile | ||
| 4 | endif | ||
diff --git a/keyboards/infinity60/keymaps/jpetermans/config.h b/keyboards/infinity60/keymaps/jpetermans/config.h new file mode 100644 index 000000000..72a2ed081 --- /dev/null +++ b/keyboards/infinity60/keymaps/jpetermans/config.h | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | #ifndef CONFIG_USER_H | ||
| 2 | #define CONFIG_USER_H | ||
| 3 | |||
| 4 | |||
| 5 | #include "../../config.h" | ||
| 6 | |||
| 7 | //overrides | ||
| 8 | #undef TAPPING_TOGGLE | ||
| 9 | #define TAPPING_TOGGLE 2 | ||
| 10 | |||
| 11 | #endif | ||
diff --git a/keyboards/infinity60/keymaps/jpetermans/keymap.c b/keyboards/infinity60/keymaps/jpetermans/keymap.c new file mode 100644 index 000000000..59249ff72 --- /dev/null +++ b/keyboards/infinity60/keymaps/jpetermans/keymap.c | |||
| @@ -0,0 +1,304 @@ | |||
| 1 | #include "infinity60.h" | ||
| 2 | #include "led_controller.h" | ||
| 3 | |||
| 4 | //Helpful Defines | ||
| 5 | #define _______ KC_TRNS | ||
| 6 | |||
| 7 | //Define Layer Names | ||
| 8 | #define _BASE 0 | ||
| 9 | #define _NUMPAD 1 | ||
| 10 | #define _FNAV 2 | ||
| 11 | #define _MEDIA 3 | ||
| 12 | #define _TILDE 4 | ||
| 13 | |||
| 14 | //IS31 chip has 8 available led pages, using 0 for all leds and 7 for single toggles | ||
| 15 | #define max_pages 6 | ||
| 16 | |||
| 17 | enum ic60_keycodes { | ||
| 18 | NUMPAD, | ||
| 19 | FNAV, | ||
| 20 | MEDIA, | ||
| 21 | TILDE, | ||
| 22 | CTLALTDEL, | ||
| 23 | BACKLIGHT, | ||
| 24 | BRIGHT, | ||
| 25 | DIM, | ||
| 26 | ALL, | ||
| 27 | GAME, | ||
| 28 | MODE_SINGLE, | ||
| 29 | MODE_PAGE, | ||
| 30 | MODE_FLASH | ||
| 31 | }; | ||
| 32 | |||
| 33 | uint8_t current_layer_global = 0; | ||
| 34 | uint8_t led_mode_global = MODE_SINGLE; | ||
| 35 | uint8_t backlight_status_global = 1; //init on/off state of backlight | ||
| 36 | uint32_t led_layer_state = 0; | ||
| 37 | |||
| 38 | /* ================================== | ||
| 39 | * KEYMAPS | ||
| 40 | * ==================================*/ | ||
| 41 | |||
| 42 | const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||
| 43 | /* Layer 0: Default Layer | ||
| 44 | * ,-----------------------------------------------------------. | ||
| 45 | * |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| Backs| | ||
| 46 | * |-----------------------------------------------------------| | ||
| 47 | * |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| | ||
| 48 | * |-----------------------------------------------------------| | ||
| 49 | * |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Enter | | ||
| 50 | * |-----------------------------------------------------------| | ||
| 51 | * |Shif| | Z| X| C| V| B| N| M| ,| .| /|Shift | | ||
| 52 | * |-----------------------------------------------------------| | ||
| 53 | * |Ctrl|Gui |Alt | Space |Alt |Gui | FN | Ctrl | | ||
| 54 | * `-----------------------------------------------------------' | ||
| 55 | */ | ||
| 56 | /* default */ | ||
| 57 | [_BASE] = KEYMAP( \ | ||
| 58 | 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,\ | ||
| 59 | 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, \ | ||
| 60 | 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, \ | ||
| 61 | 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, \ | ||
| 62 | KC_LCTL, KC_LGUI,KC_LALT, LT(_FNAV, KC_SPC), KC_RALT,TG(_NUMPAD),MO(_MEDIA), KC_RCTL \ | ||
| 63 | ), | ||
| 64 | |||
| 65 | /* numpad */ | ||
| 66 | [_NUMPAD] = KEYMAP( \ | ||
| 67 | _______,_______,_______,_______,_______,_______,_______, KC_P7, KC_P8, KC_P9, KC_PSLS, _______,_______,_______,KC_NO,\ | ||
| 68 | _______,_______,_______,_______,_______,_______,_______, KC_P4, KC_P5, KC_P6, KC_PAST, _______,_______,_______, \ | ||
| 69 | MO(_FNAV),_______,_______,_______,_______,_______,_______, KC_P1, KC_P2, KC_P3, KC_PMNS, _______,_______, \ | ||
| 70 | _______,_______,_______,_______,_______,_______,_______, KC_P0,KC_COMM,KC_PDOT,KC_PPLS, _______,KC_NO, \ | ||
| 71 | _______,_______,_______, TO(_BASE), _______,_______,_______,_______ \ | ||
| 72 | ), | ||
| 73 | |||
| 74 | /* F-, arrow, and media keys */ | ||
| 75 | [_FNAV] = KEYMAP( \ | ||
| 76 | 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,\ | ||
| 77 | KC_CAPS,_______,_______,_______,_______,_______,_______,KC_PGUP,KC_UP,KC_PGDN,KC_PSCR,_______,_______,KC_DEL, \ | ||
| 78 | _______,_______,KC_BTN2,_______,_______,_______,KC_HOME,KC_LEFT,KC_DOWN,KC_RGHT,KC_INS,_______,_______, \ | ||
| 79 | _______,KC_APP,KC_BTN1,KC_CALC,_______,_______,KC_END,_______,_______,_______,_______,_______,KC_NO, \ | ||
| 80 | _______,_______,_______, _______, F(CTLALTDEL),KC_NLCK,_______,_______ \ | ||
| 81 | ), | ||
| 82 | |||
| 83 | /* media */ | ||
| 84 | [_MEDIA] = KEYMAP( \ | ||
| 85 | _______,F(MODE_SINGLE),F(MODE_PAGE),F(MODE_FLASH),_______,_______,_______, _______, _______, _______,KC_MUTE, KC_VOLD, KC_VOLU,_______,KC_NO,\ | ||
| 86 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______,_______,\ | ||
| 87 | _______,_______,_______,_______,_______,F(GAME),_______, _______, _______, _______,_______, _______,_______, \ | ||
| 88 | _______,_______,F(ALL) ,F(BRIGHT),F(DIM),F(BACKLIGHT),_______, _______, KC_MPRV, KC_MNXT,KC_MSTP, _______,KC_NO, \ | ||
| 89 | _______,_______,_______, KC_MPLY, _______,_______, _______,_______ \ | ||
| 90 | ), | ||
| 91 | /* ~ */ | ||
| 92 | [_TILDE] = KEYMAP( \ | ||
| 93 | KC_GRV,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______,_______,KC_NO,\ | ||
| 94 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______,_______,\ | ||
| 95 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______, \ | ||
| 96 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,KC_NO, \ | ||
| 97 | _______,_______,_______, _______, _______,_______, _______,_______ \ | ||
| 98 | ), | ||
| 99 | /* template */ | ||
| 100 | [5] = KEYMAP( \ | ||
| 101 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______,_______,KC_NO,\ | ||
| 102 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______,_______,\ | ||
| 103 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,_______, \ | ||
| 104 | _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______, _______,KC_NO, \ | ||
| 105 | _______,_______,_______, _______, _______,_______, _______,_______ \ | ||
| 106 | ), | ||
| 107 | }; | ||
| 108 | |||
| 109 | //id for user defined functions and macros | ||
| 110 | enum function_id { | ||
| 111 | NONE, | ||
| 112 | }; | ||
| 113 | |||
| 114 | enum macro_id { | ||
| 115 | ACTION_LEDS_ALL, | ||
| 116 | ACTION_LEDS_GAME, | ||
| 117 | ACTION_LEDS_BACKLIGHT, | ||
| 118 | ACTION_LEDS_BRIGHT, | ||
| 119 | ACTION_LEDS_DIM, | ||
| 120 | ACTION_LEDS_SINGLE, | ||
| 121 | ACTION_LEDS_PAGE, | ||
| 122 | ACTION_LEDS_FLASH | ||
| 123 | }; | ||
| 124 | |||
| 125 | /* ================================== | ||
| 126 | * LED MAPPING | ||
| 127 | * ==================================*/ | ||
| 128 | |||
| 129 | /* | ||
| 130 | Infinity60 LED MAP | ||
| 131 | 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27* | ||
| 132 | 28 31 32 33 34 35 36 37 38 41 42 43 44 45 | ||
| 133 | 46 47 48 51 52 53 54 55 56 57 58 61 62 | ||
| 134 | 63 64 65 66 67 68 71 72 73 74 75 76 77* | ||
| 135 | 78 81 82 83 84 85 86 87 | ||
| 136 | *Unused in Alphabet Layout | ||
| 137 | */ | ||
| 138 | |||
| 139 | //======== full page arrays ========= | ||
| 140 | //any change in array size needs to be mirrored in matrix_init_user | ||
| 141 | uint8_t led_numpad[16] = { | ||
| 142 | 18,21,22,23, | ||
| 143 | 37,38,41,42, | ||
| 144 | 55,56,57,58, | ||
| 145 | 72,73,74,75 | ||
| 146 | }; | ||
| 147 | //LED Page 2 - _Nav | ||
| 148 | uint8_t led_nav[12] = { | ||
| 149 | 38, | ||
| 150 | 47,48, 55,56,57, | ||
| 151 | 64,65,66 | ||
| 152 | }; | ||
| 153 | //LED Page 3 - _Media | ||
| 154 | uint8_t led_media[15] = { | ||
| 155 | 12,13,14, 23,24,25, | ||
| 156 | 65,66,67,68, 73,74,75, | ||
| 157 | 83, 86 | ||
| 158 | }; | ||
| 159 | //LED Page 4 - _Game "WASD" | ||
| 160 | uint8_t led_game[5] = { | ||
| 161 | 11, | ||
| 162 | 32, | ||
| 163 | 47,48,51 | ||
| 164 | }; | ||
| 165 | |||
| 166 | //======== qmk functions ========= | ||
| 167 | const uint16_t fn_actions[] = { | ||
| 168 | [CTLALTDEL] = ACTION_KEY(LALT(LCTL(KC_DEL))), | ||
| 169 | [TILDE] = ACTION_LAYER_MODS(_TILDE, MOD_LSFT), | ||
| 170 | [ALL] = ACTION_FUNCTION(ACTION_LEDS_ALL), | ||
| 171 | [GAME] = ACTION_FUNCTION(ACTION_LEDS_GAME), | ||
| 172 | [BACKLIGHT] = ACTION_FUNCTION(ACTION_LEDS_BACKLIGHT), | ||
| 173 | [BRIGHT] = ACTION_FUNCTION(ACTION_LEDS_BRIGHT), | ||
| 174 | [DIM] = ACTION_FUNCTION(ACTION_LEDS_DIM), | ||
| 175 | [MODE_SINGLE] = ACTION_FUNCTION(ACTION_LEDS_SINGLE), | ||
| 176 | [MODE_PAGE] = ACTION_FUNCTION(ACTION_LEDS_PAGE), | ||
| 177 | [MODE_FLASH] = ACTION_FUNCTION(ACTION_LEDS_FLASH), | ||
| 178 | }; | ||
| 179 | |||
| 180 | /* custom action function */ | ||
| 181 | void action_function(keyrecord_t *record, uint8_t id, uint8_t opt) { | ||
| 182 | msg_t msg; | ||
| 183 | |||
| 184 | switch(id) { | ||
| 185 | case ACTION_LEDS_ALL: | ||
| 186 | if(record->event.pressed) { | ||
| 187 | led_mode_global = led_mode_global == ALL ? MODE_SINGLE : ALL; | ||
| 188 | msg=TOGGLE_ALL; | ||
| 189 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 190 | } | ||
| 191 | break; | ||
| 192 | |||
| 193 | case ACTION_LEDS_BACKLIGHT: | ||
| 194 | if(record->event.pressed) { | ||
| 195 | backlight_status_global ^= 1; | ||
| 196 | msg=(backlight_status_global << 8) | TOGGLE_BACKLIGHT; | ||
| 197 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 198 | } | ||
| 199 | break; | ||
| 200 | |||
| 201 | case ACTION_LEDS_GAME: | ||
| 202 | if(record->event.pressed) { | ||
| 203 | led_mode_global = led_mode_global == GAME ? MODE_SINGLE : GAME; | ||
| 204 | |||
| 205 | msg=(4 << 8) | DISPLAY_PAGE; | ||
| 206 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 207 | } | ||
| 208 | break; | ||
| 209 | |||
| 210 | case ACTION_LEDS_BRIGHT: | ||
| 211 | if(record->event.pressed) { | ||
| 212 | msg=(1 << 8) | STEP_BRIGHTNESS; | ||
| 213 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 214 | } | ||
| 215 | break; | ||
| 216 | |||
| 217 | case ACTION_LEDS_DIM: | ||
| 218 | if(record->event.pressed) { | ||
| 219 | msg=(0 << 8) | STEP_BRIGHTNESS; | ||
| 220 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 221 | } | ||
| 222 | break; | ||
| 223 | |||
| 224 | //set led_mode for matrix_scan to toggle leds | ||
| 225 | case ACTION_LEDS_SINGLE: | ||
| 226 | led_mode_global = MODE_SINGLE; | ||
| 227 | break; | ||
| 228 | case ACTION_LEDS_PAGE: | ||
| 229 | led_mode_global = MODE_PAGE; | ||
| 230 | break; | ||
| 231 | case ACTION_LEDS_FLASH: | ||
| 232 | led_mode_global = MODE_FLASH; | ||
| 233 | break; | ||
| 234 | |||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) | ||
| 239 | { | ||
| 240 | return MACRO_NONE; | ||
| 241 | }; | ||
| 242 | |||
| 243 | |||
| 244 | bool process_record_user (uint16_t keycode, keyrecord_t *record) { | ||
| 245 | return true; | ||
| 246 | } | ||
| 247 | |||
| 248 | // Runs just one time when the keyboard initializes. | ||
| 249 | void matrix_init_user(void) { | ||
| 250 | |||
| 251 | led_controller_init(); | ||
| 252 | |||
| 253 | // Write predefined led pages. | ||
| 254 | write_led_page(_NUMPAD, led_numpad, 16); | ||
| 255 | chThdSleepMilliseconds(10); | ||
| 256 | |||
| 257 | write_led_page(_FNAV, led_nav, 12); | ||
| 258 | chThdSleepMilliseconds(10); | ||
| 259 | |||
| 260 | write_led_page(_MEDIA, led_media, 15); | ||
| 261 | chThdSleepMilliseconds(10); | ||
| 262 | |||
| 263 | write_led_page(4, led_game, 5); | ||
| 264 | chThdSleepMilliseconds(1000); | ||
| 265 | }; | ||
| 266 | |||
| 267 | // Loops constantly in the background. | ||
| 268 | void matrix_scan_user(void) { | ||
| 269 | uint8_t page; | ||
| 270 | uint8_t led_pin_byte; | ||
| 271 | msg_t msg; | ||
| 272 | |||
| 273 | if (backlight_status_global == 0) {//backlight is off, skip the rest | ||
| 274 | return; | ||
| 275 | } | ||
| 276 | |||
| 277 | if (led_layer_state != layer_state && led_mode_global != GAME && led_mode_global != ALL) { | ||
| 278 | //check mode | ||
| 279 | //Turn on layer indicator or page depending on mode | ||
| 280 | switch(led_mode_global) { | ||
| 281 | case MODE_FLASH: //flash preset page leds then single indicator | ||
| 282 | page = biton32(layer_state) > max_pages ? 7 : biton32(layer_state); | ||
| 283 | msg=(page << 8) | DISPLAY_PAGE; | ||
| 284 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 285 | chThdSleepMilliseconds(500); | ||
| 286 | //flow to display single layer leds | ||
| 287 | |||
| 288 | case MODE_SINGLE: //light layer indicators for all active layers | ||
| 289 | led_pin_byte = layer_state & 0xFF; | ||
| 290 | msg=(7 << 8) | DISPLAY_PAGE; | ||
| 291 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 292 | msg=(1 << 16) | (led_pin_byte << 8) | SET_FULL_ROW; | ||
| 293 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 294 | break; | ||
| 295 | |||
| 296 | case MODE_PAGE: //display pre-defined led page | ||
| 297 | page = biton32(layer_state) > max_pages ? 7 : biton32(layer_state); | ||
| 298 | msg=(page << 8) | DISPLAY_PAGE; | ||
| 299 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 300 | break; | ||
| 301 | } | ||
| 302 | led_layer_state = layer_state; | ||
| 303 | } | ||
| 304 | } | ||
diff --git a/keyboards/infinity60/keymaps/jpetermans/readme.md b/keyboards/infinity60/keymaps/jpetermans/readme.md new file mode 100644 index 000000000..b83057ea7 --- /dev/null +++ b/keyboards/infinity60/keymaps/jpetermans/readme.md | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | Backlight for Infinity60 | ||
| 2 | ======================== | ||
| 3 | |||
| 4 | ## Led Controller Specs | ||
| 5 | |||
| 6 | 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. | ||
| 7 | |||
| 8 | Infinity60 LED Map: | ||
| 9 | digits mean "row" and "col", i.e. 45 means pin 4, column 5 in the IS31 datasheet | ||
| 10 | ```c | ||
| 11 | 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27* | ||
| 12 | 28 31 32 33 34 35 36 37 38 41 42 43 44 45 | ||
| 13 | 46 47 48 51 52 53 54 55 56 57 58 61 62 | ||
| 14 | 63 64 65 66 67 68 71 72 73 74 75 76 77* | ||
| 15 | 78 81 82 83 84 85 86 87 | ||
| 16 | ``` | ||
| 17 | *Unused in Alphabet Layout | ||
| 18 | |||
| 19 | The IS31 includes 8 led pages (or frames) 0-7 than can be displayed, and each page consists of 144 bytes. | ||
| 20 | - **bytes 0 - 17** - LED control (on/off). | ||
| 21 | * 18 pins which alternate between A and B matrices (A1, B1, A2, B2, ..). | ||
| 22 | * Each byte controls the 8 leds on that pin with bits (8 to 1). | ||
| 23 | - **bytes 8 - 35** - Blink control. | ||
| 24 | * Same as LED control above, but sets blink on/off. | ||
| 25 | - **bytes 36 - 143** - PWM control. | ||
| 26 | * One byte per LED, sets PWM from 0 to 255. | ||
| 27 | * Same as above, the register alternates, every 8 *bytes* (not bits) between the A & B matrices. | ||
| 28 | |||
| 29 | ## Led Controller Code | ||
| 30 | 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). | ||
| 31 | |||
| 32 | One function is available to directly set leds without the mailbox: | ||
| 33 | ``` | ||
| 34 | write_led_page(page#, array of leds by address, # of addresses in array) | ||
| 35 | ``` | ||
| 36 | This function saves a full page to the controller using a supplied array of led locations such as: | ||
| 37 | ```c | ||
| 38 | uint8_t led_numpad[16] = { | ||
| 39 | 18,21,22,23, | ||
| 40 | 37,38,41,42, | ||
| 41 | 55,56,57,58, | ||
| 42 | 72,73,74,75 | ||
| 43 | } | ||
| 44 | write_led_page(5, led_numpad, 16); | ||
| 45 | ``` | ||
| 46 | |||
| 47 | Remaining led control is done through the led mailbox using these message types: | ||
| 48 | - **SET_FULL_ROW** (3 bytes) - message type, 8-bit mask, and row#. Sets all leds on one pin per the bit mask. | ||
| 49 | - **OFF_LED, ON_LED, TOGGLE_LED** (3 bytes) - message type, led address, and page#. Off/on/toggle specific led. | ||
| 50 | - **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. | ||
| 51 | - **TOGGLE_ALL** (1 byte) - Turn on/off full backlight. | ||
| 52 | - **TOGGLE_BACKLIGHT** (2 bytes) - message type, on/off. Sets backlight completely off, no leds will display. | ||
| 53 | - **DISPLAY_PAGE** (2 bytes) - message type, page to display. Switch to specific pre-set page. | ||
| 54 | - **RESET_PAGE** (2 bytes) - message type, page to reset. Reset/erase specific page. | ||
| 55 | - **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). | ||
| 56 | - **TOGGLE_CAPS_LOCK** (2 bytes) - message type, on/off (CAPS_LOCK_LED_ADDRESS). Same as numlock. | ||
| 57 | - **STEP_BRIGHTNESS** (2 bytes) - message type, and step up (1) or step down (0). Increase or decrease led brightness. | ||
| 58 | |||
| 59 | ## Sending messages in Keymap.c | ||
| 60 | Sending an action to the led mailbox is done using chMBPost: | ||
| 61 | ``` | ||
| 62 | chMBPost(&led_mailbox, message, timeout); | ||
| 63 | ``` | ||
| 64 | - &led_mailbox - pointer to led mailbox | ||
| 65 | - 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. | ||
| 66 | - timeout is TIME_IMMEDIATE | ||
| 67 | |||
| 68 | An example: | ||
| 69 | ```c | ||
| 70 | //set the message to be sent. First byte (LSB) is the led address, and second is the message type | ||
| 71 | msg=(42 << 8) | ON_LED; | ||
| 72 | |||
| 73 | //send msg to the led mailbox | ||
| 74 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 75 | ``` | ||
| 76 | |||
| 77 | Another: | ||
| 78 | ```c | ||
| 79 | msg=(46 << 8) | BLINK_TOGGLE_LED; | ||
| 80 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 81 | ``` | ||
| 82 | |||
| 83 | Finally, SET_FULL_ROW requires an extra byte with row information in the message so sending this message looks like: | ||
| 84 | ```c | ||
| 85 | msg=(row<<16) | (led_pin_byte << 8) | SET_FULL_ROW; | ||
| 86 | chMBPost(&led_mailbox, msg, TIME_IMMEDIATE); | ||
| 87 | ``` | ||
diff --git a/keyboards/infinity60/led.c b/keyboards/infinity60/led.c index aed66c7c0..53147a78a 100644 --- a/keyboards/infinity60/led.c +++ b/keyboards/infinity60/led.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | Copyright 2012 Jun Wako <wakojun@gmail.com> | 2 | Copyright 2015 Jun Wako <wakojun@gmail.com> |
| 3 | 3 | ||
| 4 | This program is free software: you can redistribute it and/or modify | 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 | 5 | it under the terms of the GNU General Public License as published by |
| @@ -19,6 +19,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
| 19 | 19 | ||
| 20 | #include "led.h" | 20 | #include "led.h" |
| 21 | 21 | ||
| 22 | #include "led_controller.h" | ||
| 22 | 23 | ||
| 24 | /* WARNING! This function needs to be callable from | ||
| 25 | * both regular threads and ISRs, unlocked (during resume-from-sleep). | ||
| 26 | * In particular, I2C functions (interrupt-driven) should NOT be called from here. | ||
| 27 | */ | ||
| 23 | void led_set(uint8_t usb_led) { | 28 | void led_set(uint8_t usb_led) { |
| 29 | msg_t msg; | ||
| 30 | |||
| 31 | if (usb_led & (1<<USB_LED_NUM_LOCK)) { | ||
| 32 | chSysUnconditionalLock(); | ||
| 33 | msg=(1 << 8) | TOGGLE_NUM_LOCK; | ||
| 34 | chMBPostI(&led_mailbox, msg); | ||
| 35 | chSysUnconditionalUnlock(); | ||
| 36 | } else { | ||
| 37 | chSysUnconditionalLock(); | ||
| 38 | msg=(0 << 8) | TOGGLE_NUM_LOCK; | ||
| 39 | chMBPostI(&led_mailbox, msg); | ||
| 40 | chSysUnconditionalUnlock(); | ||
| 41 | } | ||
| 42 | if (usb_led & (1<<USB_LED_CAPS_LOCK)) { | ||
| 43 | chSysUnconditionalLock(); | ||
| 44 | msg=(1 << 8) | TOGGLE_CAPS_LOCK; | ||
| 45 | chMBPostI(&led_mailbox, msg); | ||
| 46 | chSysUnconditionalUnlock(); | ||
| 47 | } else { | ||
| 48 | chSysUnconditionalLock(); | ||
| 49 | msg=(0 << 8) | TOGGLE_CAPS_LOCK; | ||
| 50 | chMBPostI(&led_mailbox, msg); | ||
| 51 | chSysUnconditionalUnlock(); | ||
| 52 | } | ||
| 24 | } | 53 | } |
diff --git a/keyboards/infinity60/led_controller.c b/keyboards/infinity60/led_controller.c new file mode 100644 index 000000000..21f95a9c1 --- /dev/null +++ b/keyboards/infinity60/led_controller.c | |||
| @@ -0,0 +1,486 @@ | |||
| 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 "host.h" | ||
| 29 | |||
| 30 | #include "led_controller.h" | ||
| 31 | |||
| 32 | #include "suspend.h" | ||
| 33 | |||
| 34 | #include "usb_main.h" | ||
| 35 | |||
| 36 | /* Infinity60 LED MAP | ||
| 37 | - digits mean "row" and "col", i.e. 45 means C4-5 in the IS31 datasheet, matrix A | ||
| 38 | |||
| 39 | 11 12 13 14 15 16 17 18 21 22 23 24 25 26 27* | ||
| 40 | 28 31 32 33 34 35 36 37 38 41 42 43 44 45 | ||
| 41 | 46 47 48 51 52 53 54 55 56 57 58 61 62 | ||
| 42 | 63 64 65 66 67 68 71 72 73 74 75 76 77* | ||
| 43 | 78 81 82 83 84 85 86 87 | ||
| 44 | |||
| 45 | *Unused in Alphabet Layout | ||
| 46 | */ | ||
| 47 | |||
| 48 | /* | ||
| 49 | each page has 0xB4 bytes | ||
| 50 | 0 - 0x11: LED control (on/off): | ||
| 51 | order: CA1, CB1, CA2, CB2, .... (CA - matrix A, CB - matrix B) | ||
| 52 | CAn controls Cn-8 .. Cn-1 (LSbit) | ||
| 53 | 0x12 - 0x23: blink control (like "LED control") | ||
| 54 | 0x24 - 0xB3: PWM control: byte per LED, 0xFF max on | ||
| 55 | order same as above (CA 1st row (8bytes), CB 1st row (8bytes), ...) | ||
| 56 | */ | ||
| 57 | |||
| 58 | // Which LED should be used for CAPS LOCK indicator | ||
| 59 | #if !defined(CAPS_LOCK_LED_ADDRESS) | ||
| 60 | #define CAPS_LOCK_LED_ADDRESS 46 | ||
| 61 | #endif | ||
| 62 | |||
| 63 | #if !defined(NUM_LOCK_LED_ADDRESS) | ||
| 64 | #define NUM_LOCK_LED_ADDRESS 85 | ||
| 65 | #endif | ||
| 66 | |||
| 67 | /* Which LED should breathe during sleep */ | ||
| 68 | #if !defined(BREATHE_LED_ADDRESS) | ||
| 69 | #define BREATHE_LED_ADDRESS CAPS_LOCK_LED_ADDRESS | ||
| 70 | #endif | ||
| 71 | |||
| 72 | /* ================= | ||
| 73 | * ChibiOS I2C setup | ||
| 74 | * ================= */ | ||
| 75 | static const I2CConfig i2ccfg = { | ||
| 76 | 400000 // clock speed (Hz); 400kHz max for IS31 | ||
| 77 | }; | ||
| 78 | |||
| 79 | /* ============== | ||
| 80 | * variables | ||
| 81 | * ============== */ | ||
| 82 | // internal communication buffers | ||
| 83 | uint8_t tx[2] __attribute__((aligned(2))); | ||
| 84 | uint8_t rx[1] __attribute__((aligned(2))); | ||
| 85 | |||
| 86 | // buffer for sending the whole page at once (used also as a temp buffer) | ||
| 87 | uint8_t full_page[0xB4+1] = {0}; | ||
| 88 | |||
| 89 | // LED mask (which LEDs are present, selected by bits) | ||
| 90 | // IC60 pcb uses only CA matrix. | ||
| 91 | // Each byte is a control pin for 8 leds ordered 8-1 | ||
| 92 | const uint8_t all_on_leds_mask[0x12] = { | ||
| 93 | 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, | ||
| 94 | 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x7F, 0x00, 0x00, 0x00 | ||
| 95 | }; | ||
| 96 | |||
| 97 | // array to hold brightness pwm steps | ||
| 98 | const uint8_t pwm_levels[5] = { | ||
| 99 | 0x00, 0x16, 0x4E, 0xA1, 0xFF | ||
| 100 | }; | ||
| 101 | |||
| 102 | // array to write to pwm register | ||
| 103 | uint8_t pwm_register_array[9] = {0}; | ||
| 104 | |||
| 105 | |||
| 106 | /* ============================ | ||
| 107 | * communication functions | ||
| 108 | * ============================ */ | ||
| 109 | msg_t is31_select_page(uint8_t page) { | ||
| 110 | tx[0] = IS31_COMMANDREGISTER; | ||
| 111 | tx[1] = page; | ||
| 112 | return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, US2ST(IS31_TIMEOUT)); | ||
| 113 | } | ||
| 114 | |||
| 115 | msg_t is31_write_data(uint8_t page, uint8_t *buffer, uint8_t size) { | ||
| 116 | is31_select_page(page); | ||
| 117 | return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, buffer, size, NULL, 0, US2ST(IS31_TIMEOUT)); | ||
| 118 | } | ||
| 119 | |||
| 120 | msg_t is31_write_register(uint8_t page, uint8_t reg, uint8_t data) { | ||
| 121 | is31_select_page(page); | ||
| 122 | tx[0] = reg; | ||
| 123 | tx[1] = data; | ||
| 124 | return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 2, NULL, 0, US2ST(IS31_TIMEOUT)); | ||
| 125 | } | ||
| 126 | |||
| 127 | msg_t is31_read_register(uint8_t page, uint8_t reg, uint8_t *result) { | ||
| 128 | is31_select_page(page); | ||
| 129 | |||
| 130 | tx[0] = reg; | ||
| 131 | return i2cMasterTransmitTimeout(&I2CD1, IS31_ADDR_DEFAULT, tx, 1, result, 1, US2ST(IS31_TIMEOUT)); | ||
| 132 | } | ||
| 133 | |||
| 134 | /* ======================== | ||
| 135 | * initialise the IS31 chip | ||
| 136 | * ======================== */ | ||
| 137 | void is31_init(void) { | ||
| 138 | // just to be sure that it's all zeroes | ||
| 139 | __builtin_memset(full_page,0,0xB4+1); | ||
| 140 | // zero function page, all registers (assuming full_page is all zeroes) | ||
| 141 | is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1); | ||
| 142 | // disable hardware shutdown | ||
| 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, IS31_REG_SHUTDOWN_ON); | ||
| 148 | chThdSleepMilliseconds(10); | ||
| 149 | // zero function page, all registers | ||
| 150 | is31_write_data(IS31_FUNCTIONREG, full_page, 0xD + 1); | ||
| 151 | chThdSleepMilliseconds(10); | ||
| 152 | // software shutdown disable (i.e. turn stuff on) | ||
| 153 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF); | ||
| 154 | chThdSleepMilliseconds(10); | ||
| 155 | // zero all LED registers on all 8 pages | ||
| 156 | uint8_t i; | ||
| 157 | for(i=0; i<8; i++) { | ||
| 158 | is31_write_data(i, full_page, 0xB4 + 1); | ||
| 159 | chThdSleepMilliseconds(5); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | /* ================== | ||
| 164 | * LED control thread | ||
| 165 | * ================== */ | ||
| 166 | #define LED_MAILBOX_NUM_MSGS 5 | ||
| 167 | static msg_t led_mailbox_queue[LED_MAILBOX_NUM_MSGS]; | ||
| 168 | mailbox_t led_mailbox; | ||
| 169 | static THD_WORKING_AREA(waLEDthread, 256); | ||
| 170 | static THD_FUNCTION(LEDthread, arg) { | ||
| 171 | (void)arg; | ||
| 172 | chRegSetThreadName("LEDthread"); | ||
| 173 | |||
| 174 | uint8_t i; | ||
| 175 | uint8_t control_register_word[2] = {0};//2 bytes: register address, byte to write | ||
| 176 | uint8_t led_control_reg[0x13] = {0};//led control register start address + 0x12 bytes | ||
| 177 | |||
| 178 | //persistent status variables | ||
| 179 | uint8_t pwm_step_status, page_status, capslock_status, numlock_status; | ||
| 180 | |||
| 181 | //mailbox variables | ||
| 182 | uint8_t temp, msg_type; | ||
| 183 | uint8_t msg_args[3]; | ||
| 184 | msg_t msg; | ||
| 185 | |||
| 186 | // initialize persistent variables | ||
| 187 | pwm_step_status = 4; //full brightness | ||
| 188 | page_status = 0; //start frame 0 (all off/on) | ||
| 189 | numlock_status = (host_keyboard_leds() & (1<<USB_LED_NUM_LOCK)) ? 1 : 0; | ||
| 190 | capslock_status = (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) ? 1 : 0; | ||
| 191 | |||
| 192 | while(true) { | ||
| 193 | // wait for a message (asynchronous) | ||
| 194 | // (messages are queued (up to LED_MAILBOX_NUM_MSGS) if they can't | ||
| 195 | // be processed right away | ||
| 196 | chMBFetch(&led_mailbox, &msg, TIME_INFINITE); | ||
| 197 | msg_type = msg & 0xFF; //first byte is action information | ||
| 198 | msg_args[0] = (msg >> 8) & 0xFF; | ||
| 199 | msg_args[1] = (msg >> 16) & 0XFF; | ||
| 200 | msg_args[2] = (msg >> 24) & 0xFF; | ||
| 201 | |||
| 202 | |||
| 203 | switch (msg_type){ | ||
| 204 | case SET_FULL_ROW: | ||
| 205 | //write full byte to pin address, msg_args[1] = pin #, msg_args[0] = 8 bits to write | ||
| 206 | //writes only to currently displayed page | ||
| 207 | write_led_byte(page_status, msg_args[1], msg_args[0]); | ||
| 208 | break; | ||
| 209 | |||
| 210 | case OFF_LED: | ||
| 211 | //on/off/toggle single led, msg_args[0] = row/col of led, msg_args[1] = page | ||
| 212 | set_led_bit(msg_args[1], control_register_word, msg_args[0], 0); | ||
| 213 | break; | ||
| 214 | case ON_LED: | ||
| 215 | set_led_bit(msg_args[1], control_register_word, msg_args[0], 1); | ||
| 216 | break; | ||
| 217 | case TOGGLE_LED: | ||
| 218 | set_led_bit(msg_args[1], control_register_word, msg_args[0], 2); | ||
| 219 | break; | ||
| 220 | |||
| 221 | case BLINK_OFF_LED: | ||
| 222 | //on/off/toggle single led, msg_args[0] = row/col of led | ||
| 223 | set_led_bit(msg_args[1], control_register_word, msg_args[0], 4); | ||
| 224 | break; | ||
| 225 | case BLINK_ON_LED: | ||
| 226 | set_led_bit(msg_args[1], control_register_word, msg_args[0], 5); | ||
| 227 | break; | ||
| 228 | case BLINK_TOGGLE_LED: | ||
| 229 | set_led_bit(msg_args[1], control_register_word, msg_args[0], 6); | ||
| 230 | break; | ||
| 231 | |||
| 232 | case TOGGLE_ALL: | ||
| 233 | //turn on/off all leds, msg_args = unused | ||
| 234 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON); | ||
| 235 | chThdSleepMilliseconds(5); | ||
| 236 | is31_read_register(0, 0x00, &temp); | ||
| 237 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF); | ||
| 238 | |||
| 239 | led_control_reg[0] = 0; | ||
| 240 | |||
| 241 | //toggle led mask based on current state (temp) | ||
| 242 | if (temp==0 || page_status > 0) { | ||
| 243 | __builtin_memcpy(led_control_reg+1, all_on_leds_mask, 0x12); | ||
| 244 | } else { | ||
| 245 | __builtin_memset(led_control_reg+1, 0, 0x12); | ||
| 246 | } | ||
| 247 | is31_write_data(0, led_control_reg, 0x13); | ||
| 248 | |||
| 249 | if (page_status > 0) { | ||
| 250 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, 0); | ||
| 251 | |||
| 252 | page_status=0; | ||
| 253 | |||
| 254 | //maintain lock leds, reset to off and force recheck to blink of all leds toggled on | ||
| 255 | numlock_status = 0; | ||
| 256 | capslock_status = 0; | ||
| 257 | led_set(host_keyboard_leds()); | ||
| 258 | } | ||
| 259 | break; | ||
| 260 | |||
| 261 | case TOGGLE_BACKLIGHT: | ||
| 262 | //msg_args[0] = on/off | ||
| 263 | |||
| 264 | //populate 9 byte rows to be written to each pin, first byte is register (pin) address | ||
| 265 | if (msg_args[0] == 1) { | ||
| 266 | __builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8); | ||
| 267 | } else { | ||
| 268 | __builtin_memset(pwm_register_array+1, 0, 8); | ||
| 269 | } | ||
| 270 | |||
| 271 | for(i=0; i<8; i++) { | ||
| 272 | //first byte is register address, every 0x10 9 bytes is A-matrix pwm pins | ||
| 273 | pwm_register_array[0] = 0x24 + (i * 0x10); | ||
| 274 | is31_write_data(0,pwm_register_array,9); | ||
| 275 | } | ||
| 276 | break; | ||
| 277 | |||
| 278 | case DISPLAY_PAGE: | ||
| 279 | //msg_args[0] = page to toggle on | ||
| 280 | if (page_status != msg_args[0]) { | ||
| 281 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_PICTDISP, msg_args[0]); | ||
| 282 | page_status = msg_args[0]; | ||
| 283 | |||
| 284 | //maintain lock leds, reset to off and force recheck for new page | ||
| 285 | numlock_status = 0; | ||
| 286 | capslock_status = 0; | ||
| 287 | led_set(host_keyboard_leds()); | ||
| 288 | } | ||
| 289 | break; | ||
| 290 | |||
| 291 | case RESET_PAGE: | ||
| 292 | //led_args[0] = page to reset | ||
| 293 | led_control_reg[0] = 0; | ||
| 294 | __builtin_memset(led_control_reg+1, 0, 0x12); | ||
| 295 | is31_write_data(msg_args[0], led_control_reg, 0x13); | ||
| 296 | |||
| 297 | //repeat for blink register | ||
| 298 | led_control_reg[0] = 0x12; | ||
| 299 | is31_write_data(msg_args[0], led_control_reg, 0x13); | ||
| 300 | break; | ||
| 301 | |||
| 302 | case TOGGLE_NUM_LOCK: | ||
| 303 | //msg_args[0] = 0 or 1, off/on | ||
| 304 | if (numlock_status != msg_args[0]) { | ||
| 305 | set_lock_leds(NUM_LOCK_LED_ADDRESS, msg_args[0], page_status); | ||
| 306 | numlock_status = msg_args[0]; | ||
| 307 | } | ||
| 308 | break; | ||
| 309 | case TOGGLE_CAPS_LOCK: | ||
| 310 | //msg_args[0] = 0 or 1, off/on | ||
| 311 | if (capslock_status != msg_args[0]) { | ||
| 312 | set_lock_leds(CAPS_LOCK_LED_ADDRESS, msg_args[0], page_status); | ||
| 313 | capslock_status = msg_args[0]; | ||
| 314 | } | ||
| 315 | break; | ||
| 316 | |||
| 317 | case STEP_BRIGHTNESS: | ||
| 318 | //led_args[0] = step up (1) or down (0) | ||
| 319 | switch (msg_args[0]) { | ||
| 320 | case 0: | ||
| 321 | if (pwm_step_status == 0) { | ||
| 322 | pwm_step_status = 4; | ||
| 323 | } else { | ||
| 324 | pwm_step_status--; | ||
| 325 | } | ||
| 326 | break; | ||
| 327 | |||
| 328 | case 1: | ||
| 329 | if (pwm_step_status == 4) { | ||
| 330 | pwm_step_status = 0; | ||
| 331 | } else { | ||
| 332 | pwm_step_status++; | ||
| 333 | } | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | |||
| 337 | //populate 8 byte arrays to write on each pin | ||
| 338 | //first byte is register address, every 0x10 9 bytes are A-matrix pwm pins | ||
| 339 | __builtin_memset(pwm_register_array+1, pwm_levels[pwm_step_status], 8); | ||
| 340 | |||
| 341 | for(i=0; i<8; i++) { | ||
| 342 | pwm_register_array[0] = 0x24 + (i * 0x10); | ||
| 343 | is31_write_data(0,pwm_register_array,9); | ||
| 344 | } | ||
| 345 | break; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | /* ============================== | ||
| 351 | * led processing functions | ||
| 352 | * ============================== */ | ||
| 353 | |||
| 354 | void set_led_bit (uint8_t page, uint8_t *led_control_word, uint8_t led_addr, uint8_t action) { | ||
| 355 | //returns 2 bytes: led control register address and byte to write | ||
| 356 | //action: 0 - off, 1 - on, 2 - toggle, 4 - blink on, 5 - blink off, 6 - toggle blink | ||
| 357 | |||
| 358 | uint8_t control_reg_addr, column_bit, column_byte, temp, blink_bit; | ||
| 359 | |||
| 360 | //check for valid led address | ||
| 361 | if (led_addr < 0 || led_addr > 87 || led_addr % 10 > 8) { | ||
| 362 | return; | ||
| 363 | } | ||
| 364 | |||
| 365 | blink_bit = action>>2;//check for blink bit | ||
| 366 | action &= ~(1<<2); //strip blink bit | ||
| 367 | |||
| 368 | //led_addr tens column is pin#, ones column is bit position in 8-bit mask | ||
| 369 | control_reg_addr = ((led_addr / 10) % 10 - 1 ) * 0x02;// A-matrix is every other byte | ||
| 370 | control_reg_addr += blink_bit == 1 ? 0x12 : 0x00;//if blink_bit, shift 12 bytes to blink register | ||
| 371 | |||
| 372 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON); | ||
| 373 | chThdSleepMilliseconds(5); | ||
| 374 | is31_read_register(page, control_reg_addr, &temp);//maintain status of leds on this byte | ||
| 375 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF); | ||
| 376 | |||
| 377 | column_bit = 1<<(led_addr % 10 - 1); | ||
| 378 | column_byte = temp; | ||
| 379 | |||
| 380 | switch(action) { | ||
| 381 | case 0: | ||
| 382 | column_byte &= ~column_bit; | ||
| 383 | break; | ||
| 384 | case 1: | ||
| 385 | column_byte |= column_bit; | ||
| 386 | break; | ||
| 387 | case 2: | ||
| 388 | column_byte ^= column_bit; | ||
| 389 | break; | ||
| 390 | } | ||
| 391 | |||
| 392 | //return word to be written in register | ||
| 393 | led_control_word[0] = control_reg_addr; | ||
| 394 | led_control_word[1] = column_byte; | ||
| 395 | is31_write_data (page, led_control_word, 0x02); | ||
| 396 | } | ||
| 397 | |||
| 398 | void write_led_byte (uint8_t page, uint8_t row, uint8_t led_byte) { | ||
| 399 | uint8_t led_control_word[2] = {0};//register address and on/off byte | ||
| 400 | |||
| 401 | led_control_word[0] = (row - 1 ) * 0x02;// A-matrix is every other byte | ||
| 402 | led_control_word[1] = led_byte; | ||
| 403 | is31_write_data(page, led_control_word, 0x02); | ||
| 404 | } | ||
| 405 | |||
| 406 | void write_led_page (uint8_t page, uint8_t *user_led_array, uint8_t led_count) { | ||
| 407 | uint8_t i; | ||
| 408 | uint8_t pin, col; | ||
| 409 | uint8_t led_control_register[0x13] = {0}; | ||
| 410 | |||
| 411 | __builtin_memset(led_control_register,0,13); | ||
| 412 | |||
| 413 | for(i=0;i<led_count;i++){ | ||
| 414 | //shift pin by 1 for led register 0x00 address | ||
| 415 | pin = ((user_led_array[i] / 10) % 10 - 1 ) * 2 + 1; | ||
| 416 | col = user_led_array[i] % 10 - 1; | ||
| 417 | led_control_register[pin] |= 1<<(col); | ||
| 418 | } | ||
| 419 | |||
| 420 | is31_write_data(page, led_control_register, 0x13); | ||
| 421 | } | ||
| 422 | |||
| 423 | void set_lock_leds(uint8_t led_addr, uint8_t led_action, uint8_t page) { | ||
| 424 | uint8_t temp; | ||
| 425 | uint8_t led_control_word[2] = {0}; | ||
| 426 | |||
| 427 | //blink if all leds are on | ||
| 428 | if (page == 0) { | ||
| 429 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_ON); | ||
| 430 | chThdSleepMilliseconds(5); | ||
| 431 | is31_read_register(0, 0x00, &temp); | ||
| 432 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_SHUTDOWN, IS31_REG_SHUTDOWN_OFF); | ||
| 433 | |||
| 434 | if (temp == 0xFF) { | ||
| 435 | led_action |= (1<<2); //set blink bit | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | set_led_bit(page,led_control_word,led_addr,led_action); | ||
| 440 | } | ||
| 441 | |||
| 442 | /* ===================== | ||
| 443 | * hook into user keymap | ||
| 444 | * ===================== */ | ||
| 445 | void led_controller_init(void) { | ||
| 446 | uint8_t i; | ||
| 447 | |||
| 448 | /* initialise I2C */ | ||
| 449 | /* I2C pins */ | ||
| 450 | palSetPadMode(GPIOB, 0, PAL_MODE_ALTERNATIVE_2); // PTB0/I2C0/SCL | ||
| 451 | palSetPadMode(GPIOB, 1, PAL_MODE_ALTERNATIVE_2); // PTB1/I2C0/SDA | ||
| 452 | /* start I2C */ | ||
| 453 | i2cStart(&I2CD1, &i2ccfg); | ||
| 454 | // try high drive (from kiibohd) | ||
| 455 | I2CD1.i2c->C2 |= I2Cx_C2_HDRS; | ||
| 456 | // try glitch fixing (from kiibohd) | ||
| 457 | I2CD1.i2c->FLT = 4; | ||
| 458 | |||
| 459 | chThdSleepMilliseconds(10); | ||
| 460 | |||
| 461 | /* initialise IS31 chip */ | ||
| 462 | is31_init(); | ||
| 463 | |||
| 464 | //set Display Option Register so all pwm intensity is controlled from page 0 | ||
| 465 | //enable blink and set blink period to 0.27s x rate | ||
| 466 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_DISPLAYOPT, IS31_REG_DISPLAYOPT_INTENSITY_SAME + IS31_REG_DISPLAYOPT_BLINK_ENABLE + 4); | ||
| 467 | |||
| 468 | /* set full pwm on page 1 */ | ||
| 469 | pwm_register_array[0] = 0; | ||
| 470 | __builtin_memset(pwm_register_array+1, 0xFF, 8); | ||
| 471 | for(i=0; i<8; i++) { | ||
| 472 | pwm_register_array[0] = 0x24 + (i * 0x10);//first byte of 9 bytes must be register address | ||
| 473 | is31_write_data(0, pwm_register_array, 9); | ||
| 474 | chThdSleepMilliseconds(5); | ||
| 475 | } | ||
| 476 | |||
| 477 | /* enable breathing when the displayed page changes */ | ||
| 478 | // Fade-in Fade-out, time = 26ms * 2^N, N=3 | ||
| 479 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL1, (3<<4)|3); | ||
| 480 | is31_write_register(IS31_FUNCTIONREG, IS31_REG_BREATHCTRL2, IS31_REG_BREATHCTRL2_ENABLE|3); | ||
| 481 | |||
| 482 | /* more time consuming LED processing should be offloaded into | ||
| 483 | * a thread, with asynchronous messaging. */ | ||
| 484 | chMBObjectInit(&led_mailbox, led_mailbox_queue, LED_MAILBOX_NUM_MSGS); | ||
| 485 | chThdCreateStatic(waLEDthread, sizeof(waLEDthread), LOWPRIO, LEDthread, NULL); | ||
| 486 | } | ||
diff --git a/keyboards/infinity60/led_controller.h b/keyboards/infinity60/led_controller.h new file mode 100644 index 000000000..eb6060f26 --- /dev/null +++ b/keyboards/infinity60/led_controller.h | |||
| @@ -0,0 +1,120 @@ | |||
| 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 | #ifndef _LED_CONTROLLER_H_ | ||
| 19 | #define _LED_CONTROLLER_H_ | ||
| 20 | |||
| 21 | /* ========================= | ||
| 22 | * communication functions | ||
| 23 | * ========================= */ | ||
| 24 | |||
| 25 | msg_t is31_write_data(uint8_t page, uint8_t *buffer, uint8_t size); | ||
| 26 | msg_t is31_write_register(uint8_t page, uint8_t reg, uint8_t data); | ||
| 27 | msg_t is31_read_register(uint8_t page, uint8_t reg, uint8_t *result); | ||
| 28 | |||
| 29 | /* ============================ | ||
| 30 | * init functions/definitions | ||
| 31 | * ============================*/ | ||
| 32 | |||
| 33 | void led_controller_init(void); | ||
| 34 | |||
| 35 | #define CAPS_LOCK_LED_ADDRESS 46 //pin matrix location | ||
| 36 | #define NUM_LOCK_LED_ADDRESS 85 | ||
| 37 | |||
| 38 | /* ============================= | ||
| 39 | * IS31 chip related definitions | ||
| 40 | * ============================= */ | ||
| 41 | |||
| 42 | #define IS31_ADDR_DEFAULT 0x74 | ||
| 43 | |||
| 44 | #define IS31_REG_CONFIG 0x00 | ||
| 45 | // bits in reg | ||
| 46 | #define IS31_REG_CONFIG_PICTUREMODE 0x00 | ||
| 47 | #define IS31_REG_CONFIG_AUTOPLAYMODE 0x08 | ||
| 48 | #define IS31_REG_CONFIG_AUDIOPLAYMODE 0x18 | ||
| 49 | // D2:D0 bits are starting frame for autoplay mode | ||
| 50 | |||
| 51 | #define IS31_REG_PICTDISP 0x01 // D2:D0 frame select for picture mode | ||
| 52 | |||
| 53 | #define IS31_REG_AUTOPLAYCTRL1 0x02 | ||
| 54 | // D6:D4 number of loops (000=infty) | ||
| 55 | // D2:D0 number of frames to be used | ||
| 56 | |||
| 57 | #define IS31_REG_AUTOPLAYCTRL2 0x03 // D5:D0 delay time (*11ms) | ||
| 58 | |||
| 59 | #define IS31_REG_DISPLAYOPT 0x05 | ||
| 60 | #define IS31_REG_DISPLAYOPT_INTENSITY_SAME 0x20 // same intensity for all frames | ||
| 61 | #define IS31_REG_DISPLAYOPT_BLINK_ENABLE 0x08 | ||
| 62 | // D2:D0 bits blink period time (*0.27s) | ||
| 63 | |||
| 64 | #define IS31_REG_AUDIOSYNC 0x06 | ||
| 65 | #define IS31_REG_AUDIOSYNC_ENABLE 0x1 | ||
| 66 | |||
| 67 | #define IS31_REG_FRAMESTATE 0x07 | ||
| 68 | |||
| 69 | #define IS31_REG_BREATHCTRL1 0x08 | ||
| 70 | // D6:D4 fade out time (26ms*2^i) | ||
| 71 | // D2:D0 fade in time (26ms*2^i) | ||
| 72 | |||
| 73 | #define IS31_REG_BREATHCTRL2 0x09 | ||
| 74 | #define IS31_REG_BREATHCTRL2_ENABLE 0x10 | ||
| 75 | // D2:D0 extinguish time (3.5ms*2^i) | ||
| 76 | |||
| 77 | #define IS31_REG_SHUTDOWN 0x0A | ||
| 78 | #define IS31_REG_SHUTDOWN_OFF 0x1 | ||
| 79 | #define IS31_REG_SHUTDOWN_ON 0x0 | ||
| 80 | |||
| 81 | #define IS31_REG_AGCCTRL 0x0B | ||
| 82 | #define IS31_REG_ADCRATE 0x0C | ||
| 83 | |||
| 84 | #define IS31_COMMANDREGISTER 0xFD | ||
| 85 | #define IS31_FUNCTIONREG 0x0B // helpfully called 'page nine' | ||
| 86 | |||
| 87 | #define IS31_TIMEOUT 10000 // needs to be long enough to write a whole page | ||
| 88 | |||
| 89 | /* ======================================== | ||
| 90 | * LED Thread related items | ||
| 91 | * ========================================*/ | ||
| 92 | |||
| 93 | extern mailbox_t led_mailbox; | ||
| 94 | |||
| 95 | void set_led_bit (uint8_t page, uint8_t *led_control_reg, uint8_t led_addr, uint8_t action); | ||
| 96 | void set_lock_leds (uint8_t led_addr, uint8_t led_action, uint8_t page); | ||
| 97 | void write_led_byte (uint8_t page, uint8_t row, uint8_t led_byte); | ||
| 98 | void write_led_page (uint8_t page, uint8_t *led_array, uint8_t led_count); | ||
| 99 | |||
| 100 | // constants for signaling the LED controller thread | ||
| 101 | enum led_msg_t { | ||
| 102 | KEY_LIGHT, | ||
| 103 | SET_FULL_ROW, | ||
| 104 | OFF_LED, | ||
| 105 | ON_LED, | ||
| 106 | TOGGLE_LED, | ||
| 107 | BLINK_OFF_LED, | ||
| 108 | BLINK_ON_LED, | ||
| 109 | BLINK_TOGGLE_LED, | ||
| 110 | TOGGLE_ALL, | ||
| 111 | TOGGLE_BACKLIGHT, | ||
| 112 | DISPLAY_PAGE, | ||
| 113 | RESET_PAGE, | ||
| 114 | TOGGLE_NUM_LOCK, | ||
| 115 | TOGGLE_CAPS_LOCK, | ||
| 116 | TOGGLE_BREATH, | ||
| 117 | STEP_BRIGHTNESS | ||
| 118 | }; | ||
| 119 | |||
| 120 | #endif /* _LED_CONTROLLER_H_ */ | ||
diff --git a/keyboards/infinity60/mcuconf.h b/keyboards/infinity60/mcuconf.h index f453304b7..6af85d079 100644 --- a/keyboards/infinity60/mcuconf.h +++ b/keyboards/infinity60/mcuconf.h | |||
| @@ -47,9 +47,12 @@ | |||
| 47 | * USB driver settings | 47 | * USB driver settings |
| 48 | */ | 48 | */ |
| 49 | #define KINETIS_USB_USE_USB0 TRUE | 49 | #define KINETIS_USB_USE_USB0 TRUE |
| 50 | /* Need to redefine this, since the default is for K20x */ | 50 | #define KINETIS_USB_USB0_IRQ_PRIORITY 5 |
| 51 | /* This is for Teensy LC; you should comment it out (or change to 5) | 51 | |
| 52 | * for Teensy 3.x */ | 52 | /* |
| 53 | #define KINETIS_USB_USB0_IRQ_PRIORITY 2 | 53 | * I2C driver settings |
| 54 | */ | ||
| 55 | #define KINETIS_I2C_USE_I2C0 TRUE | ||
| 56 | #define KINETIS_I2C_I2C0_PRIORITY 4 | ||
| 54 | 57 | ||
| 55 | #endif /* _MCUCONF_H_ */ | 58 | #endif /* _MCUCONF_H_ */ |
diff --git a/keyboards/infinity60/rules.mk b/keyboards/infinity60/rules.mk index 56d6470b5..c19f62401 100644 --- a/keyboards/infinity60/rules.mk +++ b/keyboards/infinity60/rules.mk | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | # project specific files | 1 | # project specific files |
| 2 | SRC = matrix.c \ | 2 | SRC = matrix.c \ |
| 3 | led.c | 3 | led.c \ |
| 4 | led_controller.c | ||
| 4 | 5 | ||
| 5 | ## chip/board settings | 6 | ## chip/board settings |
| 6 | # - the next two should match the directories in | 7 | # - the next two should match the directories in |
| @@ -55,7 +56,7 @@ OPT_DEFS = -DCORTEX_VTOR_INIT=0x00001000 | |||
| 55 | # Build Options | 56 | # Build Options |
| 56 | # comment out to disable the options. | 57 | # comment out to disable the options. |
| 57 | # | 58 | # |
| 58 | BOOTMAGIC_ENABLE ?= yes # Virtual DIP switch configuration | 59 | BOOTMAGIC_ENABLE ?= no # Virtual DIP switch configuration |
| 59 | ## (Note that for BOOTMAGIC on Teensy LC you have to use a custom .ld script.) | 60 | ## (Note that for BOOTMAGIC on Teensy LC you have to use a custom .ld script.) |
| 60 | MOUSEKEY_ENABLE ?= yes # Mouse keys | 61 | MOUSEKEY_ENABLE ?= yes # Mouse keys |
| 61 | EXTRAKEY_ENABLE ?= yes # Audio control and System control | 62 | EXTRAKEY_ENABLE ?= yes # Audio control and System control |
| @@ -63,4 +64,4 @@ CONSOLE_ENABLE ?= yes # Console for debug | |||
| 63 | COMMAND_ENABLE ?= yes # Commands for debug and configuration | 64 | COMMAND_ENABLE ?= yes # Commands for debug and configuration |
| 64 | SLEEP_LED_ENABLE ?= yes # Breathing sleep LED during USB suspend | 65 | SLEEP_LED_ENABLE ?= yes # Breathing sleep LED during USB suspend |
| 65 | NKRO_ENABLE ?= yes # USB Nkey Rollover | 66 | NKRO_ENABLE ?= yes # USB Nkey Rollover |
| 66 | CUSTOM_MATRIX ?= yes # Custom matrix file \ No newline at end of file | 67 | CUSTOM_MATRIX ?= yes # Custom matrix file |
