]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/matrix/matrix_scan.c
7e1e1042f3a97d0a2c09d96e30e06901310b0ac2
[kiibohd-controller.git] / Scan / matrix / matrix_scan.c
1 /* Copyright (C) 2011 by Jacob Alexander
2  * 
3  * Permission is hereby granted, free of charge, to any person obtaining a copy
4  * of this software and associated documentation files (the "Software"), to deal
5  * in the Software without restriction, including without limitation the rights
6  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7  * copies of the Software, and to permit persons to whom the Software is
8  * furnished to do so, subject to the following conditions:
9  * 
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  * 
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19  * THE SOFTWARE.
20  */
21
22 // ----- Includes -----
23
24 // AVR Includes
25 #include <avr/io.h>
26 #include <util/delay.h>
27
28 // Project Includes
29 #include <print.h>
30
31 // Local Includes
32 #include "matrix_scan.h"
33
34 // Matrix Configuration
35 #include <matrix.h>
36
37
38
39 // ----- Macros -----
40
41 // -- pinSetup Macros --
42 #define REG_SET(reg)    reg |=  (1 << ( matrix[row*(MAX_ROW_SIZE+1)+col] % 10 ) ) // Modulo 10 for the define offset for each pin set 12 or 32 -> shift of 2
43 #define REG_UNSET(reg)  reg &= ~(1 << ( matrix[row*(MAX_ROW_SIZE+1)+col] % 10 ) )
44
45 #define PIN_SET(pin,scan,direction) \
46                         switch ( direction ) { \
47                         case columnSet: PIN_SET_COL(pin,scan); \
48                         case rowSet:    PIN_SET_ROW(pin,scan); \
49                         } \
50                         break
51
52 // TODO Only scanCol_powrRow Tested (and powrRow)
53 #define PIN_SET_COL(pin,scan) \
54                         switch ( scan ) { \
55                         case scanCol: \
56                         case scanRow_powrCol: \
57                         case scanDual: \
58                                 REG_SET(port##pin); break; \
59                         case scanCol_powrRow: REG_UNSET(ddr##pin); REG_UNSET(DDR##pin); \
60                                               REG_SET(port##pin);  REG_SET(PORT##pin); break; \
61                         case powrRow: break; \
62                         case powrCol: REG_SET(ddr##pin);  REG_SET(DDR##pin); \
63                                       REG_SET(port##pin); REG_SET(PORT##pin); break; \
64                         } \
65                         break
66
67 // TODO Only scanCol_powrRow Tested (and powrRow)
68 #define PIN_SET_ROW(pin,scan) \
69                         switch ( scan ) { \
70                         case scanRow_powrCol: REG_UNSET(ddr##pin); REG_SET(port##pin); break; \
71                         case scanRow: \
72                         case scanDual: \
73                                 REG_SET(port##pin); break; \
74                         case scanCol_powrRow: REG_SET(ddr##pin);    REG_SET(DDR##pin); \
75                                               REG_UNSET(port##pin); REG_UNSET(PORT##pin); break; \
76                         case powrRow: REG_SET(ddr##pin);  REG_SET(DDR##pin); \
77                                       REG_SET(port##pin); REG_SET(PORT##pin); break; \
78                         case powrCol: break; \
79                         } \
80                         break
81
82 #define PIN_CASE(pinLetter) \
83                         case pin##pinLetter##0: \
84                         case pin##pinLetter##1: \
85                         case pin##pinLetter##2: \
86                         case pin##pinLetter##3: \
87                         case pin##pinLetter##4: \
88                         case pin##pinLetter##5: \
89                         case pin##pinLetter##6: \
90                         case pin##pinLetter##7
91
92 // -- Column Scan Macros --
93 #define PIN_TEST_COL(pin) \
94                         scanCode = matrix[row*(MAX_ROW_SIZE+1)+col]; \
95                         if ( scanCode && !( pin & ( 1 << ( matrix[0*(MAX_ROW_SIZE+1)+col] % 10 ) ) ) ) \
96                         { \
97                                 detectArray[scanCode]++; \
98                         } \
99                         break
100
101 // -- Row Scan Macros --
102 #define PIN_TEST_ROW(pin) \
103                         scanCode = matrix[row*(MAX_ROW_SIZE+1)+col]; \
104                         if ( scanCode && !( pin & ( 1 << ( matrix[row*(MAX_ROW_SIZE+1)+0] % 10 ) ) ) ) \
105                         { \
106                                 detectArray[scanCode]++; \
107                         } \
108                         break
109
110 // -- Scan Dual Macros --
111 #define PIN_DUALTEST_ROW(pin) \
112                         scanCode = matrix[row*(MAX_ROW_SIZE+1)+col]; \
113                         if ( scanCode \
114                           && !( pin & ( 1 << ( matrix[row*(MAX_ROW_SIZE+1)+0] % 10 ) ) ) \
115                           && detectArray[scanCode] & 0x01 ) \
116                         { \
117                                 detectArray[scanCode]++; \
118                         } \
119                         else \
120                         { \
121                                 if ( detectArray[scanCode] & 0x01 ) \
122                                         detectArray[scanCode]--; \
123                         } \
124                         break
125
126
127
128 // ----- Variables -----
129 uint8_t showDebug = 0;
130
131 // Debug Variables for GPIO setting
132 uint8_t portA = 0x00;
133 uint8_t portB = 0x00;
134 uint8_t portC = 0x00;
135 uint8_t portD = 0x00;
136 uint8_t portE = 0x00;
137 uint8_t portF = 0x00;
138
139 uint8_t ddrA = 0x00;
140 uint8_t ddrB = 0x00;
141 uint8_t ddrC = 0x00;
142 uint8_t ddrD = 0x00;
143 uint8_t ddrE = 0x00;
144 uint8_t ddrF = 0x00;
145
146
147 // ----- Functions -----
148 // Pin Setup Debug
149 inline void matrix_debugPins()
150 {
151         char tmpStr[6];
152         info_print("Initial Matrix Pin Setup");
153         info_print(" ddrA  ddrB  ddrC  ddrD  ddrE  ddrF");
154         print("      ");
155         hexToStr_op( ddrA, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
156         hexToStr_op( ddrB, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
157         hexToStr_op( ddrC, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
158         hexToStr_op( ddrD, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
159         hexToStr_op( ddrE, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
160         hexToStr_op( ddrF, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
161         print("\n");
162         info_print("portA portB portC portD portE portF");
163         print("      ");
164         hexToStr_op( portA, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
165         hexToStr_op( portB, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
166         hexToStr_op( portC, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
167         hexToStr_op( portD, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
168         hexToStr_op( portE, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
169         hexToStr_op( portF, tmpStr, 2 ); dPrintStrs( "  0x", tmpStr );
170         print("\n");
171
172         showDebug++;
173 }
174
175
176 // Column Setup
177 inline void matrix_columnSet( uint8_t *matrix, uint8_t scanType, uint16_t startIndex, uint16_t colsToIterate )
178 {
179         // Calculate the number of pins to iterate over
180         uint8_t maxColumns = startIndex + colsToIterate - 1;
181         if ( maxColumns > MAX_COL_SIZE )
182                 maxColumns = MAX_COL_SIZE;
183
184         uint16_t row, col;
185
186         // Columns
187         for ( col = startIndex, row = 0; col <= maxColumns; col++ )
188         {
189                 // We can't pass 2D arrays, so just point to the first element and calculate directly
190                 switch ( matrix[row*(MAX_ROW_SIZE+1)+col] )
191                 {
192 #if defined(__AVR_AT90USB1286__)
193                 PIN_CASE(A):
194                         PIN_SET(A, scanType, columnSet);
195 #endif
196                 PIN_CASE(B):
197                         PIN_SET(B, scanType, columnSet);
198                 PIN_CASE(C):
199                         PIN_SET(C, scanType, columnSet);
200                 PIN_CASE(D):
201                         PIN_SET(D, scanType, columnSet);
202                 PIN_CASE(E):
203                         PIN_SET(E, scanType, columnSet);
204                 PIN_CASE(F):
205                         PIN_SET(F, scanType, columnSet);
206
207                 default:
208                         continue;
209                 }
210         }
211 }
212
213 // Row Setup
214 inline void matrix_rowSet( uint8_t *matrix, uint8_t scanType, uint16_t startIndex, uint8_t rowsToIterate )
215 {
216         // Calculate the number of pins to iterate over
217         uint16_t maxRows = startIndex + rowsToIterate - 1;
218         if ( maxRows > MAX_ROW_SIZE )
219                 maxRows = MAX_ROW_SIZE;
220
221         uint16_t row, col;
222
223         // Rows
224         for ( col = 0, row = startIndex; row <= maxRows; row++ )
225         {
226                 // We can't pass 2D arrays, so just point to the first element and calculate directly
227                 switch ( matrix[row*(MAX_ROW_SIZE+1)+col] )
228                 {
229 #if defined(__AVR_AT90USB1286__)
230                 PIN_CASE(A):
231                         PIN_SET(A, scanType, rowSet);
232 #endif
233                 PIN_CASE(B):
234                         PIN_SET(B, scanType, rowSet);
235                 PIN_CASE(C):
236                         PIN_SET(C, scanType, rowSet);
237                 PIN_CASE(D):
238                         PIN_SET(D, scanType, rowSet);
239                 PIN_CASE(E):
240                         PIN_SET(E, scanType, rowSet);
241                 PIN_CASE(F):
242                         PIN_SET(F, scanType, rowSet);
243
244                 default:
245                         continue;
246                 }
247         }
248 }
249
250
251 // Goes through the defined matrix and matrix mode, and sets the initial state of all of the available pins
252 void matrix_pinSetup( uint8_t *matrix, uint8_t scanType )
253 {
254         // Loop through all the pin assignments, for the initial pin settings
255         matrix_rowSet   ( matrix, scanType, 1, MAX_ROW_SIZE );
256         matrix_columnSet( matrix, scanType, 1, MAX_COL_SIZE );
257
258         // Pin Status
259         if ( showDebug == 0 ) // Only show once
260         {
261                 matrix_debugPins();
262         }
263 }
264
265 // Scans the given matrix determined by the scanMode method
266 inline void matrix_scan( uint8_t *matrix, uint8_t *detectArray )
267 {
268         // Loop variables for all modes
269         uint16_t col = 1;
270         uint16_t row = 1;
271         uint16_t scanCode = 0;
272
273
274         // TODO Only scanCol_powrRow tested
275         // Column Scan and Column Scan, Power Row
276 #if scanMode == scanCol || scanMode == scanCol_powrRow
277         for ( ; row <= MAX_ROW_SIZE; row++ )
278         {
279                 // Power each row separately
280                 matrix_rowSet( matrix, powrRow, row, 1 );
281
282                 for ( col = 1; col <= MAX_COL_SIZE; col++ )
283                 {
284                         // Scan over the pins for each of the columns, and using the pin alias to determine which pin to set
285                         // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
286                         switch ( matrix[0*(MAX_ROW_SIZE+1)+col] / 10 )
287                         {
288 #if defined(__AVR_AT90USB1286__)
289                         case 0: // PINA
290                                 PIN_TEST_COL(PINA);
291 #endif
292                         case 1: // PINB
293                                 PIN_TEST_COL(PINB);
294                         case 2: // PINC
295                                 PIN_TEST_COL(PINC);
296                         case 3: // PIND
297                                 PIN_TEST_COL(PIND);
298                         case 4: // PINE
299                                 PIN_TEST_COL(PINE);
300                         case 5: // PINF
301                                 PIN_TEST_COL(PINF);
302                         }
303                 }
304
305                 // Unset the row power
306                 matrix_rowSet( matrix, scanMode, row, 1 );
307         }
308 #endif // scanMode
309
310
311         // Row Scan and Row Scan, Power Row
312 #if scanMode == scanRow || scanMode == scanRow_powrCol
313         for ( ; col <= MAX_COL_SIZE; col++ )
314         {
315                 // Power each column separately
316                 matrix_columnSet( matrix, powrCol, col, 1 );
317
318                 for ( row = 1; row <= MAX_ROW_SIZE; row++ )
319                 {
320                         // Scan over the pins for each of the rows, and using the pin alias to determine which pin to set
321                         // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
322                         switch ( matrix[row*(MAX_ROW_SIZE+1)+0] / 10 )
323                         {
324 #if defined(__AVR_AT90USB1286__)
325                         case 0: // PINA
326                                 PIN_TEST_ROW(PINA);
327 #endif
328                         case 1: // PINB
329                                 PIN_TEST_ROW(PINB);
330                         case 2: // PINC
331                                 PIN_TEST_ROW(PINC);
332                         case 3: // PIND
333                                 PIN_TEST_ROW(PIND);
334                         case 4: // PINE
335                                 PIN_TEST_ROW(PINE);
336                         case 5: // PINF
337                                 PIN_TEST_ROW(PINF);
338                         }
339                 }
340
341                 // Unset the column power
342                 matrix_columnSet( matrix, scanMode, col, 1 );
343         }
344 #endif // scanMode
345
346
347         // Dual Scan
348 #if scanMode == scanDual
349         // First do a scan of all of the columns, marking each one
350         matrix_pinSetup( matrix, scanCol_powrRow, 0, MAX_ROW_SIZE, MAX_COL_SIZE );
351         _delay_us( 1 );
352         for ( ; row < (MAX_COL_SIZE+1); row++ ) for ( ; col < (MAX_ROW_SIZE+1); col++ )
353         {
354                 // Scan over the pins for each of the columns, and using the pin alias to determine which pin to set
355                 // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
356                 switch ( matrix[0*(MAX_ROW_SIZE+1)+col] / 10 )
357                 {
358 #if defined(__AVR_AT90USB1286__)
359                 case 0: // PINA
360                         PIN_TEST_COL(PINA);
361 #endif
362                 case 1: // PINB
363                         PIN_TEST_COL(PINB);
364                 case 2: // PINC
365                         PIN_TEST_COL(PINC);
366                 case 3: // PIND
367                         PIN_TEST_COL(PIND);
368                 case 4: // PINE
369                         PIN_TEST_COL(PINE);
370                 case 5: // PINF
371                         PIN_TEST_COL(PINF);
372                 }
373         }
374
375         // Next, do a scan of all of the rows, clearing any "vague" keys (only detected on row, but not column, or vice-versa)
376         // And marking any keys that are detected on the row and column
377         matrix_pinSetup( matrix, scanRow_powrCol, 0, MAX_ROW_SIZE, MAX_COL_SIZE );
378         _delay_us( 1 );
379         col = 1;
380         row = 1;
381         for ( ; col < (MAX_ROW_SIZE+1); col++ ) for ( ; row < (MAX_COL_SIZE+1); row++ ) 
382         {
383                 // Scan over the pins for each of the rows, and using the pin alias to determine which pin to set
384                 // (e.g. / 10 is for the pin name (A,B,C,etc.) and % 10 is for the position of the pin (A1,A2,etc.))
385                 switch ( matrix[row*(MAX_ROW_SIZE+1)+0] / 10 )
386                 {
387 #if defined(__AVR_AT90USB1286__)
388                 case 0: // PINA
389                         PIN_DUALTEST_ROW(PINA);
390 #endif
391                 case 1: // PINB
392                         PIN_DUALTEST_ROW(PINB);
393                 case 2: // PINC
394                         PIN_DUALTEST_ROW(PINC);
395                 case 3: // PIND
396                         PIN_DUALTEST_ROW(PIND);
397                 case 4: // PINE
398                         PIN_DUALTEST_ROW(PINE);
399                 case 5: // PINF
400                         PIN_DUALTEST_ROW(PINF);
401                 }
402         }
403 #endif
404 }
405