]> git.donarmstrong.com Git - qmk_firmware.git/blob - keyboards/converter/adb_usb/matrix.c
Debounce refactor / API (#3720)
[qmk_firmware.git] / keyboards / converter / adb_usb / matrix.c
1 /*
2 Copyright 2011 Jun Wako <wakojun@gmail.com>
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 Ported to QMK by Peter Roe <pete@13bit.me>
18 */
19
20 #include <stdint.h>
21 #include <stdbool.h>
22 #include <avr/io.h>
23 #include <util/delay.h>
24 #include "print.h"
25 #include "util.h"
26 #include "debug.h"
27 #include "adb.h"
28 #include "matrix.h"
29 #include "report.h"
30 #include "host.h"
31 #include "led.h"
32 #include "timer.h"
33
34 static bool is_iso_layout = false;
35
36 // matrix state buffer(1:on, 0:off)
37 static matrix_row_t matrix[MATRIX_ROWS];
38
39 static void register_key(uint8_t key);
40
41 __attribute__ ((weak))
42 void matrix_init_kb(void) {
43     matrix_init_user();
44 }
45
46 __attribute__ ((weak))
47 void matrix_scan_kb(void) {
48     matrix_scan_user();
49 }
50
51 __attribute__ ((weak))
52 void matrix_init_user(void) {
53 }
54
55 __attribute__ ((weak))
56 void matrix_scan_user(void) {
57 }
58
59 void matrix_init(void)
60 {
61     adb_host_init();
62
63     // wait for keyboard to boot up and receive command
64     _delay_ms(2000);
65
66     // initialize matrix state: all keys off
67     for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
68
69     // debug_enable = true;
70     // debug_matrix = true;
71     // debug_keyboard = true;
72     // debug_mouse = true;
73     // print("debug enabled.\n");
74
75     matrix_init_quantum();
76 }
77
78 #ifdef ADB_MOUSE_ENABLE
79
80 #ifdef MAX
81 #undef MAX
82 #endif
83 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
84
85 static report_mouse_t mouse_report = {};
86
87 void adb_mouse_task(void)
88 {
89     uint16_t codes;
90     int16_t x, y;
91     static int8_t mouseacc;
92
93     /* tick of last polling */
94     static uint16_t tick_ms;
95
96     // polling with 12ms interval
97     if (timer_elapsed(tick_ms) < 12) return;
98     tick_ms = timer_read();
99
100     codes = adb_host_mouse_recv();
101     // If nothing received reset mouse acceleration, and quit.
102     if (!codes) {
103         mouseacc = 1;
104         return;
105     };
106     // Bit sixteen is button.
107     if (~codes & (1 << 15))
108         mouse_report.buttons |= MOUSE_BTN1;
109     if (codes & (1 << 15))
110         mouse_report.buttons &= ~MOUSE_BTN1;
111     // lower seven bits are movement, as signed int_7.
112     // low byte is X-axis, high byte is Y.
113     y = (codes>>8 & 0x3F);
114     x = (codes>>0 & 0x3F);
115     // bit seven and fifteen is negative
116     // usb does not use int_8, but int_7 (measuring distance) with sign-bit.
117     if (codes & (1 << 6))
118           x = (x-0x40);
119     if (codes & (1 << 14))
120          y = (y-0x40);
121     // Accelerate mouse. (They weren't meant to be used on screens larger than 320x200).
122     x *= mouseacc;
123     y *= mouseacc;
124     // Cap our two bytes per axis to one byte.
125     // Easier with a MIN-function, but since -MAX(-a,-b) = MIN(a,b)...
126          // I.E. MIN(MAX(x,-127),127) = -MAX(-MAX(x, -127), -127) = MIN(-MIN(-x,127),127)
127     mouse_report.x = -MAX(-MAX(x, -127), -127);
128     mouse_report.y = -MAX(-MAX(y, -127), -127);
129     if (debug_mouse) {
130             print("adb_host_mouse_recv: "); print_bin16(codes); print("\n");
131             print("adb_mouse raw: [");
132             phex(mouseacc); print(" ");
133             phex(mouse_report.buttons); print("|");
134             print_decs(mouse_report.x); print(" ");
135             print_decs(mouse_report.y); print("]\n");
136     }
137     // Send result by usb.
138     host_mouse_send(&mouse_report);
139     // increase acceleration of mouse
140     mouseacc += ( mouseacc < ADB_MOUSE_MAXACC ? 1 : 0 );
141     return;
142 }
143 #endif
144
145 uint8_t matrix_scan(void)
146 {
147     /* extra_key is volatile and more convoluted than necessary because gcc refused
148     to generate valid code otherwise. Making extra_key uint8_t and constructing codes
149     here via codes = extra_key<<8 | 0xFF; would consistently fail to even LOAD
150     extra_key from memory, and leave garbage in the high byte of codes. I tried
151     dozens of code variations and it kept generating broken assembly output. So
152     beware if attempting to make extra_key code more logical and efficient. */
153     static volatile uint16_t extra_key = 0xFFFF;
154     uint16_t codes;
155     uint8_t key0, key1;
156
157     /* tick of last polling */
158     static uint16_t tick_ms;
159
160     codes = extra_key;
161     extra_key = 0xFFFF;
162
163     if ( codes == 0xFFFF )
164     {
165         // polling with 12ms interval
166         if (timer_elapsed(tick_ms) < 12) return 0;
167         tick_ms = timer_read();
168
169         codes = adb_host_kbd_recv();
170     }
171
172     key0 = codes>>8;
173     key1 = codes&0xFF;
174
175     if (debug_matrix && codes) {
176         print("adb_host_kbd_recv: "); phex16(codes); print("\n");
177     }
178
179     if (codes == 0) {                           // no keys
180         return 0;
181     } else if (codes == 0x7F7F) {   // power key press
182         register_key(0x7F);
183     } else if (codes == 0xFFFF) {   // power key release
184         register_key(0xFF);
185     } else if (key0 == 0xFF) {      // error
186         xprintf("adb_host_kbd_recv: ERROR(%d)\n", codes);
187         // something wrong or plug-in
188         matrix_init();
189         return key1;
190     } else {
191         /* Swap codes for ISO keyboard
192          * https://github.com/tmk/tmk_keyboard/issues/35
193          *
194          * ANSI
195          * ,-----------    ----------.
196          * | *a|  1|  2     =|Backspa|
197          * |-----------    ----------|
198          * |Tab  |  Q|     |  ]|   *c|
199          * |-----------    ----------|
200          * |CapsLo|  A|    '|Return  |
201          * |-----------    ----------|
202          * |Shift   |      Shift     |
203          * `-----------    ----------'
204          *
205          * ISO
206          * ,-----------    ----------.
207          * | *a|  1|  2     =|Backspa|
208          * |-----------    ----------|
209          * |Tab  |  Q|     |  ]|Retur|
210          * |-----------    -----`    |
211          * |CapsLo|  A|    '| *c|    |
212          * |-----------    ----------|
213          * |Shif| *b|      Shift     |
214          * `-----------    ----------'
215          *
216          *         ADB scan code   USB usage
217          *         -------------   ---------
218          * Key     ANSI    ISO     ANSI    ISO
219          * ---------------------------------------------
220          * *a      0x32    0x0A    0x35    0x35
221          * *b      ----    0x32    ----    0x64
222          * *c      0x2A    0x2A    0x31    0x31(or 0x32)
223          */
224         if (is_iso_layout) {
225             if ((key0 & 0x7F) == 0x32) {
226                 key0 = (key0 & 0x80) | 0x0A;
227             } else if ((key0 & 0x7F) == 0x0A) {
228                 key0 = (key0 & 0x80) | 0x32;
229             }
230         }
231         register_key(key0);
232         if (key1 != 0xFF)       // key1 is 0xFF when no second key.
233             extra_key = key1<<8 | 0xFF; // process in a separate call
234     }
235
236     matrix_scan_quantum();
237     return 1;
238 }
239
240 void matrix_print(void){
241
242 }
243
244 inline
245 matrix_row_t matrix_get_row(uint8_t row)
246 {
247     return matrix[row];
248 }
249
250 inline
251 static void register_key(uint8_t key)
252 {
253     uint8_t col, row;
254     col = key&0x07;
255     row = (key>>3)&0x0F;
256     if (key&0x80) {
257         matrix[row] &= ~(1<<col);
258     } else {
259         matrix[row] |=  (1<<col);
260     }
261 }