]> git.donarmstrong.com Git - tmk_firmware.git/blob - keyboard/hbkb/matrix.c
Fix debouncing and add legacy keymap support
[tmk_firmware.git] / keyboard / hbkb / matrix.c
1 /*
2 Copyright 2012 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
18 #include <stdint.h>
19 #include <stdbool.h>
20 #include <avr/io.h>
21 #include <util/delay.h>
22 #include "print.h"
23 #include "debug.h"
24 #include "util.h"
25 #include "matrix.h"
26
27
28 /*
29  * Happy Buckling Keyboard(IBM Model M mod)
30  *
31  * Pin usage:
32  *   COL: PD0-7
33  *   ROW: PB0-7, PF4-7
34  */
35 #ifndef DEBOUNCE
36 #   define DEBOUNCE     10
37 #endif
38 static uint8_t debouncing = DEBOUNCE;
39
40 // matrix state buffer(1:on, 0:off)
41 static uint8_t *matrix;
42 static uint8_t *matrix_debouncing;
43 static uint8_t matrix0[MATRIX_ROWS];
44 static uint8_t matrix1[MATRIX_ROWS];
45
46 #ifdef MATRIX_HAS_GHOST
47 static bool matrix_has_ghost_in_row(uint8_t row);
48 #endif
49 static uint8_t read_col(void);
50 static void unselect_rows(void);
51 static void select_row(uint8_t row);
52
53
54 inline
55 uint8_t matrix_rows(void)
56 {
57     return MATRIX_ROWS;
58 }
59
60 inline
61 uint8_t matrix_cols(void)
62 {
63     return MATRIX_COLS;
64 }
65
66 void matrix_init(void)
67 {
68     print_enable = true;
69     debug_enable = true;
70     debug_matrix = true;
71     debug_keyboard = false;
72     debug_mouse = false;
73     print("debug enabled.\n");
74
75     // JTAG disable for PORT F. write JTD bit twice within four cycles.
76     MCUCR |= (1<<JTD);
77     MCUCR |= (1<<JTD);
78
79     // initialize rows
80     unselect_rows();
81
82     // initialize columns to input with pull-up(DDR:0, PORT:1)
83     DDRD = 0x00;
84     PORTD = 0xFF;
85
86     // initialize matrix state: all keys off
87     for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix0[i] = 0x00;
88     for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix1[i] = 0x00;
89     matrix = matrix0;
90     matrix_debouncing = matrix1;
91 }
92
93 uint8_t matrix_scan(void)
94 {
95     for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
96         select_row(i);
97         _delay_us(30);  // without this wait read unstable value.
98         if (matrix_debouncing[i] != read_col()) {
99             matrix_debouncing[i] = read_col();
100             if (debouncing) {
101                 debug("bounce!: "); debug_hex(debouncing); debug("\n");
102             }
103             debouncing = DEBOUNCE;
104         }
105         unselect_rows();
106     }
107
108     if (debouncing) {
109         if (--debouncing) {
110             _delay_ms(1);
111         } else {
112             uint8_t *tmp = matrix;
113             matrix = matrix_debouncing;
114             matrix_debouncing = tmp;
115         }
116     }
117
118     return 1;
119 }
120
121 bool matrix_is_modified(void)
122 {
123     if (debouncing) return false;
124     return true;
125 }
126
127 inline
128 bool matrix_is_on(uint8_t row, uint8_t col)
129 {
130     return (matrix[row] & (1<<col));
131 }
132
133 inline
134 #if (MATRIX_COLS <= 8)
135 uint8_t matrix_get_row(uint8_t row)
136 #else
137 uint16_t matrix_get_row(uint8_t row)
138 #endif
139 {
140     return matrix[row];
141 }
142
143 void matrix_print(void)
144 {
145     print("\nr/c 01234567\n");
146     for (uint8_t row = 0; row < matrix_rows(); row++) {
147         phex(row); print(": ");
148 #if (MATRIX_COLS <= 8)
149         pbin_reverse(matrix_get_row(row));
150 #else
151         pbin_reverse16(matrix_get_row(row));
152 #endif
153 #ifdef MATRIX_HAS_GHOST
154         if (matrix_has_ghost_in_row(row)) {
155             print(" <ghost");
156         }
157 #endif
158         print("\n");
159     }
160 }
161
162 #ifdef MATRIX_HAS_GHOST
163 inline
164 static bool matrix_has_ghost_in_row(uint8_t row)
165 {
166     // no ghost exists in case less than 2 keys on
167     if (((matrix[row] - 1) & matrix[row]) == 0)
168         return false;
169
170     // ghost exists in case same state as other row
171     for (uint8_t i=0; i < MATRIX_ROWS; i++) {
172         if (i != row && (matrix[i] & matrix[row]))
173             return true;
174     }
175     return false;
176 }
177 #endif
178
179 inline
180 static uint8_t read_col(void)
181 {
182     return ~PIND;
183 }
184
185 inline
186 static void unselect_rows(void)
187 {
188     // Hi-Z(DDR:0, PORT:0) to unselect
189     DDRB  &= ~0b11111111;
190     PORTB &= ~0b11111111;
191     DDRF  &= ~0b11110000;
192     PORTF &= ~0b11110000;
193 }
194
195 inline
196 static void select_row(uint8_t row)
197 {
198     // Output low(DDR:1, PORT:0) to select
199     switch (row) {
200         case 0:
201         case 1:
202         case 2:
203         case 3:
204         case 4:
205         case 5:
206         case 6:
207         case 7:
208             DDRB  |=  (1<<row);
209             PORTB &= ~(1<<row);
210             break;
211         case 8:
212             DDRF  |=  (1<<4);
213             PORTF &= ~(1<<4);
214             break;
215         case 9:
216         case 10:
217         case 11:
218             DDRF  |=  (1<<(row-4));
219             PORTF &= ~(1<<(row-4));
220             break;
221     }
222 }