Commit | Line | Data |
---|---|---|
a074364c | 1 | /* |
aaa758f1 | 2 | Copyright 2011, 2012, 2013 Jun Wako <wakojun@gmail.com> |
a074364c | 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 | */ | |
06d21009 | 17 | |
a074364c | 18 | #include <stdint.h> |
19 | #include "keyboard.h" | |
20 | #include "matrix.h" | |
21 | #include "keymap.h" | |
22 | #include "host.h" | |
23 | #include "led.h" | |
24 | #include "keycode.h" | |
25 | #include "timer.h" | |
26 | #include "print.h" | |
27 | #include "debug.h" | |
28 | #include "command.h" | |
29 | #include "util.h" | |
30 | #include "sendchar.h" | |
aaa758f1 | 31 | #include "eeconfig.h" |
07d0d5cb | 32 | #include "action_layer.h" |
abfd6ed9 JC |
33 | #ifdef BACKLIGHT_ENABLE |
34 | # include "backlight.h" | |
35 | #endif | |
ab19ebd0 | 36 | #ifdef BOOTMAGIC_ENABLE |
b624f32f | 37 | # include "bootmagic.h" |
ab19ebd0 | 38 | #else |
b624f32f | 39 | # include "magic.h" |
ab19ebd0 | 40 | #endif |
a074364c | 41 | #ifdef MOUSEKEY_ENABLE |
b624f32f | 42 | # include "mousekey.h" |
a074364c | 43 | #endif |
44 | #ifdef PS2_MOUSE_ENABLE | |
b624f32f | 45 | # include "ps2_mouse.h" |
a074364c | 46 | #endif |
47 | #ifdef SERIAL_MOUSE_ENABLE | |
b624f32f | 48 | # include "serial_mouse.h" |
a074364c | 49 | #endif |
4d116a04 | 50 | #ifdef ADB_MOUSE_ENABLE |
b624f32f | 51 | # include "adb.h" |
4d116a04 | 52 | #endif |
69557190 | 53 | #ifdef RGBLIGHT_ENABLE |
b624f32f | 54 | # include "rgblight.h" |
69557190 | 55 | #endif |
f30f12ec | 56 | #ifdef STENO_ENABLE |
b624f32f | 57 | # include "process_steno.h" |
f30f12ec | 58 | #endif |
c68e596f | 59 | #ifdef FAUXCLICKY_ENABLE |
b624f32f | 60 | # include "fauxclicky.h" |
c68e596f | 61 | #endif |
4b45deb6 | 62 | #ifdef SERIAL_LINK_ENABLE |
b624f32f | 63 | # include "serial_link/system/serial_link.h" |
4b45deb6 | 64 | #endif |
07d0d5cb | 65 | #ifdef VISUALIZER_ENABLE |
b624f32f | 66 | # include "visualizer/visualizer.h" |
07d0d5cb | 67 | #endif |
ee132284 | 68 | #ifdef POINTING_DEVICE_ENABLE |
b624f32f | 69 | # include "pointing_device.h" |
ee132284 | 70 | #endif |
53ff8a31 | 71 | #ifdef MIDI_ENABLE |
b624f32f | 72 | # include "process_midi.h" |
53ff8a31 | 73 | #endif |
bbea9dad | 74 | #ifdef HD44780_ENABLE |
b624f32f | 75 | # include "hd44780.h" |
bbea9dad | 76 | #endif |
4099536c | 77 | #ifdef QWIIC_ENABLE |
b624f32f | 78 | # include "qwiic.h" |
4099536c | 79 | #endif |
e01b2d51 | 80 | #ifdef OLED_DRIVER_ENABLE |
b624f32f | 81 | # include "oled_driver.h" |
e01b2d51 | 82 | #endif |
c1c5922a | 83 | #ifdef VELOCIKEY_ENABLE |
b624f32f | 84 | # include "velocikey.h" |
c1c5922a | 85 | #endif |
320822d7 W |
86 | #ifdef VIA_ENABLE |
87 | # include "via.h" | |
88 | #endif | |
a074364c | 89 | |
cc5edb9e JC |
90 | // Only enable this if console is enabled to print to |
91 | #if defined(DEBUG_MATRIX_SCAN_RATE) && defined(CONSOLE_ENABLE) | |
92 | static uint32_t matrix_timer = 0; | |
93 | static uint32_t matrix_scan_count = 0; | |
94 | ||
95 | void matrix_scan_perf_task(void) { | |
96 | matrix_scan_count++; | |
97 | ||
98 | uint32_t timer_now = timer_read32(); | |
99 | if (TIMER_DIFF_32(timer_now, matrix_timer) > 1000) { | |
100 | dprintf("matrix scan frequency: %d\n", matrix_scan_count); | |
101 | ||
102 | matrix_timer = timer_now; | |
103 | matrix_scan_count = 0; | |
104 | } | |
105 | } | |
106 | #else | |
107 | # define matrix_scan_perf_task() | |
108 | #endif | |
109 | ||
a074364c | 110 | #ifdef MATRIX_HAS_GHOST |
37f6f927 | 111 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; |
b624f32f | 112 | static matrix_row_t get_real_keys(uint8_t row, matrix_row_t rowdata) { |
37f6f927 | 113 | matrix_row_t out = 0; |
25c6ca75 | 114 | for (uint8_t col = 0; col < MATRIX_COLS; col++) { |
b624f32f | 115 | // read each key in the row data and check if the keymap defines it as a real key |
116 | if (pgm_read_byte(&keymaps[0][row][col]) && (rowdata & (1 << col))) { | |
117 | // this creates new row data, if a key is defined in the keymap, it will be set here | |
118 | out |= 1 << col; | |
37f6f927 J |
119 | } |
120 | } | |
121 | return out; | |
122 | } | |
123 | ||
b624f32f | 124 | static inline bool popcount_more_than_one(matrix_row_t rowdata) { |
125 | rowdata &= rowdata - 1; // if there are less than two bits (keys) set, rowdata will become zero | |
25c6ca75 | 126 | return rowdata; |
b9895771 | 127 | } |
63d9698d | 128 | |
b624f32f | 129 | static inline bool has_ghost_in_row(uint8_t row, matrix_row_t rowdata) { |
849ed5a6 J |
130 | /* No ghost exists when less than 2 keys are down on the row. |
131 | If there are "active" blanks in the matrix, the key can't be pressed by the user, | |
132 | there is no doubt as to which keys are really being pressed. | |
133 | The ghosts will be ignored, they are KC_NO. */ | |
25c6ca75 | 134 | rowdata = get_real_keys(row, rowdata); |
b624f32f | 135 | if ((popcount_more_than_one(rowdata)) == 0) { |
25c6ca75 J |
136 | return false; |
137 | } | |
138 | /* Ghost occurs when the row shares a column line with other row, | |
139 | and two columns are read on each row. Blanks in the matrix don't matter, | |
140 | so they are filtered out. | |
141 | If there are two or more real keys pressed and they match columns with | |
142 | at least two of another row's real keys, the row will be ignored. Keep in mind, | |
143 | we are checking one row at a time, not all of them at once. | |
144 | */ | |
b624f32f | 145 | for (uint8_t i = 0; i < MATRIX_ROWS; i++) { |
146 | if (i != row && popcount_more_than_one(get_real_keys(i, matrix_get_row(i)) & rowdata)) { | |
8e88d55b | 147 | return true; |
849ed5a6 | 148 | } |
a074364c | 149 | } |
150 | return false; | |
151 | } | |
99877cdf | 152 | |
a074364c | 153 | #endif |
154 | ||
a5fa75fc | 155 | void disable_jtag(void) { |
f2c179de | 156 | // To use PF4-7 (PC2-5 on ATmega32A), disable JTAG by writing JTD bit twice within four cycles. |
b624f32f | 157 | #if (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) |
a5fa75fc DN |
158 | MCUCR |= _BV(JTD); |
159 | MCUCR |= _BV(JTD); | |
f2c179de | 160 | #elif defined(__AVR_ATmega32A__) |
161 | MCUCSR |= _BV(JTD); | |
162 | MCUCSR |= _BV(JTD); | |
a5fa75fc DN |
163 | #endif |
164 | } | |
165 | ||
7c9d5ace | 166 | /** \brief matrix_setup |
167 | * | |
168 | * FIXME: needs doc | |
169 | */ | |
b624f32f | 170 | __attribute__((weak)) void matrix_setup(void) {} |
a074364c | 171 | |
cc5c6b44 DJ |
172 | /** \brief keyboard_pre_init_user |
173 | * | |
174 | * FIXME: needs doc | |
175 | */ | |
b624f32f | 176 | __attribute__((weak)) void keyboard_pre_init_user(void) {} |
cc5c6b44 DJ |
177 | |
178 | /** \brief keyboard_pre_init_kb | |
179 | * | |
180 | * FIXME: needs doc | |
181 | */ | |
b624f32f | 182 | __attribute__((weak)) void keyboard_pre_init_kb(void) { keyboard_pre_init_user(); } |
cc5c6b44 DJ |
183 | |
184 | /** \brief keyboard_post_init_user | |
185 | * | |
186 | * FIXME: needs doc | |
187 | */ | |
188 | ||
b624f32f | 189 | __attribute__((weak)) void keyboard_post_init_user() {} |
cc5c6b44 DJ |
190 | |
191 | /** \brief keyboard_post_init_kb | |
192 | * | |
193 | * FIXME: needs doc | |
194 | */ | |
195 | ||
b624f32f | 196 | __attribute__((weak)) void keyboard_post_init_kb(void) { keyboard_post_init_user(); } |
cc5c6b44 | 197 | |
7c9d5ace | 198 | /** \brief keyboard_setup |
199 | * | |
200 | * FIXME: needs doc | |
201 | */ | |
aaa758f1 | 202 | void keyboard_setup(void) { |
f2c179de | 203 | #ifndef NO_JTAG_DISABLE |
a5fa75fc | 204 | disable_jtag(); |
f2c179de | 205 | #endif |
6b588eb7 | 206 | matrix_setup(); |
cc5c6b44 | 207 | keyboard_pre_init_kb(); |
6b588eb7 | 208 | } |
209 | ||
7c9d5ace | 210 | /** \brief is_keyboard_master |
211 | * | |
212 | * FIXME: needs doc | |
213 | */ | |
b624f32f | 214 | __attribute__((weak)) bool is_keyboard_master(void) { return true; } |
25285a1c | 215 | |
7c9d5ace | 216 | /** \brief keyboard_init |
217 | * | |
218 | * FIXME: needs doc | |
219 | */ | |
aaa758f1 | 220 | void keyboard_init(void) { |
a074364c | 221 | timer_init(); |
222 | matrix_init(); | |
320822d7 W |
223 | #ifdef VIA_ENABLE |
224 | via_init(); | |
225 | #endif | |
4099536c | 226 | #ifdef QWIIC_ENABLE |
227 | qwiic_init(); | |
228 | #endif | |
e01b2d51 X |
229 | #ifdef OLED_DRIVER_ENABLE |
230 | oled_init(OLED_ROTATION_0); | |
231 | #endif | |
a074364c | 232 | #ifdef PS2_MOUSE_ENABLE |
233 | ps2_mouse_init(); | |
234 | #endif | |
235 | #ifdef SERIAL_MOUSE_ENABLE | |
236 | serial_mouse_init(); | |
237 | #endif | |
4d116a04 | 238 | #ifdef ADB_MOUSE_ENABLE |
239 | adb_mouse_init(); | |
240 | #endif | |
a074364c | 241 | #ifdef BOOTMAGIC_ENABLE |
242 | bootmagic(); | |
ab19ebd0 JH |
243 | #else |
244 | magic(); | |
a074364c | 245 | #endif |
a074364c | 246 | #ifdef BACKLIGHT_ENABLE |
247 | backlight_init(); | |
248 | #endif | |
69557190 ET |
249 | #ifdef RGBLIGHT_ENABLE |
250 | rgblight_init(); | |
251 | #endif | |
f30f12ec JW |
252 | #ifdef STENO_ENABLE |
253 | steno_init(); | |
254 | #endif | |
c68e596f PIN |
255 | #ifdef FAUXCLICKY_ENABLE |
256 | fauxclicky_init(); | |
257 | #endif | |
ee132284 S |
258 | #ifdef POINTING_DEVICE_ENABLE |
259 | pointing_device_init(); | |
260 | #endif | |
1d13aa93 | 261 | #if defined(NKRO_ENABLE) && defined(FORCE_NKRO) |
558f3ec1 | 262 | keymap_config.nkro = 1; |
efb21c00 | 263 | eeconfig_update_keymap(keymap_config.raw); |
577971ab | 264 | #endif |
cc5c6b44 | 265 | keyboard_post_init_kb(); /* Always keep this last */ |
a074364c | 266 | } |
267 | ||
7c9d5ace | 268 | /** \brief Keyboard task: Do keyboard routine jobs |
269 | * | |
ee3b9d2e | 270 | * Do routine keyboard jobs: |
7c9d5ace | 271 | * |
272 | * * scan matrix | |
273 | * * handle mouse movements | |
274 | * * run visualizer code | |
275 | * * handle midi commands | |
276 | * * light LEDs | |
277 | * | |
8e88d55b JH |
278 | * This is repeatedly called as fast as possible. |
279 | */ | |
b624f32f | 280 | void keyboard_task(void) { |
8e88d55b | 281 | static matrix_row_t matrix_prev[MATRIX_ROWS]; |
b624f32f | 282 | static uint8_t led_status = 0; |
283 | matrix_row_t matrix_row = 0; | |
284 | matrix_row_t matrix_change = 0; | |
39d3d923 S |
285 | #ifdef QMK_KEYS_PER_SCAN |
286 | uint8_t keys_processed = 0; | |
287 | #endif | |
8e88d55b | 288 | |
e01b2d51 X |
289 | #if defined(OLED_DRIVER_ENABLE) && !defined(OLED_DISABLE_TIMEOUT) |
290 | uint8_t ret = matrix_scan(); | |
291 | #else | |
a074364c | 292 | matrix_scan(); |
e01b2d51 | 293 | #endif |
3cf7f732 | 294 | |
25285a1c FS |
295 | if (is_keyboard_master()) { |
296 | for (uint8_t r = 0; r < MATRIX_ROWS; r++) { | |
b624f32f | 297 | matrix_row = matrix_get_row(r); |
25285a1c FS |
298 | matrix_change = matrix_row ^ matrix_prev[r]; |
299 | if (matrix_change) { | |
a074364c | 300 | #ifdef MATRIX_HAS_GHOST |
b624f32f | 301 | if (has_ghost_in_row(r, matrix_row)) { |
302 | continue; | |
303 | } | |
25285a1c FS |
304 | #endif |
305 | if (debug_matrix) matrix_print(); | |
85f4c3eb DJ |
306 | matrix_row_t col_mask = 1; |
307 | for (uint8_t c = 0; c < MATRIX_COLS; c++, col_mask <<= 1) { | |
308 | if (matrix_change & col_mask) { | |
25285a1c | 309 | action_exec((keyevent_t){ |
85f4c3eb | 310 | .key = (keypos_t){.row = r, .col = c}, .pressed = (matrix_row & col_mask), .time = (timer_read() | 1) /* time should not be 0 */ |
25285a1c FS |
311 | }); |
312 | // record a processed key | |
85f4c3eb | 313 | matrix_prev[r] ^= col_mask; |
39d3d923 S |
314 | #ifdef QMK_KEYS_PER_SCAN |
315 | // only jump out if we have processed "enough" keys. | |
316 | if (++keys_processed >= QMK_KEYS_PER_SCAN) | |
317 | #endif | |
b624f32f | 318 | // process a key per task call |
319 | goto MATRIX_LOOP_END; | |
25285a1c | 320 | } |
a074364c | 321 | } |
322 | } | |
323 | } | |
324 | } | |
8e88d55b | 325 | // call with pseudo tick event when no real key event. |
39d3d923 S |
326 | #ifdef QMK_KEYS_PER_SCAN |
327 | // we can get here with some keys processed now. | |
328 | if (!keys_processed) | |
329 | #endif | |
b624f32f | 330 | action_exec(TICK); |
8e88d55b JH |
331 | |
332 | MATRIX_LOOP_END: | |
333 | ||
cc5edb9e JC |
334 | #ifdef DEBUG_MATRIX_SCAN_RATE |
335 | matrix_scan_perf_task(); | |
336 | #endif | |
337 | ||
ba628a28 JC |
338 | #if defined(RGBLIGHT_ANIMATIONS) && defined(RGBLIGHT_ENABLE) |
339 | rgblight_task(); | |
340 | #endif | |
341 | ||
342 | #if defined(BACKLIGHT_ENABLE) | |
343 | # if defined(BACKLIGHT_PIN) || defined(BACKLIGHT_PINS) | |
344 | backlight_task(); | |
345 | # endif | |
346 | #endif | |
347 | ||
4099536c | 348 | #ifdef QWIIC_ENABLE |
349 | qwiic_task(); | |
350 | #endif | |
351 | ||
e01b2d51 X |
352 | #ifdef OLED_DRIVER_ENABLE |
353 | oled_task(); | |
b624f32f | 354 | # ifndef OLED_DISABLE_TIMEOUT |
e01b2d51 | 355 | // Wake up oled if user is using those fabulous keys! |
b624f32f | 356 | if (ret) oled_on(); |
357 | # endif | |
e01b2d51 X |
358 | #endif |
359 | ||
a074364c | 360 | #ifdef MOUSEKEY_ENABLE |
8e88d55b | 361 | // mousekey repeat & acceleration |
a074364c | 362 | mousekey_task(); |
363 | #endif | |
8e88d55b | 364 | |
a074364c | 365 | #ifdef PS2_MOUSE_ENABLE |
366 | ps2_mouse_task(); | |
367 | #endif | |
8e88d55b | 368 | |
a074364c | 369 | #ifdef SERIAL_MOUSE_ENABLE |
4b45deb6 | 370 | serial_mouse_task(); |
a074364c | 371 | #endif |
8e88d55b | 372 | |
4d116a04 | 373 | #ifdef ADB_MOUSE_ENABLE |
4b45deb6 FS |
374 | adb_mouse_task(); |
375 | #endif | |
376 | ||
377 | #ifdef SERIAL_LINK_ENABLE | |
b624f32f | 378 | serial_link_update(); |
4d116a04 | 379 | #endif |
8e88d55b | 380 | |
07d0d5cb | 381 | #ifdef VISUALIZER_ENABLE |
9eb8d052 | 382 | visualizer_update(default_layer_state, layer_state, visualizer_get_mods(), host_keyboard_leds()); |
07d0d5cb FS |
383 | #endif |
384 | ||
ee132284 S |
385 | #ifdef POINTING_DEVICE_ENABLE |
386 | pointing_device_task(); | |
387 | #endif | |
388 | ||
53ff8a31 | 389 | #ifdef MIDI_ENABLE |
390 | midi_task(); | |
391 | #endif | |
392 | ||
c1c5922a | 393 | #ifdef VELOCIKEY_ENABLE |
b624f32f | 394 | if (velocikey_enabled()) { |
395 | velocikey_decelerate(); | |
396 | } | |
c1c5922a CL |
397 | #endif |
398 | ||
8e88d55b | 399 | // update LED |
a074364c | 400 | if (led_status != host_keyboard_leds()) { |
401 | led_status = host_keyboard_leds(); | |
402 | keyboard_set_leds(led_status); | |
403 | } | |
404 | } | |
405 | ||
7c9d5ace | 406 | /** \brief keyboard set leds |
407 | * | |
408 | * FIXME: needs doc | |
409 | */ | |
b624f32f | 410 | void keyboard_set_leds(uint8_t leds) { |
411 | if (debug_keyboard) { | |
412 | debug("keyboard_set_led: "); | |
413 | debug_hex8(leds); | |
414 | debug("\n"); | |
415 | } | |
a074364c | 416 | led_set(leds); |
417 | } |